380 lines
15 KiB
C
380 lines
15 KiB
C
/* 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));
|
|
}
|