From 005a154b9490a49dcc255409d50c8a54c35aa80b Mon Sep 17 00:00:00 2001 From: Ting-Wei Lan Date: Sun, 8 Sep 2013 00:33:03 +0800 Subject: Automatically create an archive if necessary when sending a file These codes may still have some bugs because sending two or more files at the same time may cause Telepathy internal error. Temporary archives and directories are not removed after transfer are completed. --- libempathy-gtk/empathy-ui-utils.c | 253 +++++++++++++++++++++++++++++++++++++- 1 file changed, 251 insertions(+), 2 deletions(-) diff --git a/libempathy-gtk/empathy-ui-utils.c b/libempathy-gtk/empathy-ui-utils.c index 69b50e266..088518c94 100644 --- a/libempathy-gtk/empathy-ui-utils.c +++ b/libempathy-gtk/empathy-ui-utils.c @@ -664,6 +664,20 @@ empathy_pixbuf_protocol_from_contact_scaled (EmpathyContact *contact, return pixbuf; } +struct SendData +{ + GFile *file; + GFile *destination; + GCancellable *cancellable; + EmpathyContact *contact; + GtkWidget *dialog; + GtkProgressBar *progress; + GtkLabel *progress_label; + GtkLabel *filename_label; + gboolean dialog_shown; + gint64 last_notify; +}; + void empathy_url_show (GtkWidget *parent, const char *url) @@ -701,8 +715,8 @@ empathy_url_show (GtkWidget *parent, g_free (real_url); } -void -empathy_send_file (EmpathyContact *contact, +static void +send_file (EmpathyContact *contact, GFile *file) { EmpathyFTFactory *factory; @@ -725,6 +739,226 @@ empathy_send_file (EmpathyContact *contact, g_object_unref (factory); } +static void +send_data_free (struct SendData *send_data) +{ + g_clear_object (&(send_data->file)); + g_clear_object (&(send_data->destination)); + g_clear_object (&(send_data->contact)); + g_clear_object (&(send_data->cancellable)); + if (send_data->dialog != NULL) + gtk_widget_destroy (send_data->dialog); + g_free (send_data); +} + +static void +send_file_autoar_decide_dest_cb (AutoarCreate *arcreate, + GFile *destination, + struct SendData *send_data) +{ + send_data->destination = g_object_ref (destination); +} + +static void +send_file_autoar_dialog_response_cb (GtkDialog *dialog, + gint response_id, + struct SendData *send_data) +{ + if (response_id == GTK_RESPONSE_CANCEL) + g_cancellable_cancel (send_data->cancellable); +} + +static void +send_file_autoar_create_dialog (struct SendData *send_data) +{ + GtkWidget *content; + GtkBox *vbox; + char *str, *filename, *destname; + + send_data->dialog = gtk_dialog_new_with_buttons ( + _("Creating Archives…"), NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + _("Cancel"), GTK_RESPONSE_CANCEL, + NULL); + send_data->progress = GTK_PROGRESS_BAR (gtk_progress_bar_new ()); + send_data->progress_label = GTK_LABEL (gtk_label_new (NULL)); + + str = g_strdup_printf ("%s -> %s", + filename = autoar_common_g_file_get_name (send_data->file), + destname = autoar_common_g_file_get_name (send_data->destination)); + send_data->filename_label = GTK_LABEL (gtk_label_new (str)); + + vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 5)); + gtk_box_pack_start (vbox, GTK_WIDGET (send_data->filename_label), + FALSE, FALSE, 0); + gtk_box_pack_start (vbox, GTK_WIDGET (send_data->progress), + FALSE, FALSE, 0); + gtk_box_pack_start (vbox, GTK_WIDGET (send_data->progress_label), + FALSE, FALSE, 0); + content = gtk_dialog_get_content_area (GTK_DIALOG (send_data->dialog)); + gtk_container_add (GTK_CONTAINER (content), GTK_WIDGET (vbox)); + + g_signal_connect (send_data->dialog, "response", + G_CALLBACK (send_file_autoar_dialog_response_cb), send_data); + + g_free (str); + g_free (filename); + g_free (destname); +} + +static void +send_file_autoar_progress_cb (AutoarCreate *arcreate, + guint64 completed_size, + guint completed_files, + struct SendData *send_data) +{ + gint64 mtime; + + DEBUG ("%s: size = %" G_GUINT64_FORMAT ", files = %u", + __func__, completed_size, completed_files); + + mtime = g_get_monotonic_time (); + if (mtime - send_data->last_notify < 200000) + return; + + send_data->last_notify = mtime; + + if (!(send_data->dialog_shown)) + { + if (send_data->dialog == NULL) + send_file_autoar_create_dialog (send_data); + gtk_widget_show_all (send_data->dialog); + send_data->dialog_shown = TRUE; + } + + if (send_data->progress != NULL) + gtk_progress_bar_pulse (send_data->progress); + + if (send_data->progress_label != NULL) + { + gchar *msg, *size; + msg = g_strdup_printf ( + _("%u files (%s) are archived"), + completed_files, size = g_format_size (completed_size)); + gtk_label_set_text (send_data->progress_label, msg); + g_free (msg); + g_free (size); + } +} + +static void +send_file_autoar_cancelled_cb (AutoarCreate *arcreate, + struct SendData *send_data) +{ + send_data_free (send_data); +} + +static void +send_file_autoar_completed_cb (AutoarCreate *arcreate, + struct SendData *send_data) +{ + send_file (send_data->contact, send_data->destination); + send_data_free (send_data); +} + +static void +send_file_autoar_error_cb (AutoarCreate *arcreate, + GError *error, + struct SendData *send_data) +{ + GtkWidget *error_dialog; + char *filename; + + error_dialog = gtk_message_dialog_new_with_markup ( + NULL, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, + "%s", + filename = autoar_common_g_file_get_name (send_data->file)); + gtk_message_dialog_format_secondary_text ( + GTK_MESSAGE_DIALOG (error_dialog), "%s", error->message); + gtk_widget_show_all (error_dialog); + g_signal_connect_swapped (error_dialog, "response", + G_CALLBACK (gtk_widget_destroy), error_dialog); + + send_data_free (send_data); + g_free (filename); +} + +static void +send_file_info_ready_cb (GFile *file, + GAsyncResult *res, + EmpathyContact *contact) +{ + GFileInfo *file_info; + GFileType file_type; + + file_info = g_file_query_info_finish (file, res, NULL); + if (file_info == NULL) + return; + + file_type = g_file_info_get_file_type (file_info); + g_object_unref (file_info); + + if (file_type == G_FILE_TYPE_DIRECTORY) + { + struct SendData *send_data; + AutoarPref *arpref; + AutoarCreate *arcreate; + gchar *template; + GFile *archive_dir; + gchar *archive_dir_path; + + arpref = g_object_get_data (G_OBJECT (contact), "autoar-pref"); + template = g_strdup_printf ("empathy-%s-XXXXXX", g_get_user_name ()); + archive_dir_path = g_dir_make_tmp (template, NULL); + if (archive_dir_path == NULL) + { + g_free (template); + return; + } + + DEBUG ("tmpdir = %s", archive_dir_path); + archive_dir = g_file_new_for_path (archive_dir_path); + arcreate = autoar_create_new_file (arpref, archive_dir, file, NULL); + send_data = g_new0 (struct SendData, 1); + send_data->contact = g_object_ref (contact); + send_data->file = g_object_ref (file); + send_data->cancellable = g_cancellable_new (); + send_data->last_notify = g_get_monotonic_time (); + + g_signal_connect (arcreate, "decide-dest", + G_CALLBACK (send_file_autoar_decide_dest_cb), send_data); + g_signal_connect (arcreate, "progress", + G_CALLBACK (send_file_autoar_progress_cb), send_data); + g_signal_connect (arcreate, "cancelled", + G_CALLBACK (send_file_autoar_cancelled_cb), send_data); + g_signal_connect (arcreate, "completed", + G_CALLBACK (send_file_autoar_completed_cb), send_data); + g_signal_connect (arcreate, "error", + G_CALLBACK (send_file_autoar_error_cb), send_data); + autoar_create_start_async (arcreate, send_data->cancellable); + + g_free (template); + g_free (archive_dir_path); + g_object_unref (archive_dir); + g_object_unref (arcreate); + } + else + { + send_file (contact, file); + } +} + +void +empathy_send_file (EmpathyContact *contact, + GFile *file) +{ + g_file_query_info_async (file, + G_FILE_ATTRIBUTE_STANDARD_TYPE, + G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, + NULL, (GAsyncReadyCallback) send_file_info_ready_cb, contact); +} + void empathy_send_file_from_uri_list (EmpathyContact *contact, const gchar *uri_list) @@ -764,11 +998,20 @@ file_manager_send_file_response_cb (GtkDialog *widget, EmpathyContact *contact) { GFile *file; + GtkWidget *format; + AutoarPref *arpref; + int arformat, arfilter; if (response_id == GTK_RESPONSE_OK || response_id == EMPATHY_RESPONSE_SEND) { file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (widget)); + arpref = g_object_get_data (G_OBJECT (contact), "autoar-pref"); + format = g_object_get_data (G_OBJECT (contact), "autoar-format"); + autoar_gtk_format_filter_simple_get (format, &arformat, &arfilter); + autoar_pref_set_default_format (arpref, arformat); + autoar_pref_set_default_filter (arpref, arfilter); + empathy_send_file (contact, file); g_object_unref (file); @@ -860,8 +1103,14 @@ empathy_send_file_with_file_chooser (EmpathyContact *contact) g_signal_connect (widget, "response", G_CALLBACK (file_manager_send_file_response_cb), g_object_ref (contact)); + g_object_set_data_full (G_OBJECT (contact), "autoar-pref", + g_object_ref (arpref), g_object_unref); + g_object_set_data_full (G_OBJECT (contact), "autoar-format", + g_object_ref (format_combo), g_object_unref); gtk_widget_show (widget); + g_object_unref (settings); + g_object_unref (arpref); } static void -- cgit v1.2.3