diff options
Diffstat (limited to 'liblogdiag/ld-category.c')
-rw-r--r-- | liblogdiag/ld-category.c | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/liblogdiag/ld-category.c b/liblogdiag/ld-category.c new file mode 100644 index 0000000..d0b2245 --- /dev/null +++ b/liblogdiag/ld-category.c @@ -0,0 +1,419 @@ +/* + * ld-category.c + * + * This file is a part of logdiag. + * Copyright Přemysl Janouch 2010 - 2011. All rights reserved. + * + * See the file LICENSE for licensing information. + * + */ + +#include "liblogdiag.h" +#include "config.h" + + +/** + * SECTION:ld-category + * @short_description: A category of symbols + * @see_also: #LdSymbol, #LdLibrary + * + * #LdCategory represents a category of #LdSymbol objects. + */ + +/* + * LdCategoryPrivate: + * @name: the name of this category. + * @human_name: the localized human-readable name of this category. + * @symbols: (element-type LdSymbol *): symbols in this category. + * @subcategories: (element-type LdCategory *) children of this category. + */ +struct _LdCategoryPrivate +{ + gchar *name; + gchar *human_name; + GSList *symbols; + GSList *subcategories; +}; + +enum +{ + PROP_0, + PROP_NAME, + PROP_HUMAN_NAME +}; + +static void ld_category_get_property (GObject *object, guint property_id, + GValue *value, GParamSpec *pspec); +static void ld_category_set_property (GObject *object, guint property_id, + const GValue *value, GParamSpec *pspec); +static void ld_category_finalize (GObject *gobject); + +static void on_category_notify_name (LdCategory *category, + GParamSpec *pspec, gpointer user_data); + + +G_DEFINE_TYPE (LdCategory, ld_category, G_TYPE_OBJECT); + +static void +ld_category_class_init (LdCategoryClass *klass) +{ + GObjectClass *object_class; + GParamSpec *pspec; + + object_class = G_OBJECT_CLASS (klass); + object_class->get_property = ld_category_get_property; + object_class->set_property = ld_category_set_property; + object_class->finalize = ld_category_finalize; + +/** + * LdCategory:name: + * + * The name of this symbol category. + */ + pspec = g_param_spec_string ("name", "Name", + "The name of this symbol category.", + "", G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_NAME, pspec); + +/** + * LdCategory:human-name: + * + * The localized human name of this symbol category. + */ + pspec = g_param_spec_string ("human-name", "Human name", + "The localized human name of this symbol category.", + "", G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_HUMAN_NAME, pspec); + + g_type_class_add_private (klass, sizeof (LdCategoryPrivate)); +} + +static void +ld_category_init (LdCategory *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE + (self, LD_TYPE_CATEGORY, LdCategoryPrivate); +} + +static void +ld_category_get_property (GObject *object, guint property_id, + GValue *value, GParamSpec *pspec) +{ + LdCategory *self; + + self = LD_CATEGORY (object); + switch (property_id) + { + case PROP_NAME: + g_value_set_string (value, ld_category_get_name (self)); + break; + case PROP_HUMAN_NAME: + g_value_set_string (value, ld_category_get_human_name (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +ld_category_set_property (GObject *object, guint property_id, + const GValue *value, GParamSpec *pspec) +{ + LdCategory *self; + + self = LD_CATEGORY (object); + switch (property_id) + { + case PROP_NAME: + ld_category_set_name (self, g_value_get_string (value)); + break; + case PROP_HUMAN_NAME: + ld_category_set_human_name (self, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +uninstall_category_cb (LdCategory *category, LdCategory *self) +{ + g_signal_handlers_disconnect_by_func (category, + on_category_notify_name, self); + g_object_unref (category); +} + +static void +ld_category_finalize (GObject *gobject) +{ + LdCategory *self; + + self = LD_CATEGORY (gobject); + + if (self->priv->name) + g_free (self->priv->name); + if (self->priv->human_name) + g_free (self->priv->human_name); + + g_slist_foreach (self->priv->symbols, (GFunc) g_object_unref, NULL); + g_slist_free (self->priv->symbols); + + g_slist_foreach (self->priv->subcategories, + (GFunc) uninstall_category_cb, self); + g_slist_free (self->priv->subcategories); + + /* Chain up to the parent class. */ + G_OBJECT_CLASS (ld_category_parent_class)->finalize (gobject); +} + + +/** + * ld_category_new: + * @name: the name of the new category. + * @human_name: the localized human name of the new category. + * + * Create an instance. + */ +LdCategory * +ld_category_new (const gchar *name, const gchar *human_name) +{ + LdCategory *cat; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (human_name != NULL, NULL); + + cat = g_object_new (LD_TYPE_CATEGORY, NULL); + cat->priv->name = g_strdup (name); + cat->priv->human_name = g_strdup (human_name); + + return cat; +} + +/** + * ld_category_set_name: + * @self: an #LdCategory object. + * @name: the new name for this category. + */ +void +ld_category_set_name (LdCategory *self, const gchar *name) +{ + g_return_if_fail (LD_IS_CATEGORY (self)); + g_return_if_fail (name != NULL); + + if (self->priv->name) + g_free (self->priv->name); + self->priv->name = g_strdup (name); + + g_object_notify (G_OBJECT (self), "name"); +} + +/** + * ld_category_get_name: + * @self: an #LdCategory object. + * + * Return the name of this category. + */ +const gchar * +ld_category_get_name (LdCategory *self) +{ + g_return_val_if_fail (LD_IS_CATEGORY (self), NULL); + return self->priv->name; +} + +/** + * ld_category_set_human_name: + * @self: an #LdCategory object. + * @human_name: the new localized human name for this category. + */ +void +ld_category_set_human_name (LdCategory *self, const gchar *human_name) +{ + g_return_if_fail (LD_IS_CATEGORY (self)); + g_return_if_fail (human_name != NULL); + + if (self->priv->human_name) + g_free (self->priv->human_name); + self->priv->human_name = g_strdup (human_name); + + g_object_notify (G_OBJECT (self), "human-name"); +} + +/** + * ld_category_get_human_name: + * @self: an #LdCategory object. + * + * Return the localized human name of this category. + */ +const gchar * +ld_category_get_human_name (LdCategory *self) +{ + g_return_val_if_fail (LD_IS_CATEGORY (self), NULL); + return self->priv->human_name; +} + +/** + * ld_category_insert_symbol: + * @self: an #LdCategory object. + * @symbol: the symbol to be inserted. + * @pos: the position at which the symbol will be inserted. + * Negative values will append to the end of list. + * + * Insert a symbol into the category. + * + * Return value: %TRUE if successful (no name collisions). + */ +gboolean +ld_category_insert_symbol (LdCategory *self, LdSymbol *symbol, gint pos) +{ + const gchar *name; + const GSList *iter; + + g_return_val_if_fail (LD_IS_CATEGORY (self), FALSE); + g_return_val_if_fail (LD_IS_SYMBOL (symbol), FALSE); + + /* Check for name collisions. */ + name = ld_symbol_get_name (symbol); + for (iter = self->priv->symbols; iter; iter = iter->next) + { + if (!strcmp (name, ld_symbol_get_name (iter->data))) + { + g_warning ("attempted to insert multiple `%s' symbols into" + " category `%s'", name, ld_category_get_name (self)); + return FALSE; + } + } + + self->priv->symbols = g_slist_insert (self->priv->symbols, symbol, pos); + g_object_ref (symbol); + return TRUE; +} + +/** + * ld_category_remove_symbol: + * @self: an #LdCategory object. + * @symbol: the symbol to be removed. + * + * Removes a symbol from the category. + */ +void +ld_category_remove_symbol (LdCategory *self, LdSymbol *symbol) +{ + g_return_if_fail (LD_IS_CATEGORY (self)); + g_return_if_fail (LD_IS_SYMBOL (symbol)); + + if (g_slist_find (self->priv->symbols, symbol)) + { + self->priv->symbols = g_slist_remove (self->priv->symbols, symbol); + g_object_unref (symbol); + } +} + +/** + * ld_category_get_symbols: + * @self: an #LdCategory object. + * + * Return value: (element-type LdSymbol *): a list of symbols. Do not modify. + */ +const GSList * +ld_category_get_symbols (LdCategory *self) +{ + g_return_val_if_fail (LD_IS_CATEGORY (self), NULL); + return self->priv->symbols; +} + + +static void +on_category_notify_name (LdCategory *category, + GParamSpec *pspec, gpointer user_data) +{ + LdCategory *self; + + self = (LdCategory *) user_data; + g_warning ("name of a library subcategory has changed"); + + /* The easy way of handling it. */ + g_object_ref (category); + ld_category_remove_child (self, category); + ld_category_add_child (self, category); + g_object_unref (category); +} + +/** + * ld_category_add_child: + * @self: an #LdCategory object. + * @category: the category to be inserted. + * + * Insert a subcategory into the category. + * + * Return value: %TRUE if successful (no name collisions). + */ +gboolean +ld_category_add_child (LdCategory *self, LdCategory *category) +{ + const gchar *name; + GSList *iter; + + g_return_val_if_fail (LD_IS_CATEGORY (self), FALSE); + g_return_val_if_fail (LD_IS_CATEGORY (category), FALSE); + + name = ld_category_get_name (category); + for (iter = self->priv->subcategories; iter; iter = iter->next) + { + gint comp; + + comp = g_utf8_collate (name, ld_category_get_name (iter->data)); + if (!comp) + { + g_warning ("attempted to insert multiple `%s' subcategories into" + " category `%s'", name, ld_category_get_name (self)); + return FALSE; + } + if (comp < 0) + break; + } + + g_signal_connect (category, "notify::name", + G_CALLBACK (on_category_notify_name), self); + self->priv->subcategories = g_slist_insert_before + (self->priv->subcategories, iter, category); + g_object_ref (category); + return TRUE; +} + +/** + * ld_category_remove_child: + * @self: an #LdCategory object. + * @category: the category to be removed. + * + * Removes a subcategory from the category. + */ +void +ld_category_remove_child (LdCategory *self, LdCategory *category) +{ + g_return_if_fail (LD_IS_CATEGORY (self)); + g_return_if_fail (LD_IS_CATEGORY (category)); + + if (g_slist_find (self->priv->subcategories, category)) + { + g_signal_handlers_disconnect_by_func (category, + on_category_notify_name, self); + self->priv->subcategories + = g_slist_remove (self->priv->subcategories, category); + g_object_unref (category); + } +} + +/** + * ld_category_get_children: + * @self: an #LdCategory object. + * + * Return value: (element-type LdCategory *): + * a list of subcategories. Do not modify. + */ +const GSList * +ld_category_get_children (LdCategory *self) +{ + g_return_val_if_fail (LD_IS_CATEGORY (self), NULL); + return self->priv->subcategories; +} + |