diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2021-05-31 00:44:03 +0200 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2021-08-26 14:04:23 +0200 |
commit | b4effff8a50562636b00bf71e18252edfaed725f (patch) | |
tree | c370241ad171634ab48ad51c8a9626eb8c918db2 | |
parent | 99ff643e823ee878698822a7677c6054956a632c (diff) | |
download | tracker-b4effff8a50562636b00bf71e18252edfaed725f.tar.gz |
docs: Refactor common utils to separate file
We'll want to generate different document formats, the printing
of the hierarchy tree can be abstraced into a common helper.
-rw-r--r-- | docs/tools/meson.build | 1 | ||||
-rw-r--r-- | docs/tools/tracker-utils.c | 391 | ||||
-rw-r--r-- | docs/tools/tracker-utils.h | 41 | ||||
-rw-r--r-- | docs/tools/ttlresource2xml.c | 367 |
4 files changed, 435 insertions, 365 deletions
diff --git a/docs/tools/meson.build b/docs/tools/meson.build index 6e7ad958e..8eb2aeec7 100644 --- a/docs/tools/meson.build +++ b/docs/tools/meson.build @@ -4,6 +4,7 @@ doctool_gresources = gnome.compile_resources('tracker_doctool_gresources', 'dsc- doctool_files = [ 'tracker-ontology-model.c', + 'tracker-utils.c', 'ttl_xml.c', 'ttlresource2xml.c', 'ttl2xml.c', diff --git a/docs/tools/tracker-utils.c b/docs/tools/tracker-utils.c new file mode 100644 index 000000000..bf72a8de3 --- /dev/null +++ b/docs/tools/tracker-utils.c @@ -0,0 +1,391 @@ +/* + * Copyright (C) 2015, Carlos Garnacho + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * Authors: Carlos Garnacho <carlosg@gnome.org> + */ + +#include <glib-object.h> +#include <glib/gprintf.h> +#include <gio/gio.h> +#include <stdlib.h> + +#include "tracker-utils.h" + +static void +class_get_parent_hierarchy (TrackerOntologyModel *model, + const gchar *class_name, + GList **list) +{ + TrackerOntologyClass *klass; + GList *l, *elem; + + /* Ensure we only got the same class there once */ + elem = g_list_find_custom (*list, class_name, + (GCompareFunc) g_strcmp0); + if (elem) + *list = g_list_delete_link (*list, elem); + *list = g_list_prepend (*list, (gpointer) class_name); + + klass = tracker_ontology_model_get_class (model, class_name); + if (!klass) + return; + + + for (l = klass->superclasses; l; l = l->next) { + class_get_parent_hierarchy (model, l->data, list); + } +} + +static GList * +class_get_hierarchy (TrackerOntologyModel *model, + TrackerOntologyClass *klass) +{ + GList *hierarchy = NULL, *l; + + /* Order is: parents, this class, and children. Guaranteed + * to be in an order where all parents are before a child. + * We first prepend all children, and then find out the + * upwards hierarchy recursively. + */ + for (l = klass->subclasses; l; l = l->next) { + hierarchy = g_list_prepend (hierarchy, l->data); + } + + class_get_parent_hierarchy (model, klass->classname, &hierarchy); + + return hierarchy; +} + +typedef struct { + TrackerOntologyClass *class; + GList *hierarchy; + GHashTable *resolved_children; + GHashTable *resolved_parents; + GHashTable *placed; + GPtrArray *strings; +} HierarchyContext; + +static HierarchyString * +hierarchy_string_new (void) +{ + HierarchyString *str; + + str = g_new0 (HierarchyString, 1); + str->str = g_string_new (""); + + return str; +} + +static void +hierarchy_string_free (HierarchyString *str) +{ + g_string_free (str->str, TRUE); + g_free (str); +} + +static void +hierarchy_string_append (HierarchyString *str, + const gchar *substr) +{ + g_string_append (str->str, substr); + str->visible_len += g_utf8_strlen (substr, -1); +} + +static void +hierarchy_string_append_link (HierarchyString *str, + const gchar *substr, + const gchar *link, + gboolean bold) +{ + if (bold) + g_string_append_printf (str->str, "<emphasis><link linkend=\"%s\">%s</link></emphasis>", + link, substr); + else + g_string_append_printf (str->str, "<link linkend=\"%s\">%s</link>", link, substr); + + str->visible_len += g_utf8_strlen (substr, -1); +} + +static GList * +list_filter (GList *original, + GList *valid) +{ + GList *l, *filtered = NULL; + + for (l = original; l; l = l->next) { + if (!g_list_find_custom (valid, l->data, + (GCompareFunc) g_strcmp0)) + continue; + + filtered = g_list_prepend (filtered, l->data); + } + + return filtered; +} + +static HierarchyContext * +hierarchy_context_new (TrackerOntologyClass *klass, + TrackerOntologyModel *model) +{ + HierarchyContext *context; + GList *l; + + context = g_new0 (HierarchyContext, 1); + context->class = klass; + context->hierarchy = class_get_hierarchy (model, klass); + context->placed = g_hash_table_new (g_str_hash, g_str_equal); + context->resolved_parents = g_hash_table_new_full (g_str_hash, + g_str_equal, + NULL, + (GDestroyNotify) g_list_free); + context->resolved_children = g_hash_table_new_full (g_str_hash, + g_str_equal, + NULL, + (GDestroyNotify) g_list_free); + context->strings = g_ptr_array_new_with_free_func ((GDestroyNotify) hierarchy_string_free); + + for (l = context->hierarchy; l; l = l->next) { + TrackerOntologyClass *cl = tracker_ontology_model_get_class (model, l->data); + + g_hash_table_insert (context->resolved_parents, + cl->classname, + list_filter (cl->superclasses, + context->hierarchy)); + g_hash_table_insert (context->resolved_children, + cl->classname, + list_filter (cl->subclasses, + context->hierarchy)); + + g_ptr_array_add (context->strings, hierarchy_string_new ()); + } + + return context; +} + +static void +hierarchy_context_free (HierarchyContext *context) +{ + g_list_free (context->hierarchy); + g_ptr_array_unref (context->strings); + g_hash_table_unref (context->placed); + g_hash_table_unref (context->resolved_parents); + g_hash_table_unref (context->resolved_children); + g_free (context); +} + +static GList * +hierarchy_context_get_single_parented_children (HierarchyContext *context, + TrackerOntologyClass *klass, + TrackerOntologyModel *model) +{ + GList *filtered = NULL, *children, *l; + + children = g_hash_table_lookup (context->resolved_children, + klass->classname); + + for (l = children; l; l = l->next) { + GList *parents; + + parents = g_hash_table_lookup (context->resolved_parents, l->data); + + if (g_list_length (parents) == 1) + filtered = g_list_prepend (filtered, l->data); + } + + return filtered; +} + +static void +fill_padding (HierarchyString *str, + gint max_len, + gchar *substr) +{ + gint padding = max_len - str->visible_len; + + if (padding <= 0) + return; + + while (padding > 0) { + hierarchy_string_append (str, substr); + padding--; + } +} + +static gboolean +check_parents_placed (GList *parents, + GHashTable *ht) +{ + GList *l; + + for (l = parents; l; l = l->next) { + if (!g_hash_table_lookup (ht, l->data)) + return FALSE; + } + + return TRUE; +} + +static void +hierarchy_context_resolve_class (HierarchyContext *context, + TrackerOntologyClass *klass, + TrackerOntologyModel *model) +{ + GList *l = g_list_find_custom (context->hierarchy, klass->classname, + (GCompareFunc) g_strcmp0); + gint pos = g_list_position (context->hierarchy, l); + GList *children, *parents; + const gchar *shortname, *link; + HierarchyString *str; + gboolean is_child; + + if (pos < 0) + return; + + shortname = link = klass->shortname; + parents = g_hash_table_lookup (context->resolved_parents, + klass->classname); + + if (g_list_length (parents) > 1) { + gboolean first_pending = TRUE; + gint i, max_len = 0; + + /* This class has more than one parent in the current graph, + * those paint the lines on the right side. + */ + + /* Step 1: Find the longest string */ + first_pending = TRUE; + for (i = 0, l = context->hierarchy; i < pos && l; i++, l = l->next) { + is_child = g_list_find_custom (klass->superclasses, l->data, + (GCompareFunc) g_strcmp0) != NULL; + if (!is_child && first_pending) + continue; + + str = g_ptr_array_index (context->strings, i); + max_len = MAX (max_len, str->visible_len); + } + + /* Step 2: append the line art, we must fill in some padding if + * necessary. + */ + first_pending = TRUE; + for (i = 0, l = context->hierarchy; i < pos && l; i++, l = l->next) { + is_child = g_list_find_custom (klass->superclasses, l->data, + (GCompareFunc) g_strcmp0) != NULL; + + if (!is_child && first_pending) + continue; + + str = g_ptr_array_index (context->strings, i); + + fill_padding (str, max_len, is_child ? "─" : " "); + + if (first_pending) { + hierarchy_string_append (str, "──┐"); + first_pending = FALSE; + } else if (is_child) { + hierarchy_string_append (str, "──┤"); + } else { + hierarchy_string_append (str, " │"); + } + } + + /* Step 3: Finally, print the current class */ + str = g_ptr_array_index (context->strings, pos); + fill_padding (str, max_len - 1, " "); + + hierarchy_string_append (str, " └── "); + hierarchy_string_append_link (str, shortname, link, klass == context->class); + hierarchy_string_append (str, " "); + } else { + /* The current class has only 1 parent, lineart for those is + * displayed on the left side. + */ + + /* Step 1: Print the current class */ + str = g_ptr_array_index (context->strings, pos); + hierarchy_string_append_link (str, shortname, link, klass == context->class); + hierarchy_string_append (str, " "); + + /* Step 2: Modify all strings downwards, adding the lineart + * necessary for all children of this class. + */ + children = hierarchy_context_get_single_parented_children (context, klass, model); + l = l->next; + pos++; + + for (; l; l = l->next, pos++) { + guint len = g_list_length (children); + GList *cur; + + str = g_ptr_array_index (context->strings, pos); + cur = g_list_find_custom (children, l->data, + (GCompareFunc) g_strcmp0); + is_child = (cur != NULL); + + if (is_child) { + if (len > 1) + hierarchy_string_append (str, "├── "); + else if (len == 1) + hierarchy_string_append (str, "╰── "); + + children = g_list_delete_link (children, cur); + g_hash_table_insert (context->placed, + l->data, GINT_TO_POINTER (TRUE)); + } else { + if (len > 0) + hierarchy_string_append (str, "│ "); + else if (len == 0 && + !g_hash_table_lookup (context->placed, l->data)) { + GList *cl_parents; + + cl_parents = g_hash_table_lookup (context->resolved_parents, l->data); + + if (g_list_length (cl_parents) == 1 || + !check_parents_placed (cl_parents, context->placed)) { + hierarchy_string_append (str, " "); + } + } + } + } + } +} + +GPtrArray * +class_get_parent_hierarchy_strings (TrackerOntologyClass *klass, + TrackerOntologyModel *model) +{ + HierarchyContext *context; + GList *c; + GPtrArray *strings = NULL; + + context = hierarchy_context_new (klass, model); + + /* Proceed from parent to child classes, populating the + * context->strings array. + */ + for (c = context->hierarchy; c; c = c->next) { + TrackerOntologyClass *cl = tracker_ontology_model_get_class (model, c->data); + hierarchy_context_resolve_class (context, cl, model); + } + + strings = g_ptr_array_ref (context->strings); + hierarchy_context_free (context); + + return strings; +} diff --git a/docs/tools/tracker-utils.h b/docs/tools/tracker-utils.h new file mode 100644 index 000000000..9c7365ca7 --- /dev/null +++ b/docs/tools/tracker-utils.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017, Red Hat, Inc + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * Author: Carlos Garnacho <carlosg@gnome.org> + */ + +#ifndef TRACKER_UTILS_H +#define TRACKER_UTILS_H + +#include <glib.h> +#include "tracker-ontology-model.h" + +G_BEGIN_DECLS + +typedef struct { + GString *str; + gint visible_len; +} HierarchyString; + +GPtrArray * +class_get_parent_hierarchy_strings (TrackerOntologyClass *klass, + TrackerOntologyModel *model); + +G_END_DECLS + +#endif /* TRACKER_UTILS_H */ diff --git a/docs/tools/ttlresource2xml.c b/docs/tools/ttlresource2xml.c index 446a8f8b2..84fef3cca 100644 --- a/docs/tools/ttlresource2xml.c +++ b/docs/tools/ttlresource2xml.c @@ -23,52 +23,13 @@ #include <glib/gprintf.h> #include <gio/gio.h> #include <stdlib.h> + #include "tracker-ontology-model.h" +#include "tracker-utils.h" #include "ttl_xml.h" #include "ttlresource2xml.h" static void -class_get_parent_hierarchy (TrackerOntologyModel *model, - const gchar *class_name, - GList **list) -{ - TrackerOntologyClass *klass; - GList *l; - - /* Ensure we only got the same class there once */ - *list = g_list_remove (*list, (gpointer) class_name); - *list = g_list_prepend (*list, (gpointer) class_name); - - klass = tracker_ontology_model_get_class (model, class_name); - if (!klass) - return; - - for (l = klass->superclasses; l; l = l->next) { - class_get_parent_hierarchy (model, l->data, list); - } -} - -static GList * -class_get_hierarchy (TrackerOntologyModel *model, - TrackerOntologyClass *klass) -{ - GList *hierarchy = NULL, *l; - - /* Order is: parents, this class, and children. Guaranteed - * to be in an order where all parents are before a child. - * We first prepend all children, and then find out the - * upwards hierarchy recursively. - */ - for (l = klass->subclasses; l; l = l->next) { - hierarchy = g_list_prepend (hierarchy, l->data); - } - - class_get_parent_hierarchy (model, klass->classname, &hierarchy); - - return hierarchy; -} - -static void print_predefined_instances (FILE *f, TrackerOntologyClass *klass, TrackerOntologyModel *model) @@ -95,330 +56,6 @@ print_predefined_instances (FILE *f, g_fprintf (f, "</itemizedlist></para></refsect3>\n"); } -typedef struct { - GString *str; - gint visible_len; -} HierarchyString; - -typedef struct { - TrackerOntologyClass *class; - GList *hierarchy; - GHashTable *resolved_children; - GHashTable *resolved_parents; - GHashTable *placed; - GPtrArray *strings; -} HierarchyContext; - -static HierarchyString * -hierarchy_string_new (void) -{ - HierarchyString *str; - - str = g_new0 (HierarchyString, 1); - str->str = g_string_new (""); - - return str; -} - -static void -hierarchy_string_free (HierarchyString *str) -{ - g_string_free (str->str, TRUE); - g_free (str); -} - -static void -hierarchy_string_append (HierarchyString *str, - const gchar *substr) -{ - g_string_append (str->str, substr); - str->visible_len += g_utf8_strlen (substr, -1); -} - -static void -hierarchy_string_append_link (HierarchyString *str, - const gchar *substr, - const gchar *link, - gboolean bold) -{ - if (bold) - g_string_append_printf (str->str, "<emphasis><link linkend=\"%s\">%s</link></emphasis>", - link, substr); - else - g_string_append_printf (str->str, "<link linkend=\"%s\">%s</link>", link, substr); - - str->visible_len += g_utf8_strlen (substr, -1); -} - -static GList * -list_filter (GList *original, - GList *valid) -{ - GList *l, *filtered = NULL; - - for (l = original; l; l = l->next) { - if (!g_list_find_custom (valid, l->data, - (GCompareFunc) g_strcmp0)) - continue; - - filtered = g_list_prepend (filtered, l->data); - } - - return filtered; -} - -static HierarchyContext * -hierarchy_context_new (TrackerOntologyClass *klass, - TrackerOntologyModel *model) -{ - HierarchyContext *context; - GList *l; - - context = g_new0 (HierarchyContext, 1); - context->class = klass; - context->hierarchy = class_get_hierarchy (model, klass); - context->placed = g_hash_table_new (g_str_hash, g_str_equal); - context->resolved_parents = g_hash_table_new_full (g_str_hash, - g_str_equal, - NULL, - (GDestroyNotify) g_list_free); - context->resolved_children = g_hash_table_new_full (g_str_hash, - g_str_equal, - NULL, - (GDestroyNotify) g_list_free); - context->strings = g_ptr_array_new_with_free_func ((GDestroyNotify) hierarchy_string_free); - - for (l = context->hierarchy; l; l = l->next) { - TrackerOntologyClass *cl = tracker_ontology_model_get_class (model, l->data); - - g_hash_table_insert (context->resolved_parents, - cl->classname, - list_filter (cl->superclasses, - context->hierarchy)); - g_hash_table_insert (context->resolved_children, - cl->classname, - list_filter (cl->subclasses, - context->hierarchy)); - - g_ptr_array_add (context->strings, hierarchy_string_new ()); - } - - return context; -} - -static void -hierarchy_context_free (HierarchyContext *context) -{ - g_list_free (context->hierarchy); - g_ptr_array_unref (context->strings); - g_hash_table_unref (context->placed); - g_hash_table_unref (context->resolved_parents); - g_hash_table_unref (context->resolved_children); - g_free (context); -} - -static GList * -hierarchy_context_get_single_parented_children (HierarchyContext *context, - TrackerOntologyClass *klass, - TrackerOntologyModel *model) -{ - GList *filtered = NULL, *children, *l; - - children = g_hash_table_lookup (context->resolved_children, - klass->classname); - - for (l = children; l; l = l->next) { - GList *parents; - - parents = g_hash_table_lookup (context->resolved_parents, l->data); - - if (g_list_length (parents) == 1) - filtered = g_list_prepend (filtered, l->data); - } - - return filtered; -} - -static void -fill_padding (HierarchyString *str, - gint max_len, - gchar *substr) -{ - gint padding = max_len - str->visible_len; - - if (padding <= 0) - return; - - while (padding > 0) { - hierarchy_string_append (str, substr); - padding--; - } -} - -static gboolean -check_parents_placed (GList *parents, - GHashTable *ht) -{ - GList *l; - - for (l = parents; l; l = l->next) { - if (!g_hash_table_lookup (ht, l->data)) - return FALSE; - } - - return TRUE; -} - -static void -hierarchy_context_resolve_class (HierarchyContext *context, - TrackerOntologyClass *klass, - TrackerOntologyModel *model) -{ - GList *l = g_list_find_custom (context->hierarchy, klass->classname, - (GCompareFunc) g_strcmp0); - gint pos = g_list_position (context->hierarchy, l); - GList *children, *parents; - const gchar *shortname, *link; - HierarchyString *str; - gboolean is_child; - - if (pos < 0) - return; - - shortname = link = klass->shortname; - parents = g_hash_table_lookup (context->resolved_parents, - klass->classname); - - if (g_list_length (parents) > 1) { - gboolean first_pending = TRUE; - gint i, max_len = 0; - - /* This class has more than one parent in the current graph, - * those paint the lines on the right side. - */ - - /* Step 1: Find the longest string */ - first_pending = TRUE; - for (i = 0, l = context->hierarchy; i < pos && l; i++, l = l->next) { - is_child = g_list_find_custom (klass->superclasses, l->data, - (GCompareFunc) g_strcmp0) != NULL; - if (!is_child && first_pending) - continue; - - str = g_ptr_array_index (context->strings, i); - max_len = MAX (max_len, str->visible_len); - } - - /* Step 2: append the line art, we must fill in some padding if - * necessary. - */ - first_pending = TRUE; - for (i = 0, l = context->hierarchy; i < pos && l; i++, l = l->next) { - is_child = g_list_find_custom (klass->superclasses, l->data, - (GCompareFunc) g_strcmp0) != NULL; - - if (!is_child && first_pending) - continue; - - str = g_ptr_array_index (context->strings, i); - - fill_padding (str, max_len, is_child ? "─" : " "); - - if (first_pending) { - hierarchy_string_append (str, "──┐"); - first_pending = FALSE; - } else if (is_child) { - hierarchy_string_append (str, "──┤"); - } else { - hierarchy_string_append (str, " │"); - } - } - - /* Step 3: Finally, print the current class */ - str = g_ptr_array_index (context->strings, pos); - fill_padding (str, max_len - 1, " "); - - hierarchy_string_append (str, " └── "); - hierarchy_string_append_link (str, shortname, link, klass == context->class); - hierarchy_string_append (str, " "); - } else { - /* The current class has only 1 parent, lineart for those is - * displayed on the left side. - */ - - /* Step 1: Print the current class */ - str = g_ptr_array_index (context->strings, pos); - hierarchy_string_append_link (str, shortname, link, klass == context->class); - hierarchy_string_append (str, " "); - - /* Step 2: Modify all strings downwards, adding the lineart - * necessary for all children of this class. - */ - children = hierarchy_context_get_single_parented_children (context, klass, model); - l = l->next; - pos++; - - for (; l; l = l->next, pos++) { - guint len = g_list_length (children); - GList *cur; - - str = g_ptr_array_index (context->strings, pos); - cur = g_list_find_custom (children, l->data, - (GCompareFunc) g_strcmp0); - is_child = (cur != NULL); - - if (is_child) { - if (len > 1) - hierarchy_string_append (str, "├── "); - else if (len == 1) - hierarchy_string_append (str, "╰── "); - - children = g_list_delete_link (children, cur); - g_hash_table_insert (context->placed, - l->data, GINT_TO_POINTER (TRUE)); - } else { - if (len > 0) - hierarchy_string_append (str, "│ "); - else if (len == 0 && - !g_hash_table_lookup (context->placed, l->data)) { - GList *cl_parents; - - cl_parents = g_hash_table_lookup (context->resolved_parents, l->data); - - if (g_list_length (cl_parents) == 1 || - !check_parents_placed (cl_parents, context->placed)) { - hierarchy_string_append (str, " "); - } - } - } - } - } -} - -static GPtrArray * -class_get_parent_hierarchy_strings (TrackerOntologyClass *klass, - TrackerOntologyModel *model) -{ - HierarchyContext *context; - GList *c; - GPtrArray *strings = NULL; - - context = hierarchy_context_new (klass, model); - - /* Proceed from parent to child classes, populating the - * context->strings array. - */ - for (c = context->hierarchy; c; c = c->next) { - TrackerOntologyClass *cl = tracker_ontology_model_get_class (model, c->data); - hierarchy_context_resolve_class (context, cl, model); - } - - strings = g_ptr_array_ref (context->strings); - hierarchy_context_free (context); - - return strings; -} - static void print_class_hierarchy (FILE *f, TrackerOntologyClass *klass, |