1.12.42
[gnumeric.git] / src / file-autoft.c
blob60c1699a34d7159fcc9b9dc9d8c3f51791fa6a8f
1 /*
2 * file-autoft.c : Retrieve available autoformat templates/categories
4 * Copyright (C) Almer. S. Tigelaar.
5 * E-mail: almer1@dds.nl or almer-t@bigfoot.com
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <https://www.gnu.org/licenses/>.
21 #include <gnumeric-config.h>
22 #include <glib/gi18n-lib.h>
23 #include <gnumeric.h>
24 #include <file-autoft.h>
26 #include <gutils.h>
27 #include <workbook-control.h>
28 #include <format-template.h>
29 #include <gnumeric-conf.h>
31 #include <gsf/gsf-impl-utils.h>
32 #include <goffice/goffice.h>
34 #include <sys/types.h>
35 #include <string.h>
36 #include <unistd.h>
38 #define CXML2C(s) ((char const *)(s))
40 static gint
41 gnm_ft_category_compare_name_and_dir (gconstpointer a, gconstpointer b)
43 GnmFTCategory const *cat_a = a, *cat_b = b;
44 int res;
46 res = strcmp (cat_a->name, cat_b->name);
47 return res != 0 ? res : strcmp (cat_a->directory, cat_b->directory);
50 static void
51 gnm_ft_category_free (GnmFTCategory *category)
53 g_free (category->directory);
54 g_free (category->name);
55 g_free (category->description);
56 g_free (category);
59 static GSList *
60 gnm_ft_category_get_templates_list (GnmFTCategory *category,
61 GOCmdContext *cc)
63 GSList *templates = NULL;
64 GDir *dir;
65 char const *d_name;
67 if (category == NULL)
68 return NULL;
70 dir = g_dir_open (category->directory, 0, NULL);
71 if (dir == NULL)
72 return NULL;
74 while ((d_name = g_dir_read_name (dir)) != NULL) {
75 if (g_str_has_suffix (d_name, ".xml")) {
76 gchar *full_entry_name;
77 GnmFT *ft;
79 full_entry_name = g_build_filename (category->directory, d_name, NULL);
80 ft = gnm_ft_new_from_file (full_entry_name, cc);
81 if (ft == NULL) {
82 g_warning (_("Invalid template file: %s"), full_entry_name);
83 } else {
84 ft->category = category;
85 templates = g_slist_prepend (templates, ft);
87 g_free (full_entry_name);
91 g_dir_close (dir);
93 return g_slist_sort (templates, gnm_ft_compare_name);
96 /**
97 * gnm_ft_xml_read_category:
98 * Open an XML file and read a GnmFTCategory
100 static GnmFTCategory *
101 gnm_ft_xml_read_category (char const *dir_name)
103 gchar *file_name;
104 xmlDocPtr doc;
105 xmlNodePtr node;
106 GnmFTCategory *category = NULL;
108 g_return_val_if_fail (dir_name != NULL, NULL);
110 file_name = g_build_filename (dir_name, ".category", NULL);
111 doc = xmlParseFile (file_name);
112 if (doc != NULL && doc->xmlRootNode != NULL
113 && xmlSearchNsByHref (doc, doc->xmlRootNode, (xmlChar *)"http://www.gnome.org/gnumeric/format-template-category/v1") != NULL
114 && strcmp (CXML2C (doc->xmlRootNode->name), "FormatTemplateCategory") == 0
115 && (node = go_xml_get_child_by_name (doc->xmlRootNode, "Information")) != NULL) {
116 xmlChar *name = xmlGetProp (node, (xmlChar *)"name");
117 if (name != NULL) {
118 xmlChar *description = xmlGetProp (node, (xmlChar *)"description");
119 category = g_new (GnmFTCategory, 1);
120 category->directory = g_strdup (dir_name);
121 category->name = g_strdup ((gchar *)name);
122 category->description = g_strdup ((gchar *)description);
123 category->is_writable = (access (dir_name, W_OK) == 0);
124 if (description != NULL)
125 xmlFree (description);
126 xmlFree (name);
129 xmlFreeDoc (doc);
130 g_free (file_name);
132 return category;
135 static GList *
136 gnm_ft_category_list_get_from_dir_list (GSList *dir_list)
138 GList *categories = NULL;
139 GSList *dir_iterator;
141 g_return_val_if_fail (dir_list != NULL, NULL);
143 for (dir_iterator = dir_list; dir_iterator != NULL; dir_iterator = dir_iterator->next) {
144 gchar *dir_name = dir_iterator->data;
145 GDir *dir;
146 char const *d_name;
148 dir = g_dir_open (dir_name, 0, NULL);
149 if (dir == NULL)
150 continue;
152 while ((d_name = g_dir_read_name (dir)) != NULL) {
153 gchar *full_entry_name;
155 full_entry_name = g_build_filename (dir_name, d_name, NULL);
156 if (d_name[0] != '.' && g_file_test (full_entry_name, G_FILE_TEST_IS_DIR)) {
157 GnmFTCategory *category;
159 category = gnm_ft_xml_read_category (full_entry_name);
160 if (category != NULL) {
161 categories = g_list_prepend (categories, category);
164 g_free (full_entry_name);
167 g_dir_close (dir);
170 return categories;
173 static void
174 gnm_ft_category_list_free (GList *categories)
176 GList *l;
178 g_return_if_fail (categories);
180 for (l = categories; l != NULL; l = l->next) {
181 gnm_ft_category_free ((GnmFTCategory *) l->data);
183 g_list_free (categories);
186 static void
187 add_dir (GSList **pl, const char *dir, const char *base_dir)
189 char *dirc = NULL;
190 if (g_path_is_absolute (dir))
191 dirc = g_strdup (dir);
192 else
193 dirc = g_build_filename (base_dir, dir, NULL);
194 *pl = g_slist_prepend (*pl, dirc);
198 * gnm_ft_category_group_list_get:
200 * Returns: (element-type GnmFTCategoryGroup) (transfer full):
201 * the list of #GnmFTCategoryGroup which should be freed using
202 * gnm_ft_category_group_list_free().
204 GList *
205 gnm_ft_category_group_list_get (void)
207 GList *category_groups = NULL;
208 GSList *dir_list = NULL, *sl;
209 GList *categories, *l;
210 GnmFTCategoryGroup *current_group;
212 add_dir (&dir_list,
213 gnm_conf_get_autoformat_sys_dir (),
214 gnm_sys_data_dir ());
215 add_dir (&dir_list,
216 gnm_conf_get_autoformat_usr_dir (),
217 gnm_usr_dir (FALSE));
218 add_dir (&dir_list,
219 gnm_conf_get_autoformat_usr_dir (),
220 gnm_usr_dir (TRUE));
222 for (sl = gnm_conf_get_autoformat_extra_dirs (); sl; sl = sl->next) {
223 const char *dir = sl->data;
224 add_dir (&dir_list, dir, g_get_home_dir ());
226 dir_list = g_slist_reverse (dir_list);
227 categories = gnm_ft_category_list_get_from_dir_list (dir_list);
228 g_slist_free_full (dir_list, g_free);
230 categories = g_list_sort (categories, gnm_ft_category_compare_name_and_dir);
232 current_group = NULL;
233 for (l = categories; l != NULL; l = l->next) {
234 GnmFTCategory *category = l->data;
235 if (current_group == NULL || strcmp (current_group->name, category->name) != 0) {
236 if (current_group != NULL) {
237 category_groups = g_list_prepend (category_groups, current_group);
239 current_group = g_new (GnmFTCategoryGroup, 1);
240 current_group->categories = g_list_append (NULL, category);
241 current_group->name = g_strdup (category->name);
242 current_group->description = g_strdup (category->description);
243 } else {
244 current_group->categories = g_list_prepend (current_group->categories, category);
247 if (current_group != NULL)
248 category_groups = g_list_prepend (category_groups, current_group);
250 g_list_free (categories);
252 return category_groups;
257 * gnm_ft_category_group_list_free:
258 * @category_groups: (element-type GnmFTCategoryGroup): the list to free.
261 void
262 gnm_ft_category_group_list_free (GList *groups)
264 GList *ptr;
266 for (ptr = groups; ptr != NULL; ptr = ptr->next) {
267 GnmFTCategoryGroup *group = ptr->data;
268 g_free (group->name);
269 g_free (group->description);
270 gnm_ft_category_list_free (group->categories);
271 g_free (group);
273 g_list_free (groups);
277 * gnm_ft_category_group_get_templates_list:
278 * @category_group: #GnmFTCategoryGroup
279 * @context: #GOCmdContext
281 * Returns: (element-type GnmFT) (transfer container):
283 GSList *
284 gnm_ft_category_group_get_templates_list (GnmFTCategoryGroup *category_group,
285 GOCmdContext *cc)
287 GSList *templates = NULL;
288 GList *l;
290 for (l = category_group->categories; l != NULL; l = l->next)
291 templates = g_slist_concat (templates,
292 gnm_ft_category_get_templates_list (l->data, cc));
294 return g_slist_sort (templates, gnm_ft_compare_name);
298 gnm_ft_category_group_cmp (gconstpointer a, gconstpointer b)
300 GnmFTCategoryGroup const *group_a = a;
301 GnmFTCategoryGroup const *group_b = b;
302 return g_utf8_collate (_(group_a->name), _(group_b->name));