summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjell Ahlstedt <kjellahlstedt@gmail.com>2022-08-29 16:13:32 +0200
committerKjell Ahlstedt <kjellahlstedt@gmail.com>2022-08-29 16:13:32 +0200
commitd0d08f9d826517fd2e02ae6300732faefe072f9d (patch)
tree11db1249dec5afec6c362a8d7a1a967b0139754e
parent818d7a22708ddc225b6363cd845e6cd72481028d (diff)
downloadglibmm-d0d08f9d826517fd2e02ae6300732faefe072f9d.tar.gz
Gio::ListStore: Add find()
* gio/src/liststore.[ccg|hg]: Add two ListStoreBase::find() and two ListStore::find(). * tests/giomm_listmodel/main.cc: Test ListStore::find().
-rw-r--r--gio/src/liststore.ccg34
-rw-r--r--gio/src/liststore.hg128
-rw-r--r--tests/giomm_listmodel/main.cc72
3 files changed, 234 insertions, 0 deletions
diff --git a/gio/src/liststore.ccg b/gio/src/liststore.ccg
index 3b2191d9..9c95e7ef 100644
--- a/gio/src/liststore.ccg
+++ b/gio/src/liststore.ccg
@@ -32,6 +32,19 @@ int ListStoreBase_CompareDataFunc(gconstpointer a, gconstpointer b, gpointer use
return (*slot)(item_a, item_b);
}
+
+// gboolean is int
+gboolean ListStoreBase_EqualFuncFull(gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ auto slot = static_cast<Gio::ListStoreBase::SlotEqual*>(user_data);
+
+ const Glib::RefPtr<const Glib::ObjectBase> item_a =
+ Glib::wrap(static_cast<Glib::Object::BaseObjectType*>(const_cast<gpointer>(a)), true);
+ const Glib::RefPtr<const Glib::ObjectBase> item_b =
+ Glib::wrap(static_cast<Glib::Object::BaseObjectType*>(const_cast<gpointer>(b)), true);
+
+ return (*slot)(item_a, item_b);
+}
}
} // anonymous namespace
@@ -49,4 +62,25 @@ void ListStoreBase::splice(guint position, guint n_removals,
g_list_store_splice(gobj(), position, n_removals, g_additions.get(), n_additions);
}
+std::pair<bool, unsigned int> ListStoreBase::find(const Glib::RefPtr<const Glib::ObjectBase>& item) const
+{
+ unsigned int position = std::numeric_limits<unsigned int>::max();
+ bool result = g_list_store_find(const_cast<GListStore*>(gobj()),
+ const_cast<GObject*>(item->gobj()), &position);
+ return {result, position};
+}
+
+std::pair<bool, unsigned int> ListStoreBase::find(
+ const Glib::RefPtr<const Glib::ObjectBase>& item, const SlotEqual& slot) const
+{
+ // Use the original slot (not a copy).
+ auto slot_ptr = const_cast<SlotEqual*>(&slot);
+
+ unsigned int position = std::numeric_limits<unsigned int>::max();
+ bool result = g_list_store_find_with_equal_func_full(
+ const_cast<GListStore*>(gobj()), const_cast<GObject*>(item->gobj()),
+ &ListStoreBase_EqualFuncFull, slot_ptr, &position);
+ return {result, position};
+}
+
} // namespace Gio
diff --git a/gio/src/liststore.hg b/gio/src/liststore.hg
index 3bef97ec..3a28b944 100644
--- a/gio/src/liststore.hg
+++ b/gio/src/liststore.hg
@@ -18,6 +18,8 @@
#include <giomm/listmodel.h>
#include <vector>
#include <type_traits>
+#include <limits>
+#include <utility>
_DEFS(giomm,gio)
_PINCLUDE(glibmm/private/object_p.h)
@@ -98,6 +100,51 @@ public:
const std::vector<Glib::RefPtr<Glib::ObjectBase>>& additions);
_IGNORE(g_list_store_splice)
+ /** Looks up the given @a item in the list store by looping over the items until
+ * the first occurrence of @a item.
+ *
+ * If you need to compare the two items with a custom comparison function, use
+ * find(const Glib::RefPtr<const Glib::ObjectBase>& item, const SlotEqual& slot) const instead.
+ *
+ * @newin{2,74}
+ *
+ * @param item An item.
+ * @return std::pair{item_found, position} Whether the %ListStoreBase contains @a item.
+ * If it was found, @a position will be set to the position where @a item
+ * occurred for the first time, else @a position = std::numeric_limits<unsigned int>::max().
+ */
+ std::pair<bool, unsigned int> find(const Glib::RefPtr<const Glib::ObjectBase>& item) const;
+ _IGNORE(g_list_store_find)
+
+ /** A slot that will be called to compare two items.
+ * The slot should return <tt>true</tt> if the items are equal,
+ * <tt>false</tt> if they are not equal.
+ * For instance,
+ * @code
+ * bool on_equal_item(const Glib::RefPtr<const Glib::ObjectBase>& item1, const Glib::RefPtr<const Glib::ObjectBase>& item2);
+ * @endcode
+ *
+ * @newin{2,74}
+ */
+ using SlotEqual = sigc::slot<bool(const Glib::RefPtr<const Glib::ObjectBase>&, const Glib::RefPtr<const Glib::ObjectBase>&)>;
+
+ /** Looks up the given @a item in the list store by looping over the items until
+ * the first occurrence of @a item.
+ *
+ * If you don't need to compare the two items with a custom comparison function,
+ * use find(const Glib::RefPtr<const Glib::ObjectBase>& item) const instead.
+ *
+ * @newin{2,74}
+ *
+ * @param item An item.
+ * @param slot A comparison function.
+ * @return std::pair{item_found, position} Whether the %ListStoreBase contains @a item.
+ * If it was found, @a position will be set to the position where @a item
+ * occurred for the first time, else @a position = std::numeric_limits<unsigned int>::max().
+ */
+ std::pair<bool, unsigned int> find(const Glib::RefPtr<const Glib::ObjectBase>& item, const SlotEqual& slot) const;
+ _IGNORE(g_list_store_find_with_equal_func, g_list_store_find_with_equal_func_full)
+
_WRAP_PROPERTY("item-type", GType, newin "2,50")
_WRAP_PROPERTY("n-items", unsigned int)
@@ -232,8 +279,53 @@ public:
void splice(guint position, guint n_removals,
const std::vector<Glib::RefPtr<T_item>>& additions);
+ /** Looks up the given @a item in the list store by looping over the items until
+ * the first occurrence of @a item.
+ *
+ * If you need to compare the two items with a custom comparison function, use
+ * find(const Glib::RefPtr<const T_item>& item, const SlotEqual& slot) const instead.
+ *
+ * @newin{2,74}
+ *
+ * @param item An item.
+ * @return std::pair{item_found, position} Whether the %ListStore contains @a item.
+ * If it was found, @a position will be set to the position where @a item
+ * occurred for the first time, else @a position = std::numeric_limits<unsigned int>::max().
+ */
+ std::pair<bool, unsigned int> find(const Glib::RefPtr<const T_item>& item) const;
+
+ /** A slot that will be called to compare two items.
+ * The slot should return <tt>true</tt> if the items are equal,
+ * <tt>false</tt> if they are not equal.
+ * For instance,
+ * @code
+ * bool on_equal_item(const Glib::RefPtr<const T_item>& item1, const Glib::RefPtr<const T_item>& item2);
+ * @endcode
+ *
+ * @newin{2,74}
+ */
+ using SlotEqual = sigc::slot<bool(const Glib::RefPtr<const T_item>&, const Glib::RefPtr<const T_item>&)>;
+
+ /** Looks up the given @a item in the list store by looping over the items until
+ * the first occurrence of @a item.
+ *
+ * If you don't need to compare the two items with a custom comparison function,
+ * use find(const Glib::RefPtr<const T_item>& item) const instead.
+ *
+ * @newin{2,74}
+ *
+ * @param item An item.
+ * @param slot A comparison function.
+ * @return std::pair{item_found, position} Whether the %ListStore contains @a item.
+ * If it was found, @a position will be set to the position where @a item
+ * occurred for the first time, else @a position = std::numeric_limits<unsigned int>::max().
+ */
+ std::pair<bool, unsigned int> find(const Glib::RefPtr<const T_item>& item, const SlotEqual& slot) const;
+
private:
static int compare_data_func(gconstpointer a, gconstpointer b, gpointer user_data);
+ // gboolean is int
+ static gboolean equal_func_full(gconstpointer a, gconstpointer b, gpointer user_data);
}; // end class ListStore
#ifndef DOXYGEN_SHOULD_SKIP_THIS
@@ -306,6 +398,27 @@ void ListStore<T_item>::splice(guint position, guint n_removals,
}
template <typename T_item>
+std::pair<bool, unsigned int> ListStore<T_item>::find(
+ const Glib::RefPtr<const T_item>& item) const
+{
+ return ListStoreBase::find(item);
+}
+
+template <typename T_item>
+std::pair<bool, unsigned int> ListStore<T_item>::find(
+ const Glib::RefPtr<const T_item>& item, const SlotEqual& slot) const
+{
+ // Use the original slot (not a copy).
+ auto slot_ptr = const_cast<SlotEqual*>(&slot);
+
+ unsigned int position = std::numeric_limits<unsigned int>::max();
+ bool result = g_list_store_find_with_equal_func_full(
+ const_cast<GListStore*>(gobj()), const_cast<typename T_item::BaseObjectType*>(item->gobj()),
+ &equal_func_full, slot_ptr, &position);
+ return {result, position};
+}
+
+template <typename T_item>
int ListStore<T_item>::compare_data_func(gconstpointer a, gconstpointer b, gpointer user_data)
{
auto slot = static_cast<SlotCompare*>(user_data);
@@ -320,6 +433,21 @@ int ListStore<T_item>::compare_data_func(gconstpointer a, gconstpointer b, gpoin
return (*slot)(item_a, item_b);
}
+template <typename T_item>
+gboolean ListStore<T_item>::equal_func_full(gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ auto slot = static_cast<SlotEqual*>(user_data);
+
+ // cast_dynamic is necessary if T_item is a user-derived class, such as
+ // class MyObject : public Glib::Object
+ const Glib::RefPtr<const T_item> item_a = std::dynamic_pointer_cast<T_item>(
+ Glib::wrap(static_cast<typename T_item::BaseObjectType*>(const_cast<gpointer>(a)), true));
+ const Glib::RefPtr<const T_item> item_b = std::dynamic_pointer_cast<T_item>(
+ Glib::wrap(static_cast<typename T_item::BaseObjectType*>(const_cast<gpointer>(b)), true));
+
+ return (*slot)(item_a, item_b);
+}
+
#endif // DOXYGEN_SHOULD_SKIP_THIS
} // namespace Gio
diff --git a/tests/giomm_listmodel/main.cc b/tests/giomm_listmodel/main.cc
index 1024a05e..f92fc5c7 100644
--- a/tests/giomm_listmodel/main.cc
+++ b/tests/giomm_listmodel/main.cc
@@ -19,6 +19,7 @@
#include <giomm.h>
#include <cstdlib>
#include <iostream>
+#include <tuple>
namespace
{
@@ -324,6 +325,76 @@ void test_store_sorted2()
}
} // end test_store_sorted2()
+void check_found_item_position(int icall, bool found_item, unsigned int position,
+ bool expected_found_item, unsigned int expected_position)
+{
+ if (found_item != expected_found_item || position != expected_position)
+ {
+ result = EXIT_FAILURE;
+ std::cerr << "test_store_find(), " << icall << ": found_item="
+ << found_item << ", position=" << position << std::endl;
+ }
+}
+
+bool casecmp_action_by_name(const Glib::RefPtr<const Gio::SimpleAction>& a,
+ const Glib::RefPtr<const Gio::SimpleAction>& b, const Glib::ustring& suffix)
+{
+ const auto a_name = a->get_name();
+ const auto b_name = b->get_name() + suffix;
+ if (suffix.empty())
+ return a_name.casefold() == b_name.casefold();
+ else
+ return a_name == b_name;
+}
+
+void test_store_find()
+{
+ const std::vector<Glib::ustring> item_strings{ "aaa", "bbb", "xxx", "ccc" };
+ std::vector<Glib::RefPtr<Gio::SimpleAction>> items;
+
+ for (auto& item_string : item_strings)
+ items.push_back(Gio::SimpleAction::create(item_string));
+ auto store = Gio::ListStore<Gio::SimpleAction>::create();
+
+ // Shouldn't crash on an empty list, or change the position pointer.
+ auto [found_item, position] = store->find(items[0]);
+ check_found_item_position(1, found_item, position,
+ false, std::numeric_limits<unsigned int>::max());
+
+ for (auto& item : items)
+ store->append(item);
+
+ // Check whether it could still find the the elements.
+ for (unsigned int i = 0; i < item_strings.size(); ++i)
+ {
+ std::tie(found_item, position) = store->find(items[i]);
+ check_found_item_position(1+i, found_item, position, true, i);
+ }
+
+ // Try to find element not part of the list.
+ auto other_item = Gio::SimpleAction::create("111");
+ std::tie(found_item, position) = store->find(other_item);
+ check_found_item_position(6, found_item, position,
+ false, std::numeric_limits<unsigned int>::max());
+
+ // Re-add item; find() should only return the first position.
+ store->append(items[0]);
+ std::tie(found_item, position) = store->find(items[0]);
+ check_found_item_position(7, found_item, position, true, 0);
+
+ // Try to find element which should only work with custom equality check.
+ other_item = Gio::SimpleAction::create("XXX");
+ std::tie(found_item, position) = store->find(other_item,
+ sigc::bind(sigc::ptr_fun(casecmp_action_by_name), ""));
+ check_found_item_position(8, found_item, position, true, 2);
+
+ other_item = Gio::SimpleAction::create("c");
+ std::tie(found_item, position) = store->find(other_item,
+ sigc::bind(sigc::ptr_fun(casecmp_action_by_name), "cc"));
+ check_found_item_position(8, found_item, position, true, 3);
+
+} // end test_store_find()
+
} // anonymous namespace
int main(int, char**)
@@ -334,6 +405,7 @@ int main(int, char**)
test_store_refcounts();
test_store_sorted1();
test_store_sorted2();
+ test_store_find();
return result;
}