1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * file-autoft.c : Retrieve available autoformat templates/categories
5 * Copyright (C) Almer. S. Tigelaar.
6 * E-mail: almer1@dds.nl or almer-t@bigfoot.com
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <https://www.gnu.org/licenses/>.
22 #include <gnumeric-config.h>
23 #include <glib/gi18n-lib.h>
25 #include "file-autoft.h"
28 #include "workbook-control.h"
29 #include "format-template.h"
30 #include "gnumeric-conf.h"
32 #include <gsf/gsf-impl-utils.h>
33 #include <goffice/goffice.h>
35 #include <sys/types.h>
39 #define CXML2C(s) ((char const *)(s))
42 gnm_ft_category_compare_name_and_dir (gconstpointer a
, gconstpointer b
)
44 GnmFTCategory
const *cat_a
= a
, *cat_b
= b
;
47 res
= strcmp (cat_a
->name
, cat_b
->name
);
48 return res
!= 0 ? res
: strcmp (cat_a
->directory
, cat_b
->directory
);
52 gnm_ft_category_free (GnmFTCategory
*category
)
54 g_free (category
->directory
);
55 g_free (category
->name
);
56 g_free (category
->description
);
61 gnm_ft_category_get_templates_list (GnmFTCategory
*category
,
64 GSList
*templates
= NULL
;
71 dir
= g_dir_open (category
->directory
, 0, NULL
);
75 while ((d_name
= g_dir_read_name (dir
)) != NULL
) {
78 name_len
= strlen (d_name
);
79 if (name_len
> 4 && strcmp (d_name
+ name_len
- 4, ".xml") == 0) {
80 gchar
*full_entry_name
;
83 full_entry_name
= g_build_filename (category
->directory
, d_name
, NULL
);
84 ft
= gnm_ft_new_from_file (full_entry_name
, cc
);
86 g_warning (_("Invalid template file: %s"), full_entry_name
);
88 ft
->category
= category
;
89 templates
= g_slist_prepend (templates
, ft
);
91 g_free (full_entry_name
);
97 return g_slist_sort (templates
, gnm_ft_compare_name
);
101 * gnm_ft_xml_read_category :
102 * Open an XML file and read a GnmFTCategory
104 static GnmFTCategory
*
105 gnm_ft_xml_read_category (char const *dir_name
)
110 GnmFTCategory
*category
= NULL
;
112 g_return_val_if_fail (dir_name
!= NULL
, NULL
);
114 file_name
= g_build_filename (dir_name
, ".category", NULL
);
115 doc
= xmlParseFile (file_name
);
116 if (doc
!= NULL
&& doc
->xmlRootNode
!= NULL
117 && xmlSearchNsByHref (doc
, doc
->xmlRootNode
, (xmlChar
*)"http://www.gnome.org/gnumeric/format-template-category/v1") != NULL
118 && strcmp (CXML2C (doc
->xmlRootNode
->name
), "FormatTemplateCategory") == 0
119 && (node
= go_xml_get_child_by_name (doc
->xmlRootNode
, "Information")) != NULL
) {
120 xmlChar
*name
= xmlGetProp (node
, (xmlChar
*)"name");
122 xmlChar
*description
= xmlGetProp (node
, (xmlChar
*)"description");
123 category
= g_new (GnmFTCategory
, 1);
124 category
->directory
= g_strdup (dir_name
);
125 category
->name
= g_strdup ((gchar
*)name
);
126 category
->description
= g_strdup ((gchar
*)description
);
127 category
->is_writable
= (access (dir_name
, W_OK
) == 0);
128 if (description
!= NULL
)
129 xmlFree (description
);
140 gnm_ft_category_list_get_from_dir_list (GSList
*dir_list
)
142 GList
*categories
= NULL
;
143 GSList
*dir_iterator
;
145 g_return_val_if_fail (dir_list
!= NULL
, NULL
);
147 for (dir_iterator
= dir_list
; dir_iterator
!= NULL
; dir_iterator
= dir_iterator
->next
) {
148 gchar
*dir_name
= dir_iterator
->data
;
152 dir
= g_dir_open (dir_name
, 0, NULL
);
156 while ((d_name
= g_dir_read_name (dir
)) != NULL
) {
157 gchar
*full_entry_name
;
159 full_entry_name
= g_build_filename (dir_name
, d_name
, NULL
);
160 if (d_name
[0] != '.' && g_file_test (full_entry_name
, G_FILE_TEST_IS_DIR
)) {
161 GnmFTCategory
*category
;
163 category
= gnm_ft_xml_read_category (full_entry_name
);
164 if (category
!= NULL
) {
165 categories
= g_list_prepend (categories
, category
);
168 g_free (full_entry_name
);
178 gnm_ft_category_list_free (GList
*categories
)
182 g_return_if_fail (categories
);
184 for (l
= categories
; l
!= NULL
; l
= l
->next
) {
185 gnm_ft_category_free ((GnmFTCategory
*) l
->data
);
187 g_list_free (categories
);
191 add_dir (GSList
**pl
, const char *dir
, const char *base_dir
)
194 if (g_path_is_absolute (dir
))
195 dirc
= g_strdup (dir
);
197 dirc
= g_build_filename (base_dir
, dir
, NULL
);
198 *pl
= g_slist_prepend (*pl
, dirc
);
202 * gnm_ft_category_group_list_get:
204 * Returns: (element-type GnmFTCategoryGroup) (transfer full):
205 * the list of #GnmFTCategoryGroup which should be freed using
206 * gnm_ft_category_group_list_free().
209 gnm_ft_category_group_list_get (void)
211 GList
*category_groups
= NULL
;
212 GSList
*dir_list
= NULL
, *sl
;
213 GList
*categories
, *l
;
214 GnmFTCategoryGroup
*current_group
;
217 gnm_conf_get_autoformat_sys_dir (),
218 gnm_sys_data_dir ());
220 gnm_conf_get_autoformat_usr_dir (),
221 gnm_usr_dir (FALSE
));
223 gnm_conf_get_autoformat_usr_dir (),
226 for (sl
= gnm_conf_get_autoformat_extra_dirs (); sl
; sl
= sl
->next
) {
227 const char *dir
= sl
->data
;
228 add_dir (&dir_list
, dir
, g_get_home_dir ());
230 dir_list
= g_slist_reverse (dir_list
);
231 categories
= gnm_ft_category_list_get_from_dir_list (dir_list
);
232 g_slist_free_full (dir_list
, g_free
);
234 categories
= g_list_sort (categories
, gnm_ft_category_compare_name_and_dir
);
236 current_group
= NULL
;
237 for (l
= categories
; l
!= NULL
; l
= l
->next
) {
238 GnmFTCategory
*category
= l
->data
;
239 if (current_group
== NULL
|| strcmp (current_group
->name
, category
->name
) != 0) {
240 if (current_group
!= NULL
) {
241 category_groups
= g_list_prepend (category_groups
, current_group
);
243 current_group
= g_new (GnmFTCategoryGroup
, 1);
244 current_group
->categories
= g_list_append (NULL
, category
);
245 current_group
->name
= g_strdup (category
->name
);
246 current_group
->description
= g_strdup (category
->description
);
248 current_group
->categories
= g_list_prepend (current_group
->categories
, category
);
251 if (current_group
!= NULL
)
252 category_groups
= g_list_prepend (category_groups
, current_group
);
254 g_list_free (categories
);
256 return category_groups
;
261 * gnm_ft_category_group_list_free:
262 * @category_groups: (element-type GnmFTCategoryGroup): the list to free.
266 gnm_ft_category_group_list_free (GList
*groups
)
270 for (ptr
= groups
; ptr
!= NULL
; ptr
= ptr
->next
) {
271 GnmFTCategoryGroup
*group
= ptr
->data
;
272 g_free (group
->name
);
273 g_free (group
->description
);
274 gnm_ft_category_list_free (group
->categories
);
277 g_list_free (groups
);
281 * gnm_ft_category_group_get_templates_list:
282 * @category_group: #GnmFTCategoryGroup
283 * @context: #GOCmdContext
285 * Returns: (element-type GnmFT) (transfer container):
288 gnm_ft_category_group_get_templates_list (GnmFTCategoryGroup
*category_group
,
291 GSList
*templates
= NULL
;
294 for (l
= category_group
->categories
; l
!= NULL
; l
= l
->next
)
295 templates
= g_slist_concat (templates
,
296 gnm_ft_category_get_templates_list (l
->data
, cc
));
298 return g_slist_sort (templates
, gnm_ft_compare_name
);
302 gnm_ft_category_group_cmp (gconstpointer a
, gconstpointer b
)
304 GnmFTCategoryGroup
const *group_a
= a
;
305 GnmFTCategoryGroup
const *group_b
= b
;
306 return g_utf8_collate (_(group_a
->name
), _(group_b
->name
));