/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Pix * * Copyright (C) 2010 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 #include #include #include #include #include #include #include "gth-burn-task.h" struct _GthBurnTaskPrivate { GthBrowser *browser; GFile *location; GList *selected_files; GtkWidget *dialog; GtkBuilder *builder; GthTest *test; GthFileSource *file_source; char *base_directory; char *current_directory; GHashTable *content; GHashTable *parents; BraseroSessionCfg *session; BraseroTrackDataCfg *track; }; G_DEFINE_TYPE_WITH_CODE (GthBurnTask, gth_burn_task, GTH_TYPE_TASK, G_ADD_PRIVATE (GthBurnTask)) static void free_file_list_from_content (gpointer key, gpointer value, gpointer user_data) { _g_object_list_unref (value); } static void gth_burn_task_finalize (GObject *object) { GthBurnTask *task; task = GTH_BURN_TASK (object); gtk_widget_destroy (task->priv->dialog); g_hash_table_foreach (task->priv->content, free_file_list_from_content, NULL); g_hash_table_unref (task->priv->content); g_hash_table_unref (task->priv->parents); g_free (task->priv->current_directory); _g_object_unref (task->priv->file_source); _g_object_unref (task->priv->test); _g_object_unref (task->priv->builder); _g_object_list_unref (task->priv->selected_files); g_free (task->priv->base_directory); g_object_unref (task->priv->location); g_object_unref (task->priv->browser); G_OBJECT_CLASS (gth_burn_task_parent_class)->finalize (object); } static void add_file_to_track (GthBurnTask *task, const char *parent_uri, const char *relative_subfolder, GFile *file) { char *relative_parent; GtkTreePath *tree_path; char *uri; relative_parent = g_build_path ("/", parent_uri + strlen (task->priv->base_directory), relative_subfolder, NULL); if (relative_parent != NULL) { char **subfolders; int i; char *subfolder; /* add all the subfolders to the track data */ subfolder = NULL; subfolders = g_strsplit (relative_parent, "/", -1); for (i = 0; subfolders[i] != NULL; i++) { char *subfolder_parent; subfolder_parent = subfolder; if (subfolder_parent != NULL) subfolder = g_strconcat (subfolder_parent, "/", subfolders[i], NULL); else subfolder = g_strdup (subfolders[i]); if ((strcmp (subfolder, "") != 0) && g_hash_table_lookup (task->priv->parents, subfolder) == NULL) { GtkTreePath *subfolder_parent_tpath; GtkTreePath *subfolder_tpath; char *basename; if (subfolder_parent != NULL) subfolder_parent_tpath = g_hash_table_lookup (task->priv->parents, subfolder_parent); else subfolder_parent_tpath = NULL; basename = _g_uri_get_basename (subfolder); subfolder_tpath = brasero_track_data_cfg_add_empty_directory (task->priv->track, basename, subfolder_parent_tpath); g_hash_table_insert (task->priv->parents, g_strdup (subfolder), subfolder_tpath); g_free (basename); } g_free (subfolder_parent); } g_free (subfolder); g_strfreev (subfolders); } tree_path = NULL; if (relative_parent != NULL) tree_path = g_hash_table_lookup (task->priv->parents, relative_parent); uri = g_file_get_uri (file); brasero_track_data_cfg_add (task->priv->track, uri, tree_path); g_free (uri); g_free (relative_parent); } static void add_content_list (gpointer key, gpointer value, gpointer user_data) { GthBurnTask *task = user_data; char *parent_uri = key; GList *files = value; GList *scan; for (scan = files; scan; scan = scan->next) add_file_to_track (task, parent_uri, NULL, (GFile *) scan->data); for (scan = files; scan; scan = scan->next) { GFile *file = scan->data; GFile *file_parent; GList *file_sidecars = NULL; GList *scan_sidecars; file_parent = g_file_get_parent (file); gth_hook_invoke ("add-sidecars", file, &file_sidecars); for (scan_sidecars = file_sidecars; scan_sidecars; scan_sidecars = scan_sidecars->next) { GFile *sidecar = scan_sidecars->data; char *relative_path; char *subfolder_path; if (! g_file_query_exists (sidecar, NULL)) continue; relative_path = g_file_get_relative_path (file_parent, sidecar); subfolder_path = _g_uri_get_parent (relative_path); if (g_strcmp0 (subfolder_path, "") == 0) { g_free (subfolder_path); subfolder_path = NULL; } add_file_to_track (task, parent_uri, subfolder_path, sidecar); } _g_object_list_unref (file_sidecars); g_object_unref (file_parent); } } static void label_entry_changed_cb (GtkEntry *entry, BraseroBurnSession *session) { brasero_burn_session_set_label (session, gtk_entry_get_text (entry)); } static void burn_content_to_disc (GthBurnTask *task) { static gboolean initialized = FALSE; GdkCursor *cursor; GtkWidget *dialog; GtkBuilder *builder; GtkWidget *options; GtkResponseType result; cursor = _gdk_cursor_new_for_widget (GTK_WIDGET (task->priv->browser), GDK_WATCH); gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (task->priv->browser)), cursor); g_object_unref (cursor); if (! initialized) { brasero_media_library_start (); brasero_burn_library_start (NULL, NULL); initialized = TRUE; } task->priv->session = brasero_session_cfg_new (); task->priv->track = brasero_track_data_cfg_new (); brasero_burn_session_add_track (BRASERO_BURN_SESSION (task->priv->session), BRASERO_TRACK (task->priv->track), NULL); g_object_unref (task->priv->track); g_hash_table_foreach (task->priv->content, add_content_list, task); dialog = brasero_burn_options_new (task->priv->session); gtk_window_set_icon_name (GTK_WINDOW (dialog), gtk_window_get_icon_name (GTK_WINDOW (task->priv->browser))); gtk_window_set_title (GTK_WINDOW (dialog), _("Write to Disc")); gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (task->priv->browser)); builder = _gtk_builder_new_from_file ("burn-disc-options.ui", "burn_disc"); options = _gtk_builder_get_widget (builder, "options"); gtk_entry_set_text (GTK_ENTRY (_gtk_builder_get_widget (builder, "label_entry")), g_file_info_get_display_name (gth_browser_get_location_data (task->priv->browser)->info)); g_signal_connect (_gtk_builder_get_widget (builder, "label_entry"), "changed", G_CALLBACK (label_entry_changed_cb), task->priv->session); gtk_widget_show (options); brasero_burn_options_add_options (BRASERO_BURN_OPTIONS (dialog), options); gth_task_dialog (GTH_TASK (task), TRUE, dialog); result = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); if (result == GTK_RESPONSE_OK) { dialog = brasero_burn_dialog_new (); gtk_window_set_icon_name (GTK_WINDOW (dialog), gtk_window_get_icon_name (GTK_WINDOW (task->priv->browser))); gtk_window_set_title (GTK_WINDOW (dialog), _("Write to Disc")); brasero_session_cfg_disable (task->priv->session); gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (task->priv->browser)); gtk_window_present (GTK_WINDOW (dialog)); brasero_burn_dialog_run (BRASERO_BURN_DIALOG (dialog), BRASERO_BURN_SESSION (task->priv->session)); gtk_widget_destroy (dialog); } gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (task->priv->browser)), NULL); g_object_unref (task->priv->session); gth_task_completed (GTH_TASK (task), NULL); } static void done_func (GObject *object, GError *error, gpointer user_data) { GthBurnTask *task = user_data; if (error != NULL) { gth_task_completed (GTH_TASK (task), error); return; } burn_content_to_disc (task); } static void for_each_file_func (GFile *file, GFileInfo *info, gpointer user_data) { GthBurnTask *task = user_data; GthFileData *file_data; if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR) return; file_data = gth_file_data_new (file, info); if (gth_test_match (task->priv->test, file_data)) { GList *list; list = g_hash_table_lookup (task->priv->content, task->priv->current_directory); list = g_list_prepend (list, g_file_dup (file)); g_hash_table_insert (task->priv->content, g_strdup (task->priv->current_directory), list); } g_object_unref (file_data); } static DirOp start_dir_func (GFile *directory, GFileInfo *info, GError **error, gpointer user_data) { GthBurnTask *task = user_data; GFile *parent; char *escaped; GFile *destination; char *uri; g_free (task->priv->current_directory); parent = g_file_get_parent (directory); escaped = _g_utf8_replace_str (g_file_info_get_display_name (info), "/", "-"); destination = g_file_get_child_for_display_name (parent, escaped, NULL); uri = g_file_get_uri (destination); task->priv->current_directory = g_uri_unescape_string (uri, NULL); g_hash_table_insert (task->priv->content, g_strdup (task->priv->current_directory), NULL); g_free (uri); g_object_unref (destination); g_free (escaped); g_object_unref (parent); return DIR_OP_CONTINUE; } static void source_dialog_response_cb (GtkDialog *dialog, int response, GthBurnTask *task) { gtk_widget_hide (task->priv->dialog); gth_task_dialog (GTH_TASK (task), FALSE, NULL); if (response == GTK_RESPONSE_OK) { if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (_gtk_builder_get_widget (task->priv->builder, "selection_radiobutton")))) { g_hash_table_replace (task->priv->content, g_file_get_uri (task->priv->location), g_list_reverse (task->priv->selected_files)); task->priv->selected_files = NULL; burn_content_to_disc (task); } else { GSettings *settings; gboolean recursive; _g_object_list_unref (task->priv->selected_files); task->priv->selected_files = NULL; settings = g_settings_new (PIX_BROWSER_SCHEMA); recursive = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (_gtk_builder_get_widget (task->priv->builder, "folder_recursive_radiobutton"))); task->priv->test = gth_main_get_general_filter (); task->priv->file_source = gth_main_get_file_source (task->priv->location); gth_file_source_for_each_child (task->priv->file_source, task->priv->location, recursive, g_settings_get_boolean (settings, PREF_BROWSER_FAST_FILE_TYPE) ? GFILE_STANDARD_ATTRIBUTES_WITH_FAST_CONTENT_TYPE : GFILE_STANDARD_ATTRIBUTES_WITH_CONTENT_TYPE, start_dir_func, for_each_file_func, done_func, task); g_object_unref (settings); } } else gth_task_completed (GTH_TASK (task), NULL); } static void gth_burn_task_exec (GthTask *base) { GthBurnTask *task = (GthBurnTask *) base; task->priv->builder = _gtk_builder_new_from_file ("burn-source-selector.ui", "burn_disc"); task->priv->dialog = g_object_new (GTK_TYPE_DIALOG, "title", _("Write to Disc"), "transient-for", GTK_WINDOW (task->priv->browser), "modal", FALSE, "use-header-bar", _gtk_settings_get_dialogs_use_header (), NULL); gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (task->priv->dialog))), _gtk_builder_get_widget (task->priv->builder, "source_selector")); gtk_dialog_add_buttons (GTK_DIALOG (task->priv->dialog), _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL, _("_Continue"), GTK_RESPONSE_OK, NULL); _gtk_dialog_add_class_to_response (GTK_DIALOG (task->priv->dialog), GTK_RESPONSE_OK, GTK_STYLE_CLASS_SUGGESTED_ACTION); if (task->priv->selected_files == NULL) gtk_widget_set_sensitive (_gtk_builder_get_widget (task->priv->builder, "selection_radiobutton"), FALSE); else if ((task->priv->selected_files != NULL) && (task->priv->selected_files->next != NULL)) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (_gtk_builder_get_widget (task->priv->builder, "selection_radiobutton")), TRUE); gth_task_dialog (GTH_TASK (task), TRUE, task->priv->dialog); g_signal_connect (task->priv->dialog, "response", G_CALLBACK (source_dialog_response_cb), task); gtk_widget_show_all (task->priv->dialog); } static void gth_burn_task_cancelled (GthTask *task) { /* FIXME */ } static void gth_burn_task_class_init (GthBurnTaskClass *class) { GObjectClass *object_class; GthTaskClass *task_class; object_class = (GObjectClass*) class; object_class->finalize = gth_burn_task_finalize; task_class = (GthTaskClass*) class; task_class->exec = gth_burn_task_exec; task_class->cancelled = gth_burn_task_cancelled; } static void gth_burn_task_init (GthBurnTask *task) { task->priv = gth_burn_task_get_instance_private (task); task->priv->browser = NULL; task->priv->location = NULL; task->priv->selected_files = NULL; task->priv->dialog = NULL; task->priv->builder = NULL; task->priv->test = NULL; task->priv->file_source = NULL; task->priv->base_directory = NULL; task->priv->current_directory = NULL; task->priv->content = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); task->priv->parents = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gtk_tree_path_free); task->priv->session = NULL; task->priv->track = NULL; } GthTask * gth_burn_task_new (GthBrowser *browser, GList *selected_files) { GthBurnTask *task; task = (GthBurnTask *) g_object_new (GTH_TYPE_BURN_TASK, NULL); task->priv->browser = g_object_ref (browser); task->priv->location = g_file_dup (gth_browser_get_location (browser)); task->priv->base_directory = g_file_get_uri (task->priv->location); task->priv->selected_files = _g_object_list_ref (selected_files); return (GthTask*) task; }