/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis * * pikafilteredcontainer.c * Copyright (C) 2008 Aurimas Juška * 2011 Michael Natterer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include "libpikabase/pikabase.h" #include "core-types.h" #include "pikafilteredcontainer.h" enum { PROP_0, PROP_SRC_CONTAINER, PROP_FILTER_FUNC, PROP_FILTER_DATA }; static void pika_filtered_container_constructed (GObject *object); static void pika_filtered_container_dispose (GObject *object); static void pika_filtered_container_finalize (GObject *object); static void pika_filtered_container_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void pika_filtered_container_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); static void pika_filtered_container_real_src_add (PikaFilteredContainer *filtered_container, PikaObject *object); static void pika_filtered_container_real_src_remove (PikaFilteredContainer *filtered_container, PikaObject *object); static void pika_filtered_container_real_src_freeze (PikaFilteredContainer *filtered_container); static void pika_filtered_container_real_src_thaw (PikaFilteredContainer *filtered_container); static gboolean pika_filtered_container_object_matches (PikaFilteredContainer *filtered_container, PikaObject *object); static void pika_filtered_container_src_add (PikaContainer *src_container, PikaObject *obj, PikaFilteredContainer *filtered_container); static void pika_filtered_container_src_remove (PikaContainer *src_container, PikaObject *obj, PikaFilteredContainer *filtered_container); static void pika_filtered_container_src_freeze (PikaContainer *src_container, PikaFilteredContainer *filtered_container); static void pika_filtered_container_src_thaw (PikaContainer *src_container, PikaFilteredContainer *filtered_container); G_DEFINE_TYPE (PikaFilteredContainer, pika_filtered_container, PIKA_TYPE_LIST) #define parent_class pika_filtered_container_parent_class static void pika_filtered_container_class_init (PikaFilteredContainerClass *klass) { GObjectClass *g_object_class = G_OBJECT_CLASS (klass); PikaFilteredContainerClass *filtered_class = PIKA_FILTERED_CONTAINER_CLASS (klass); g_object_class->constructed = pika_filtered_container_constructed; g_object_class->dispose = pika_filtered_container_dispose; g_object_class->finalize = pika_filtered_container_finalize; g_object_class->set_property = pika_filtered_container_set_property; g_object_class->get_property = pika_filtered_container_get_property; filtered_class->src_add = pika_filtered_container_real_src_add; filtered_class->src_remove = pika_filtered_container_real_src_remove; filtered_class->src_freeze = pika_filtered_container_real_src_freeze; filtered_class->src_thaw = pika_filtered_container_real_src_thaw; g_object_class_install_property (g_object_class, PROP_SRC_CONTAINER, g_param_spec_object ("src-container", NULL, NULL, PIKA_TYPE_CONTAINER, PIKA_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (g_object_class, PROP_FILTER_FUNC, g_param_spec_pointer ("filter-func", NULL, NULL, PIKA_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (g_object_class, PROP_FILTER_DATA, g_param_spec_pointer ("filter-data", NULL, NULL, PIKA_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } static void pika_filtered_container_init (PikaFilteredContainer *filtered_container) { } static void pika_filtered_container_constructed (GObject *object) { PikaFilteredContainer *filtered_container = PIKA_FILTERED_CONTAINER (object); G_OBJECT_CLASS (parent_class)->constructed (object); pika_assert (PIKA_IS_CONTAINER (filtered_container->src_container)); if (! pika_container_frozen (filtered_container->src_container)) { /* a freeze/thaw can't hurt on a newly created container because * we can't have any views yet. This way we get away without * having a virtual function for initializing the container. */ pika_filtered_container_src_freeze (filtered_container->src_container, filtered_container); pika_filtered_container_src_thaw (filtered_container->src_container, filtered_container); } } static void pika_filtered_container_dispose (GObject *object) { PikaFilteredContainer *filtered_container = PIKA_FILTERED_CONTAINER (object); if (filtered_container->src_container) { g_signal_handlers_disconnect_by_func (filtered_container->src_container, pika_filtered_container_src_add, filtered_container); g_signal_handlers_disconnect_by_func (filtered_container->src_container, pika_filtered_container_src_remove, filtered_container); g_signal_handlers_disconnect_by_func (filtered_container->src_container, pika_filtered_container_src_freeze, filtered_container); g_signal_handlers_disconnect_by_func (filtered_container->src_container, pika_filtered_container_src_thaw, filtered_container); } G_OBJECT_CLASS (parent_class)->dispose (object); } static void pika_filtered_container_finalize (GObject *object) { PikaFilteredContainer *filtered_container = PIKA_FILTERED_CONTAINER (object); g_clear_object (&filtered_container->src_container); G_OBJECT_CLASS (parent_class)->finalize (object); } static void pika_filtered_container_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { PikaFilteredContainer *filtered_container = PIKA_FILTERED_CONTAINER (object); switch (property_id) { case PROP_SRC_CONTAINER: filtered_container->src_container = g_value_dup_object (value); g_signal_connect (filtered_container->src_container, "add", G_CALLBACK (pika_filtered_container_src_add), filtered_container); g_signal_connect (filtered_container->src_container, "remove", G_CALLBACK (pika_filtered_container_src_remove), filtered_container); g_signal_connect (filtered_container->src_container, "freeze", G_CALLBACK (pika_filtered_container_src_freeze), filtered_container); g_signal_connect (filtered_container->src_container, "thaw", G_CALLBACK (pika_filtered_container_src_thaw), filtered_container); break; case PROP_FILTER_FUNC: filtered_container->filter_func = g_value_get_pointer (value); break; case PROP_FILTER_DATA: filtered_container->filter_data = g_value_get_pointer (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void pika_filtered_container_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { PikaFilteredContainer *filtered_container = PIKA_FILTERED_CONTAINER (object); switch (property_id) { case PROP_SRC_CONTAINER: g_value_set_object (value, filtered_container->src_container); break; case PROP_FILTER_FUNC: g_value_set_pointer (value, filtered_container->filter_func); break; case PROP_FILTER_DATA: g_value_set_pointer (value, filtered_container->filter_data); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void pika_filtered_container_real_src_add (PikaFilteredContainer *filtered_container, PikaObject *object) { if (pika_filtered_container_object_matches (filtered_container, object)) { pika_container_add (PIKA_CONTAINER (filtered_container), object); } } static void pika_filtered_container_real_src_remove (PikaFilteredContainer *filtered_container, PikaObject *object) { if (pika_filtered_container_object_matches (filtered_container, object)) { pika_container_remove (PIKA_CONTAINER (filtered_container), object); } } static void pika_filtered_container_real_src_freeze (PikaFilteredContainer *filtered_container) { pika_container_clear (PIKA_CONTAINER (filtered_container)); } static void pika_filtered_container_real_src_thaw (PikaFilteredContainer *filtered_container) { GList *list; for (list = PIKA_LIST (filtered_container->src_container)->queue->head; list; list = g_list_next (list)) { PikaObject *object = list->data; if (pika_filtered_container_object_matches (filtered_container, object)) { pika_container_add (PIKA_CONTAINER (filtered_container), object); } } } /** * pika_filtered_container_new: * @src_container: container to be filtered. * * Creates a new #PikaFilteredContainer object which creates filtered * data view of #PikaTagged objects. It filters @src_container for objects * containing all of the filtering tags. Synchronization with @src_container * data is performed automatically. * * Returns: a new #PikaFilteredContainer object. **/ PikaContainer * pika_filtered_container_new (PikaContainer *src_container, PikaObjectFilterFunc filter_func, gpointer filter_data) { GType children_type; GCompareFunc sort_func; g_return_val_if_fail (PIKA_IS_LIST (src_container), NULL); children_type = pika_container_get_children_type (src_container); sort_func = pika_list_get_sort_func (PIKA_LIST (src_container)); return g_object_new (PIKA_TYPE_FILTERED_CONTAINER, "sort-func", sort_func, "children-type", children_type, "policy", PIKA_CONTAINER_POLICY_WEAK, "unique-names", FALSE, "src-container", src_container, "filter-func", filter_func, "filter-data", filter_data, NULL); } static gboolean pika_filtered_container_object_matches (PikaFilteredContainer *filtered_container, PikaObject *object) { return (! filtered_container->filter_func || filtered_container->filter_func (object, filtered_container->filter_data)); } static void pika_filtered_container_src_add (PikaContainer *src_container, PikaObject *object, PikaFilteredContainer *filtered_container) { if (! pika_container_frozen (filtered_container->src_container)) { PIKA_FILTERED_CONTAINER_GET_CLASS (filtered_container)->src_add (filtered_container, object); } } static void pika_filtered_container_src_remove (PikaContainer *src_container, PikaObject *object, PikaFilteredContainer *filtered_container) { if (! pika_container_frozen (filtered_container->src_container)) { PIKA_FILTERED_CONTAINER_GET_CLASS (filtered_container)->src_remove (filtered_container, object); } } static void pika_filtered_container_src_freeze (PikaContainer *src_container, PikaFilteredContainer *filtered_container) { pika_container_freeze (PIKA_CONTAINER (filtered_container)); PIKA_FILTERED_CONTAINER_GET_CLASS (filtered_container)->src_freeze (filtered_container); } static void pika_filtered_container_src_thaw (PikaContainer *src_container, PikaFilteredContainer *filtered_container) { PIKA_FILTERED_CONTAINER_GET_CLASS (filtered_container)->src_thaw (filtered_container); pika_container_thaw (PIKA_CONTAINER (filtered_container)); }