PIKApp/app/core/pikafilteredcontainer.c

380 lines
15 KiB
C
Raw Normal View History

2023-09-26 00:35:21 +02:00
/* 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 <aurisj@svn.gnome.org>
* 2011 Michael Natterer <mitch@gimp.org>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gio/gio.h>
#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));
}