From 522cca5ac1473405d325fce4fef0d6e0343f6257 Mon Sep 17 00:00:00 2001 From: Frediano Ziglio Date: Wed, 10 Jun 2020 13:27:36 +0100 Subject: [PATCH] virt-viewer-file-transfer-dialog: Reports detailed errors Instead of showing just a generic error with a list of files group files by error and show them. This solves https://bugzilla.redhat.com/show_bug.cgi?id=1753563 Signed-off-by: Frediano Ziglio --- src/virt-viewer-file-transfer-dialog.c | 47 +++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/virt-viewer-file-transfer-dialog.c b/src/virt-viewer-file-transfer-dialog.c index b510d8e..975346f 100644 --- a/src/virt-viewer-file-transfer-dialog.c +++ b/src/virt-viewer-file-transfer-dialog.c @@ -188,6 +188,23 @@ error_dialog_response(GtkDialog *dialog, gtk_widget_destroy(GTK_WIDGET(dialog)); } +static const gchar* +file_error_message(GError *err) +{ + if (err && err->message) { + return err->message; + } + return _("Unspecified error"); +} + +static gint +compare_file_error(gconstpointer a, gconstpointer b) +{ + GError *error_a = g_object_get_data(G_OBJECT(a), "virt-viewer-error"); + GError *error_b = g_object_get_data(G_OBJECT(b), "virt-viewer-error"); + return g_strcmp0(file_error_message(error_a), file_error_message(error_b)); +} + static gboolean hide_transfer_dialog(gpointer data) { VirtViewerFileTransferDialog *self = data; @@ -202,10 +219,26 @@ static gboolean hide_transfer_dialog(gpointer data) GString *msg = g_string_new(""); GtkWidget *dialog, *files_label, *scrolled_window, *area; GtkRequisition files_label_sz; + const gchar *last_error = NULL; + const gchar *group_separator = ""; + + self->priv->failed = g_slist_sort(self->priv->failed, compare_file_error); for (sl = self->priv->failed; sl != NULL; sl = g_slist_next(sl)) { SpiceFileTransferTask *failed_task = sl->data; gchar *filename = spice_file_transfer_task_get_filename(failed_task); + + const gchar *error_message = + file_error_message(g_object_get_data(G_OBJECT(failed_task), "virt-viewer-error")); + if (g_strcmp0(error_message, last_error) != 0) { + // add error message + gchar *header = g_markup_printf_escaped("%s%s:", group_separator, error_message); + g_string_append(msg, header); + g_free(header); + last_error = error_message; + group_separator = "\n\n"; + } + if (filename == NULL) { guint id; @@ -214,15 +247,16 @@ static gboolean hide_transfer_dialog(gpointer data) filename = g_strdup_printf("(task #%u)", id); } - g_string_append_printf(msg, "\n%s", filename); + gchar *escaped_filename = g_markup_printf_escaped("\n%s", filename); + g_string_append(msg, escaped_filename); + g_free(escaped_filename); g_free(filename); } g_slist_free_full(self->priv->failed, g_object_unref); self->priv->failed = NULL; dialog = gtk_message_dialog_new(GTK_WINDOW(self), 0, GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _("An error caused the following file transfers to fail:")); + GTK_BUTTONS_OK, NULL); gtk_window_set_title(GTK_WINDOW(dialog), "Transfer error"); scrolled_window = gtk_scrolled_window_new(NULL, NULL); @@ -232,8 +266,9 @@ static gboolean hide_transfer_dialog(gpointer data) area = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog)); gtk_container_add(GTK_CONTAINER(area), scrolled_window); - files_label = gtk_label_new(msg->str + 1); /* skip the initial '\n' */ + files_label = gtk_label_new(NULL); gtk_label_set_selectable(GTK_LABEL(files_label), TRUE); + gtk_label_set_markup(GTK_LABEL(files_label), msg->str); gtk_container_add(GTK_CONTAINER(scrolled_window), files_label); g_string_free(msg, TRUE); @@ -242,6 +277,8 @@ static gboolean hide_transfer_dialog(gpointer data) /* adjust panel to file_label height */ gtk_widget_get_preferred_size(files_label, NULL, &files_label_sz); + gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(scrolled_window), + MIN(files_label_sz.width, 500)); gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled_window), MIN(files_label_sz.height, 170)); } @@ -256,6 +293,8 @@ static void task_finished(SpiceFileTransferTask *task, VirtViewerFileTransferDialog *self = VIRT_VIEWER_FILE_TRANSFER_DIALOG(user_data); if (error && !g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_object_set_data_full(G_OBJECT(task), "virt-viewer-error", + g_error_copy(error), (GDestroyNotify) g_error_free); self->priv->failed = g_slist_prepend(self->priv->failed, g_object_ref(task)); g_warning("File transfer task %p failed: %s", task, error->message); } -- 2.28.0