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>
24 #include <file-autoft.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>
38 #define CXML2C(s) ((char const *)(s))
41 gnm_ft_category_compare_name_and_dir (gconstpointer a
, gconstpointer b
)
43 GnmFTCategory
const *cat_a
= a
, *cat_b
= b
;
46 res
= strcmp (cat_a
->name
, cat_b
->name
);
47 return res
!= 0 ? res
: strcmp (cat_a
->directory
, cat_b
->directory
);
51 gnm_ft_category_free (GnmFTCategory
*category
)
53 g_free (category
->directory
);
54 g_free (category
->name
);
55 g_free (category
->description
);
60 gnm_ft_category_get_templates_list (GnmFTCategory
*category
,
63 GSList
*templates
= NULL
;
70 dir
= g_dir_open (category
->directory
, 0, 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
;
79 full_entry_name
= g_build_filename (category
->directory
, d_name
, NULL
);
80 ft
= gnm_ft_new_from_file (full_entry_name
, cc
);
82 g_warning (_("Invalid template file: %s"), full_entry_name
);
84 ft
->category
= category
;
85 templates
= g_slist_prepend (templates
, ft
);
87 g_free (full_entry_name
);
93 return g_slist_sort (templates
, gnm_ft_compare_name
);
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
)
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");
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
);
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
;
148 dir
= g_dir_open (dir_name
, 0, NULL
);
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
);
174 gnm_ft_category_list_free (GList
*categories
)
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
);
187 add_dir (GSList
**pl
, const char *dir
, const char *base_dir
)
190 if (g_path_is_absolute (dir
))
191 dirc
= g_strdup (dir
);
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().
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
;
213 gnm_conf_get_autoformat_sys_dir (),
214 gnm_sys_data_dir ());
216 gnm_conf_get_autoformat_usr_dir (),
217 gnm_usr_dir (FALSE
));
219 gnm_conf_get_autoformat_usr_dir (),
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
);
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.
262 gnm_ft_category_group_list_free (GList
*groups
)
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
);
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):
284 gnm_ft_category_group_get_templates_list (GnmFTCategoryGroup
*category_group
,
287 GSList
*templates
= NULL
;
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
));