/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Pix * * Copyright (C) 2009 Free Software Foundation, 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, see . */ #include #include #include #include #include "gth-catalog.h" #define CATALOG_FORMAT "1.0" struct _GthCatalogPrivate { GthCatalogType type; GFile *file; GList *file_list; GHashTable *file_hash; /* used to avoid duplicates */ char *name; GthDateTime *date_time; gboolean active; char *order; gboolean order_inverse; }; G_DEFINE_TYPE_WITH_CODE (GthCatalog, gth_catalog, G_TYPE_OBJECT, G_ADD_PRIVATE (GthCatalog)) static void gth_catalog_finalize (GObject *object) { GthCatalog *catalog = GTH_CATALOG (object); g_value_hash_unref (catalog->attributes); if (catalog->priv->file != NULL) g_object_unref (catalog->priv->file); g_free (catalog->priv->name); _g_object_list_unref (catalog->priv->file_list); g_hash_table_destroy (catalog->priv->file_hash); gth_datetime_free (catalog->priv->date_time); g_free (catalog->priv->order); G_OBJECT_CLASS (gth_catalog_parent_class)->finalize (object); } static DomElement * base_create_root (GthCatalog *catalog, DomDocument *doc) { return dom_document_create_element (doc, "catalog", "version", CATALOG_FORMAT, NULL); } static void base_read_from_doc (GthCatalog *catalog, DomElement *root) { GList *file_list; DomElement *child; file_list = NULL; for (child = root->first_child; child; child = child->next_sibling) { if (g_strcmp0 (child->tag_name, "files") == 0) { DomElement *file; for (file = child->first_child; file; file = file->next_sibling) { const char *uri; uri = dom_element_get_attribute (file, "uri"); if (uri != NULL) file_list = g_list_prepend (file_list, g_file_new_for_uri (uri)); } file_list = g_list_reverse (file_list); } if (g_strcmp0 (child->tag_name, "order") == 0) gth_catalog_set_order (catalog, dom_element_get_attribute (child, "type"), g_strcmp0 (dom_element_get_attribute (child, "inverse"), "1") == 0); if (g_strcmp0 (child->tag_name, "date") == 0) gth_datetime_from_exif_date (catalog->priv->date_time, dom_element_get_inner_text (child)); if (g_strcmp0 (child->tag_name, "name") == 0) gth_catalog_set_name (catalog, dom_element_get_inner_text (child)); } gth_catalog_set_file_list (catalog, file_list); gth_hook_invoke ("gth-catalog-read-from-doc", catalog, root); _g_object_list_unref (file_list); } static void read_catalog_data_from_xml (GthCatalog *catalog, const char *buffer, gsize count, GError **error) { DomDocument *doc; doc = dom_document_new (); if (dom_document_load (doc, buffer, count, error)) GTH_CATALOG_GET_CLASS (catalog)->read_from_doc (catalog, DOM_ELEMENT (doc)->first_child); g_object_unref (doc); } static void read_catalog_data_old_format (GthCatalog *catalog, const char *buffer, gsize count) { GInputStream *mem_stream; GDataInputStream *data_stream; gboolean is_search; int list_start; int n_line; char *line; mem_stream = g_memory_input_stream_new_from_data (buffer, count, NULL); data_stream = g_data_input_stream_new (mem_stream); is_search = (strncmp (buffer, "# Search", 8) == 0); if (is_search) list_start = 10; else list_start = 1; gth_catalog_set_file_list (catalog, NULL); n_line = 0; while ((line = g_data_input_stream_read_line (data_stream, NULL, NULL, NULL)) != NULL) { n_line++; if (is_search) { /* FIXME: read the search metadata here. */ } if (n_line > list_start) { char *uri; uri = g_strndup (line + 1, strlen (line) - 2); catalog->priv->file_list = g_list_prepend (catalog->priv->file_list, g_file_new_for_uri (uri)); g_free (uri); } g_free (line); } catalog->priv->file_list = g_list_reverse (catalog->priv->file_list); g_object_unref (data_stream); g_object_unref (mem_stream); } static void base_write_to_doc (GthCatalog *catalog, DomDocument *doc, DomElement *root) { if (catalog->priv->name != NULL) dom_element_append_child (root, dom_document_create_element_with_text (doc, catalog->priv->name, "name", NULL)); if (gth_datetime_valid_date (catalog->priv->date_time)) { char *s; s = gth_datetime_to_exif_date (catalog->priv->date_time); dom_element_append_child (root, dom_document_create_element_with_text (doc, s, "date", NULL)); g_free (s); } if (catalog->priv->order != NULL) dom_element_append_child (root, dom_document_create_element (doc, "order", "type", catalog->priv->order, "inverse", (catalog->priv->order_inverse ? "1" : "0"), NULL)); if (catalog->priv->file_list != NULL) { DomElement *node; GList *scan; node = dom_document_create_element (doc, "files", NULL); dom_element_append_child (root, node); for (scan = catalog->priv->file_list; scan; scan = scan->next) { GFile *file = scan->data; char *uri; uri = g_file_get_uri (file); dom_element_append_child (node, dom_document_create_element (doc, "file", "uri", uri, NULL)); g_free (uri); } } gth_hook_invoke ("gth-catalog-write-to-doc", catalog, doc, root); } static void gth_catalog_class_init (GthCatalogClass *class) { GObjectClass *object_class; object_class = (GObjectClass*) class; object_class->finalize = gth_catalog_finalize; class->create_root = base_create_root; class->read_from_doc = base_read_from_doc; class->write_to_doc = base_write_to_doc; } static void gth_catalog_init (GthCatalog *catalog) { catalog->attributes = g_value_hash_new (); catalog->priv = gth_catalog_get_instance_private (catalog); catalog->priv->type = GTH_CATALOG_TYPE_INVALID; catalog->priv->file = NULL; catalog->priv->file_list = NULL; catalog->priv->file_hash = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, NULL, NULL); catalog->priv->name = NULL; catalog->priv->date_time = gth_datetime_new (); catalog->priv->order = NULL; catalog->priv->order_inverse = FALSE; } GthCatalog * gth_catalog_new (void) { return (GthCatalog *) g_object_new (GTH_TYPE_CATALOG, NULL); } GthCatalog * gth_catalog_new_for_file (GFile *file) { char *uri; GthCatalog *catalog; if (file == NULL) return NULL; uri = g_file_get_uri (file); catalog = gth_hook_invoke_get ("gth-catalog-new-for-uri", uri); g_free (uri); return catalog; } GthCatalog * gth_catalog_new_from_data (const void *buffer, gsize count, GError **error) { char *text_buffer; GthCatalog *catalog = NULL; text_buffer = (char *) buffer; if ((text_buffer == NULL) || (*text_buffer == 0)) return NULL; if (strncmp (text_buffer, "priv->file != NULL) { g_object_unref (catalog->priv->file); catalog->priv->file = NULL; } if (file != NULL) catalog->priv->file = g_file_dup (file); catalog->priv->type = GTH_CATALOG_TYPE_CATALOG; } GFile * gth_catalog_get_file (GthCatalog *catalog) { return catalog->priv->file; } void gth_catalog_set_name (GthCatalog *catalog, const char *name) { g_free (catalog->priv->name); catalog->priv->name = NULL; if ((name != NULL) && (strcmp (name, "") != 0)) catalog->priv->name = g_strdup (name);; } const char * gth_catalog_get_name (GthCatalog *catalog) { return catalog->priv->name; } void gth_catalog_set_date (GthCatalog *catalog, GthDateTime *date_time) { if (g_date_valid (date_time->date)) g_date_set_dmy (catalog->priv->date_time->date, g_date_get_day (date_time->date), g_date_get_month (date_time->date), g_date_get_year (date_time->date)); else g_date_clear (catalog->priv->date_time->date, 1); gth_time_set_hms (catalog->priv->date_time->time, 0, 0, 0, 0); } GthDateTime * gth_catalog_get_date (GthCatalog *catalog) { return catalog->priv->date_time; } void gth_catalog_set_order (GthCatalog *catalog, const char *order, gboolean inverse) { g_free (catalog->priv->order); catalog->priv->order = NULL; if (order != NULL) catalog->priv->order = g_strdup (order); catalog->priv->order_inverse = inverse; } const char * gth_catalog_get_order (GthCatalog *catalog, gboolean *inverse) { *inverse = catalog->priv->order_inverse; return catalog->priv->order; } char * gth_catalog_to_data (GthCatalog *catalog, gsize *length) { DomDocument *doc; DomElement *root; char *data; doc = dom_document_new (); root = GTH_CATALOG_GET_CLASS (catalog)->create_root (catalog, doc); dom_element_append_child (DOM_ELEMENT (doc), root); GTH_CATALOG_GET_CLASS (catalog)->write_to_doc (catalog, doc, root); data = dom_document_dump (doc, length); g_object_unref (doc); return data; } void gth_catalog_set_file_list (GthCatalog *catalog, GList *file_list) { _g_object_list_unref (catalog->priv->file_list); catalog->priv->file_list = NULL; g_hash_table_remove_all (catalog->priv->file_hash); if (file_list != NULL) { GList *list; GList *scan; list = NULL; for (scan = file_list; scan; scan = scan->next) { GFile *file = scan->data; if (g_hash_table_lookup (catalog->priv->file_hash, file) != NULL) continue; file = g_file_dup (file); list = g_list_prepend (list, file); g_hash_table_insert (catalog->priv->file_hash, file, GINT_TO_POINTER (1)); } catalog->priv->file_list = g_list_reverse (list); } } GList * gth_catalog_get_file_list (GthCatalog *catalog) { return catalog->priv->file_list; } gboolean gth_catalog_insert_file (GthCatalog *catalog, GFile *file, int pos) { if (g_hash_table_lookup (catalog->priv->file_hash, file) != NULL) return FALSE; file = g_file_dup (file); catalog->priv->file_list = g_list_insert (catalog->priv->file_list, file, pos); g_hash_table_insert (catalog->priv->file_hash, file, GINT_TO_POINTER (1)); return TRUE; } int gth_catalog_remove_file (GthCatalog *catalog, GFile *file) { GList *scan; int i = 0; g_return_val_if_fail (catalog != NULL, -1); g_return_val_if_fail (file != NULL, -1); for (scan = catalog->priv->file_list; scan; scan = scan->next, i++) if (g_file_equal ((GFile *) scan->data, file)) break; if (scan == NULL) return -1; catalog->priv->file_list = g_list_remove_link (catalog->priv->file_list, scan); g_hash_table_remove (catalog->priv->file_hash, file); _g_object_list_unref (scan); return i; } static char * get_display_name (GFile *file, const char *name, GthDateTime *date_time) { GString *display_name; char *basename; display_name = g_string_new (""); basename = g_file_get_basename (file); if ((basename == NULL) || (strcmp (basename, "/") == 0)) { g_string_append (display_name, _("Catalogs")); } else { if ((name == NULL) && ! gth_datetime_valid_date (date_time)) { char *name; char *utf8_name; name = _g_path_remove_extension (basename); utf8_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL); g_string_append (display_name, utf8_name); g_free (utf8_name); g_free (name); } else { if (name != NULL) g_string_append (display_name, name); if (gth_datetime_valid_date (date_time)) { char *formatted; formatted = gth_datetime_strftime (date_time, "%x"); if ((name == NULL) || (strstr (name, formatted) == NULL)) { if (name != NULL) g_string_append (display_name, " ("); g_string_append (display_name, formatted); if (name != NULL) g_string_append (display_name, ")"); } g_free (formatted); } } } g_free (basename); return g_string_free (display_name, FALSE); } static char * get_edit_name (GFile *file, const char *name, GthDateTime *date_time) { GString *display_name; char *basename; display_name = g_string_new (""); basename = g_file_get_basename (file); if ((basename == NULL) || (strcmp (basename, "/") == 0)) { g_string_append (display_name, _("Catalogs")); } else { if (name == NULL) { char *name; char *utf8_name; name = _g_path_remove_extension (basename); utf8_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL); g_string_append (display_name, utf8_name); g_free (utf8_name); g_free (name); } else g_string_append (display_name, name); } g_free (basename); return g_string_free (display_name, FALSE); } static void update_standard_attributes (GFile *file, GFileInfo *info, const char *name, GthDateTime *date_time) { char *display_name; char *edit_name; if (gth_datetime_valid_date (date_time)) { char *sort_order_s; sort_order_s = gth_datetime_strftime (date_time, "%Y%m%d"); _g_file_info_set_secondary_sort_order (info, atoi (sort_order_s)); g_free (sort_order_s); } else g_file_info_remove_attribute (info, "gth::standard::secondary-sort-order"); display_name = get_display_name (file, name, date_time); if (display_name != NULL) { g_file_info_set_display_name (info, display_name); g_free (display_name); } edit_name = get_edit_name (file, name, date_time); if (edit_name != NULL) { g_file_info_set_edit_name (info, edit_name); g_free (edit_name); } } void gth_catalog_update_metadata (GthCatalog *catalog, GthFileData *file_data) { const char *sort_type; gboolean sort_inverse; /* sort::type,sort::inverse */ sort_type = gth_catalog_get_order (catalog, &sort_inverse); if (sort_type != NULL) { g_file_info_set_attribute_string (file_data->info, "sort::type", sort_type); g_file_info_set_attribute_boolean (file_data->info, "sort::inverse", sort_inverse); } else { g_file_info_remove_attribute (file_data->info, "sort::type"); g_file_info_remove_attribute (file_data->info, "sort::inverse"); } /* general::event-date */ if (gth_datetime_valid_date (catalog->priv->date_time)) { GObject *metadata; char *raw; char *formatted; char *sort_order_s; metadata = (GObject *) gth_metadata_new (); raw = gth_datetime_to_exif_date (catalog->priv->date_time); formatted = gth_datetime_strftime (catalog->priv->date_time, "%x"); g_object_set (metadata, "id", "general::event-date", "raw", raw, "formatted", formatted, NULL); g_file_info_set_attribute_object (file_data->info, "general::event-date", metadata); sort_order_s = gth_datetime_strftime (catalog->priv->date_time, "%Y%m%d"); _g_file_info_set_secondary_sort_order (file_data->info, atoi (sort_order_s)); g_free (formatted); g_free (raw); g_object_unref (metadata); } else { g_file_info_remove_attribute (file_data->info, "general::event-date"); g_file_info_remove_attribute (file_data->info, "gth::standard::secondary-sort-order"); } /* standard::display-name,standard::sort-order */ update_standard_attributes (file_data->file, file_data->info, catalog->priv->name, catalog->priv->date_time); gth_hook_invoke ("gth-catalog-write-metadata", catalog, file_data); } int gth_catalog_get_size (GthCatalog *catalog) { return g_hash_table_size (catalog->priv->file_hash); } /* utils */ GFile * gth_catalog_get_base (void) { return gth_user_dir_get_file_for_read (GTH_DIR_DATA, PIX_DIR, "catalogs", NULL); } GFile * gth_catalog_file_to_gio_file (GFile *file) { GFile *gio_file = NULL; char *uri; UriParts file_parts; if (! g_file_has_uri_scheme (file, "catalog")) return g_file_dup (file); uri = g_file_get_uri (file); if (! _g_uri_split (uri, &file_parts)) return NULL; if (file_parts.query != NULL) { char *new_uri; new_uri = g_uri_unescape_string (file_parts.query, NULL); gio_file = g_file_new_for_uri (new_uri); g_free (new_uri); } else { GFile *base; char *base_uri; char *new_uri; base = gth_catalog_get_base (); base_uri = g_file_get_uri (base); new_uri = _g_uri_append_path (base_uri, file_parts.path); gio_file = g_file_new_for_uri (new_uri); g_free (new_uri); g_free (base_uri); g_object_unref (base); } _g_uri_parts_clear (&file_parts); g_free (uri); return gio_file; } GFile * gth_catalog_file_from_gio_file (GFile *gio_file, GFile *catalog) { GFile *gio_base; GFile *file = NULL; char *path; gio_base = gth_catalog_get_base (); if (g_file_equal (gio_base, gio_file)) { g_object_unref (gio_base); return g_file_new_for_uri ("catalog:///"); } path = g_file_get_relative_path (gio_base, gio_file); if (path != NULL) { GFile *base; base = g_file_new_for_uri ("catalog:///"); file = _g_file_append_path (base, path); g_object_unref (base); } else if (catalog != NULL) { char *catalog_uri; char *file_uri; char *query; char *uri; catalog_uri = g_file_get_uri (catalog); file_uri = g_file_get_uri (gio_file); query = g_uri_escape_string (file_uri, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE); uri = g_strconcat (file_uri, "?", query, NULL); file = g_file_new_for_uri (uri); g_free (uri); g_free (query); g_free (file_uri); g_free (catalog_uri); } g_free (path); g_object_unref (gio_base); return file; } GFile * gth_catalog_file_from_relative_path (const char *name, const char *file_extension) { char *path; char *uri; GFile *file; path = g_strconcat (name, file_extension, NULL); uri = _g_uri_append_path ("catalog:///", path); file = g_file_new_for_uri (uri); g_free (uri); g_free (path); return file; } char * gth_catalog_get_relative_path (GFile *file) { GFile *base; char *path; base = gth_catalog_get_base (); path = g_file_get_relative_path (base, file); g_object_unref (base); return path; } GIcon * gth_catalog_get_icon (GFile *file) { char *uri; GIcon *icon; uri = g_file_get_uri (file); if (g_str_has_suffix (uri, ".catalog")) icon = g_themed_icon_new ("file-catalog-symbolic"); else icon = g_themed_icon_new ("file-library-symbolic"); g_free (uri); return icon; } static char * get_tag_value (const char *buffer, const char *tag_start, const char *tag_end) { char *value; char *begin_tag; value = NULL; begin_tag = strstr (buffer, tag_start); if (begin_tag != NULL) { char *end_tag; char *xml; DomDocument *doc; end_tag = strstr (begin_tag, tag_end); xml = g_strndup (begin_tag, (end_tag - begin_tag) + strlen (tag_end)); doc = dom_document_new (); if (dom_document_load (doc, xml, strlen (xml), NULL)) value = g_strdup (dom_element_get_inner_text (DOM_ELEMENT (doc)->first_child)); g_object_unref (doc); g_free (xml); } return value; } void gth_catalog_update_standard_attributes (GFile *file, GFileInfo *info) { char *display_name = NULL; char *edit_name = NULL; char *basename; basename = g_file_get_basename (file); if ((basename != NULL) && (strcmp (basename, "/") != 0)) { char *name; GthDateTime *date_time; name = NULL; date_time = gth_datetime_new (); { GFile *gio_file; GFileInputStream *istream; const int buffer_size = 256; char buffer[buffer_size]; gio_file = gth_catalog_file_to_gio_file (file); istream = g_file_read (gio_file, NULL, NULL); if (istream != NULL) { gsize bytes_read; if (g_input_stream_read_all (G_INPUT_STREAM (istream), buffer, buffer_size - 1, &bytes_read, NULL, NULL)) { char *exif_date; buffer[bytes_read] = '\0'; name = get_tag_value (buffer, "", ""); exif_date = get_tag_value (buffer, "", ""); if (exif_date != NULL) gth_datetime_from_exif_date (date_time, exif_date); g_free (exif_date); } g_object_unref (istream); } g_object_unref (gio_file); } update_standard_attributes (file, info, name, date_time); gth_datetime_free (date_time); g_free (name); } else { display_name = g_strdup (_("Catalogs")); edit_name = g_strdup (_("Catalogs")); } if (display_name != NULL) g_file_info_set_display_name (info, display_name); if (edit_name != NULL) g_file_info_set_edit_name (info, edit_name); g_free (edit_name); g_free (display_name); g_free (basename); } /* -- gth_catalog_load_from_file --*/ typedef struct { GFile *file; ReadyCallback ready_func; gpointer user_data; } LoadData; static void load__catalog_buffer_ready_cb (void **buffer, gsize count, GError *error, gpointer user_data) { LoadData *load_data = user_data; GthCatalog *catalog; if (error == NULL) { catalog = gth_catalog_new_from_data (*buffer, count, &error); if (catalog == NULL) catalog = gth_catalog_new_for_file (load_data->file); } else catalog = NULL; load_data->ready_func (G_OBJECT (catalog), error, load_data->user_data); g_object_unref (load_data->file); g_free (load_data); } void gth_catalog_load_from_file_async (GFile *file, GCancellable *cancellable, ReadyCallback ready_func, gpointer user_data) { LoadData *load_data; GFile *gio_file; load_data = g_new0 (LoadData, 1); load_data->file = g_object_ref (file); load_data->ready_func = ready_func; load_data->user_data = user_data; gio_file = gth_catalog_file_to_gio_file (file); _g_file_load_async (gio_file, G_PRIORITY_DEFAULT, cancellable, load__catalog_buffer_ready_cb, load_data); g_object_unref (gio_file); } GFile * gth_catalog_get_file_for_date (GthDateTime *date_time, const char *extension) { char *year; char *uri; char *display_name; GFile *catalog_file; year = gth_datetime_strftime (date_time, "%Y"); uri = g_strconcat ("catalog:///", year, "/", NULL); display_name = gth_datetime_strftime (date_time, "%Y-%m-%d"); catalog_file = _g_file_new_for_display_name (uri, display_name, extension); g_free (display_name); g_free (uri); g_free (year); return catalog_file; } GFile * gth_catalog_get_file_for_tag (const char *tag, const char *extension) { char *uri; GFile *catalog_file; uri = g_strconcat ("catalog:///", _("Tags"), "/", NULL); catalog_file = _g_file_new_for_display_name (uri, tag, extension); g_free (uri); return catalog_file; } GthCatalog * gth_catalog_load_from_file (GFile *file) { GthCatalog *catalog; GFile *gio_file; void *buffer; gsize buffer_size; gio_file = gth_catalog_file_to_gio_file (file); if (! _g_file_load_in_buffer (gio_file, &buffer, &buffer_size, NULL, NULL)) return NULL; catalog = gth_catalog_new_from_data (buffer, buffer_size, NULL); g_free (buffer); g_object_unref (gio_file); return catalog; } void gth_catalog_save (GthCatalog *catalog) { GFile *file; GFile *gio_file; GFile *gio_parent; char *data; gsize size; GError *error = NULL; file = gth_catalog_get_file (catalog); gio_file = gth_catalog_file_to_gio_file (file); gio_parent = g_file_get_parent (gio_file); if (gio_parent != NULL) g_file_make_directory_with_parents (gio_parent, NULL, NULL); data = gth_catalog_to_data (catalog, &size); if (! _g_file_write (gio_file, FALSE, G_FILE_CREATE_NONE, data, size, NULL, &error)) { g_warning ("%s", error->message); g_clear_error (&error); } else { GFile *parent_parent; GFile *parent; GList *list; parent = g_file_get_parent (file); parent_parent = g_file_get_parent (parent); if (parent_parent != NULL) { list = g_list_append (NULL, parent); gth_monitor_folder_changed (gth_main_get_default_monitor (), parent_parent, list, GTH_MONITOR_EVENT_CREATED); g_list_free (list); } list = g_list_append (NULL, file); gth_monitor_folder_changed (gth_main_get_default_monitor (), parent, list, GTH_MONITOR_EVENT_CREATED); g_list_free (list); g_object_unref (parent); } g_free (data); _g_object_unref (gio_parent); g_object_unref (gio_file); } /* -- gth_catalog_list_async -- */ typedef struct { GthCatalog *catalog; const char *attributes; CatalogReadyCallback list_ready_func; gpointer user_data; GList *current_file; GList *files; GCancellable *cancellable; } ListData; static void gth_catalog_list_done (ListData *list_data, GError *error) { if (list_data->list_ready_func != NULL) { list_data->files = g_list_reverse (list_data->files); list_data->list_ready_func (list_data->catalog, list_data->files, error, list_data->user_data); } _g_object_list_unref (list_data->files); _g_object_unref (list_data->cancellable); _g_object_unref (list_data->catalog); g_free (list_data); } static void catalog_file_info_ready_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { ListData *list_data = user_data; GFile *file; GFileInfo *info; file = (GFile*) source_object; info = g_file_query_info_finish (file, result, NULL); if (info != NULL) { list_data->files = g_list_prepend (list_data->files, gth_file_data_new (file, info)); g_object_unref (info); } list_data->current_file = list_data->current_file->next; if (list_data->current_file == NULL) { gth_catalog_list_done (list_data, NULL); return; } g_file_query_info_async ((GFile *) list_data->current_file->data, list_data->attributes, 0, G_PRIORITY_DEFAULT, list_data->cancellable, catalog_file_info_ready_cb, list_data); } static void list__catalog_buffer_ready_cb (void **buffer, gsize count, GError *error, gpointer user_data) { ListData *list_data = user_data; if ((error == NULL) && (*buffer != NULL)) { list_data->catalog = gth_catalog_new_from_data (*buffer, count, &error); if (list_data->catalog == NULL) { gth_catalog_list_done (list_data, error); return; } list_data->current_file = list_data->catalog->priv->file_list; if (list_data->current_file == NULL) { gth_catalog_list_done (list_data, NULL); return; } g_file_query_info_async ((GFile *) list_data->current_file->data, list_data->attributes, 0, G_PRIORITY_DEFAULT, list_data->cancellable, catalog_file_info_ready_cb, list_data); } else gth_catalog_list_done (list_data, error); } void gth_catalog_list_async (GFile *file, const char *attributes, GCancellable *cancellable, CatalogReadyCallback ready_func, gpointer user_data) { ListData *list_data; list_data = g_new0 (ListData, 1); list_data->attributes = attributes; list_data->list_ready_func = ready_func; list_data->user_data = user_data; list_data->cancellable = _g_object_ref (cancellable); _g_file_load_async (file, G_PRIORITY_DEFAULT, list_data->cancellable, list__catalog_buffer_ready_cb, list_data); }