1 /*
2  * xed-io-error-info-bar.c
3  * This file is part of xed
4  *
5  * Copyright (C) 2005 - Paolo Maggi
6  *
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.
11  *
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.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 /*
24  * Modified by the xed Team, 2005. See the AUTHORS file for a
25  * list of people on the xed Team.
26  * See the ChangeLog files for a list of changes.
27  *
28  * $Id$
29  */
30 
31 /*
32  * Verbose error reporting for file I/O operations (load, save, revert, create)
33  */
34 
35 #include <config.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <glib/gi18n.h>
39 #include <gio/gio.h>
40 #include <xed/xed-encodings-combo-box.h>
41 
42 #include "xed-settings.h"
43 #include "xed-utils.h"
44 #include "xed-document.h"
45 #include "xed-io-error-info-bar.h"
46 
47 #define MAX_URI_IN_DIALOG_LENGTH 50
48 
49 static gboolean
is_recoverable_error(const GError * error)50 is_recoverable_error (const GError *error)
51 {
52     gboolean is_recoverable = FALSE;
53 
54     if (error->domain == G_IO_ERROR)
55     {
56         switch (error->code)
57         {
58             case G_IO_ERROR_PERMISSION_DENIED:
59             case G_IO_ERROR_NOT_FOUND:
60             case G_IO_ERROR_HOST_NOT_FOUND:
61             case G_IO_ERROR_TIMED_OUT:
62             case G_IO_ERROR_NOT_MOUNTABLE_FILE:
63             case G_IO_ERROR_NOT_MOUNTED:
64             case G_IO_ERROR_BUSY:
65                 is_recoverable = TRUE;
66         }
67     }
68 
69     return is_recoverable;
70 }
71 
72 static gboolean
is_gio_error(const GError * error,gint code)73 is_gio_error (const GError *error,
74               gint          code)
75 {
76     return error->domain == G_IO_ERROR && error->code == code;
77 }
78 
79 static void
set_contents(GtkWidget * area,GtkWidget * contents)80 set_contents (GtkWidget *area,
81               GtkWidget *contents)
82 {
83     GtkWidget *content_area;
84 
85     content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (area));
86     gtk_container_add (GTK_CONTAINER (content_area), contents);
87 }
88 
89 static void
set_info_bar_text_and_icon(GtkWidget * info_bar,const gchar * icon_name,const gchar * primary_text,const gchar * secondary_text)90 set_info_bar_text_and_icon (GtkWidget   *info_bar,
91                             const gchar *icon_name,
92                             const gchar *primary_text,
93                             const gchar *secondary_text)
94 {
95     GtkWidget *hbox_content;
96     GtkWidget *image;
97     GtkWidget *vbox;
98     gchar *primary_markup;
99     gchar *secondary_markup;
100     GtkWidget *primary_label;
101     GtkWidget *secondary_label;
102 
103     hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
104 
105     image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_DIALOG);
106     gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0);
107     gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
108     gtk_widget_set_valign (image, GTK_ALIGN_START);
109 
110     vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
111     gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
112 
113     primary_markup = g_strdup_printf ("<b>%s</b>", primary_text);
114     primary_label = gtk_label_new (primary_markup);
115     g_free (primary_markup);
116     gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
117     gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
118     gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
119     gtk_widget_set_halign (primary_label, GTK_ALIGN_START);
120     gtk_widget_set_can_focus (primary_label, TRUE);
121     gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
122 
123     if (secondary_text != NULL)
124     {
125         secondary_markup = g_strdup_printf ("<small>%s</small>", secondary_text);
126         secondary_label = gtk_label_new (secondary_markup);
127         g_free (secondary_markup);
128         gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
129         gtk_widget_set_can_focus (secondary_label, TRUE);
130         gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
131         gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
132         gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
133         gtk_widget_set_halign (secondary_label, GTK_ALIGN_START);
134     }
135 
136     gtk_widget_show_all (hbox_content);
137     set_contents (info_bar, hbox_content);
138 }
139 
140 static GtkWidget *
create_io_loading_error_info_bar(const gchar * primary_text,const gchar * secondary_text,gboolean recoverable_error)141 create_io_loading_error_info_bar (const gchar *primary_text,
142                                   const gchar *secondary_text,
143                                   gboolean     recoverable_error)
144 {
145     GtkWidget *info_bar;
146 
147     info_bar = gtk_info_bar_new_with_buttons (_("_Cancel"), GTK_RESPONSE_CANCEL, NULL);
148     gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_ERROR);
149 
150     set_info_bar_text_and_icon (info_bar, "dialog-error-symbolic", primary_text, secondary_text);
151 
152     if (recoverable_error)
153     {
154         gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), _("_Retry"), GTK_RESPONSE_OK);
155     }
156 
157     return info_bar;
158 }
159 
160 static gboolean
parse_gio_error(gint code,gchar ** error_message,gchar ** message_details,GFile * location,const gchar * uri_for_display)161 parse_gio_error (gint          code,
162                  gchar       **error_message,
163                  gchar       **message_details,
164                  GFile        *location,
165                  const gchar  *uri_for_display)
166 {
167     gboolean ret = TRUE;
168 
169     switch (code)
170     {
171         case G_IO_ERROR_NOT_FOUND:
172         case G_IO_ERROR_NOT_DIRECTORY:
173             *error_message = g_strdup_printf (_("Could not find the file %s."), uri_for_display);
174             *message_details = g_strdup (_("Please check that you typed the "
175                                          "location correctly and try again."));
176             break;
177         case G_IO_ERROR_NOT_SUPPORTED:
178             {
179                 gchar *scheme_string;
180                 gchar *scheme_markup;
181 
182                 scheme_string = g_file_get_uri_scheme (location);
183 
184                 if ((scheme_string != NULL) && g_utf8_validate (scheme_string, -1, NULL))
185                 {
186                     scheme_markup = g_markup_printf_escaped ("<i>%s:</i>", scheme_string);
187 
188                     /* Translators: %s is a URI scheme (like for example http:, ftp:, etc.) */
189                     *message_details = g_strdup_printf (_("xed cannot handle %s locations."), scheme_markup);
190                     g_free (scheme_markup);
191                 }
192                 else
193                 {
194                     *message_details = g_strdup (_("xed cannot handle this location."));
195                 }
196 
197                 g_free (scheme_string);
198             }
199             break;
200         case G_IO_ERROR_NOT_MOUNTABLE_FILE:
201             *message_details = g_strdup (_("The location of the file cannot be mounted."));
202             break;
203         case G_IO_ERROR_NOT_MOUNTED:
204             *message_details = g_strdup( _("The location of the file cannot be accessed because it is not mounted."));
205             break;
206         case G_IO_ERROR_IS_DIRECTORY:
207             *error_message = g_strdup_printf (_("%s is a directory."), uri_for_display);
208             *message_details = g_strdup (_("Please check that you typed the "
209                                          "location correctly and try again."));
210             break;
211         case G_IO_ERROR_INVALID_FILENAME:
212             *error_message = g_strdup_printf (_("%s is not a valid location."), uri_for_display);
213             *message_details = g_strdup (_("Please check that you typed the "
214                                          "location correctly and try again."));
215             break;
216         case G_IO_ERROR_HOST_NOT_FOUND:
217             /* This case can be hit for user-typed strings like "foo" due to
218              * the code that guesses web addresses when there's no initial "/".
219              * But this case is also hit for legitimate web addresses when
220              * the proxy is set up wrong.
221              */
222             {
223                 gchar *hn = NULL;
224                 gchar *uri;
225 
226                 uri = g_file_get_uri (location);
227 
228                 if (uri && xed_utils_decode_uri (uri, NULL, NULL, &hn, NULL, NULL))
229                 {
230                     if (hn != NULL)
231                     {
232                         gchar *host_markup;
233                         gchar *host_name;
234 
235                         host_name = xed_utils_make_valid_utf8 (hn);
236                         g_free (hn);
237 
238                         host_markup = g_markup_printf_escaped ("<i>%s</i>", host_name);
239                         g_free (host_name);
240 
241                         /* Translators: %s is a host name */
242                         *message_details = g_strdup_printf (_("Host %s could not be found. "
243                                                             "Please check that your proxy settings "
244                                                             "are correct and try again."),
245                                                             host_markup);
246 
247                         g_free (host_markup);
248                     }
249                 }
250 
251                 g_free (uri);
252 
253                 if (!*message_details)
254                 {
255                     /* use the same string as INVALID_HOST */
256                     *message_details = g_strdup_printf (_("Hostname was invalid. "
257                                                         "Please check that you typed the location "
258                                                         "correctly and try again."));
259                 }
260             }
261             break;
262         case G_IO_ERROR_NOT_REGULAR_FILE:
263             *message_details = g_strdup_printf (_("%s is not a regular file."), uri_for_display);
264             break;
265         case G_IO_ERROR_TIMED_OUT:
266             *message_details = g_strdup (_("Connection timed out. Please try again."));
267             break;
268         default:
269             ret = FALSE;
270             break;
271     }
272 
273     return ret;
274 }
275 
276 static void
parse_error(const GError * error,gchar ** error_message,gchar ** message_details,GFile * location,const gchar * uri_for_display)277 parse_error (const GError *error,
278              gchar       **error_message,
279              gchar       **message_details,
280              GFile        *location,
281              const gchar  *uri_for_display)
282 {
283     gboolean ret = FALSE;
284 
285     if (error->domain == G_IO_ERROR)
286     {
287         ret = parse_gio_error (error->code, error_message, message_details, location, uri_for_display);
288     }
289 
290     if (!ret)
291     {
292         g_warning ("Hit unhandled case %d (%s) in %s.", error->code, error->message, G_STRFUNC);
293         *message_details = g_strdup_printf (_("Unexpected error: %s"), error->message);
294     }
295 }
296 
297 GtkWidget *
xed_unrecoverable_reverting_error_info_bar_new(GFile * location,const GError * error)298 xed_unrecoverable_reverting_error_info_bar_new (GFile        *location,
299                                                 const GError *error)
300 {
301     gchar *error_message = NULL;
302     gchar *message_details = NULL;
303     gchar *full_formatted_uri;
304     gchar *uri_for_display;
305     gchar *temp_uri_for_display;
306     GtkWidget *info_bar;
307 
308     g_return_val_if_fail (G_IS_FILE (location), NULL);
309     g_return_val_if_fail (error != NULL, NULL);
310     g_return_val_if_fail ((error->domain == GTK_SOURCE_FILE_LOADER_ERROR) || error->domain == G_IO_ERROR, NULL);
311 
312     full_formatted_uri = g_file_get_parse_name (location);
313 
314     /* Truncate the URI so it doesn't get insanely wide. Note that even
315      * though the dialog uses wrapped text, if the URI doesn't contain
316      * white space then the text-wrapping code is too stupid to wrap it.
317      */
318     temp_uri_for_display = xed_utils_str_middle_truncate (full_formatted_uri, MAX_URI_IN_DIALOG_LENGTH);
319     g_free (full_formatted_uri);
320 
321     uri_for_display = g_markup_printf_escaped ("<i>%s</i>", temp_uri_for_display);
322     g_free (temp_uri_for_display);
323 
324     if (is_gio_error (error, G_IO_ERROR_NOT_FOUND))
325     {
326         message_details = g_strdup (_("xed cannot find the file. "
327                                     "Perhaps it has recently been deleted."));
328     }
329     else
330     {
331         parse_error (error, &error_message, &message_details, location, uri_for_display);
332     }
333 
334     if (error_message == NULL)
335     {
336         error_message = g_strdup_printf (_("Could not revert the file %s."), uri_for_display);
337     }
338 
339     info_bar = create_io_loading_error_info_bar (error_message, message_details, FALSE);
340 
341     g_free (uri_for_display);
342     g_free (error_message);
343     g_free (message_details);
344 
345     return info_bar;
346 }
347 
348 static void
create_combo_box(GtkWidget * info_bar,GtkWidget * vbox)349 create_combo_box (GtkWidget *info_bar,
350                   GtkWidget *vbox)
351 {
352     GtkWidget *hbox;
353     GtkWidget *label;
354     GtkWidget *menu;
355     gchar *label_markup;
356 
357     hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
358 
359     label_markup = g_strdup_printf ("<small>%s</small>", _("Ch_aracter Encoding:"));
360     label = gtk_label_new_with_mnemonic (label_markup);
361     g_free (label_markup);
362     gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
363     menu = xed_encodings_combo_box_new (TRUE);
364     g_object_set_data (G_OBJECT (info_bar), "xed-info-bar-encoding-menu", menu);
365 
366     gtk_label_set_mnemonic_widget (GTK_LABEL (label), menu);
367     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
368     gtk_box_pack_start (GTK_BOX (hbox), menu, FALSE, FALSE, 0);
369 
370     gtk_widget_show_all (hbox);
371     gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
372 }
373 
374 static GtkWidget *
create_conversion_error_info_bar(const gchar * primary_text,const gchar * secondary_text,gboolean edit_anyway)375 create_conversion_error_info_bar (const gchar *primary_text,
376                                   const gchar *secondary_text,
377                                   gboolean     edit_anyway)
378 {
379     GtkWidget *info_bar;
380     GtkWidget *hbox_content;
381     GtkWidget *image;
382     GtkWidget *vbox;
383     gchar *primary_markup;
384     gchar *secondary_markup;
385     GtkWidget *primary_label;
386     GtkWidget *secondary_label;
387 
388     info_bar = gtk_info_bar_new ();
389 
390     gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), _("_Retry"), GTK_RESPONSE_OK);
391 
392     if (edit_anyway)
393     {
394         gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
395         /* Translators: the access key chosen for this string should be
396          different from other main menu access keys (Open, Edit, View...) */
397                      _("Edit Any_way"),
398                      GTK_RESPONSE_YES);
399         gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_WARNING);
400     }
401     else
402     {
403         gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_ERROR);
404     }
405 
406     gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), _("_Cancel"), GTK_RESPONSE_CANCEL);
407 
408     hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
409 
410     image = gtk_image_new_from_icon_name ("dialog-error-symbolic", GTK_ICON_SIZE_DIALOG);
411     gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0);
412     gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
413     gtk_widget_set_valign (image, GTK_ALIGN_START);
414 
415     vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
416     gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
417 
418     primary_markup = g_strdup_printf ("<b>%s</b>", primary_text);
419     primary_label = gtk_label_new (primary_markup);
420     g_free (primary_markup);
421     gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
422     gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
423     gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
424     gtk_widget_set_halign (primary_label, GTK_ALIGN_START);
425     gtk_widget_set_can_focus (primary_label, TRUE);
426     gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
427 
428     if (secondary_text != NULL)
429     {
430         secondary_markup = g_strdup_printf ("<small>%s</small>", secondary_text);
431         secondary_label = gtk_label_new (secondary_markup);
432         g_free (secondary_markup);
433         gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
434         gtk_widget_set_can_focus (secondary_label, TRUE);
435         gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
436         gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
437         gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
438         gtk_widget_set_halign (secondary_label, GTK_ALIGN_START);
439     }
440 
441     create_combo_box (info_bar, vbox);
442     gtk_widget_show_all (hbox_content);
443     set_contents (info_bar, hbox_content);
444 
445     return info_bar;
446 }
447 
448 GtkWidget *
xed_io_loading_error_info_bar_new(GFile * location,const GtkSourceEncoding * encoding,const GError * error)449 xed_io_loading_error_info_bar_new (GFile                   *location,
450                                    const GtkSourceEncoding *encoding,
451                                    const GError            *error)
452 {
453     gchar *error_message = NULL;
454     gchar *message_details = NULL;
455     gchar *full_formatted_uri;
456     gchar *uri_for_display;
457     gchar *temp_uri_for_display;
458     GtkWidget *info_bar;
459     gboolean edit_anyway = FALSE;
460     gboolean convert_error = FALSE;
461 
462     g_return_val_if_fail (G_IS_FILE (location), NULL);
463     g_return_val_if_fail (error != NULL, NULL);
464     g_return_val_if_fail (error->domain == GTK_SOURCE_FILE_LOADER_ERROR ||
465                           error->domain == G_IO_ERROR ||
466                           error->domain == G_CONVERT_ERROR, NULL);
467 
468     if (location != NULL)
469     {
470         full_formatted_uri = g_file_get_parse_name (location);
471     }
472     else
473     {
474         full_formatted_uri = g_strdup ("stdin");
475     }
476 
477     /* Truncate the URI so it doesn't get insanely wide. Note that even
478      * though the dialog uses wrapped text, if the URI doesn't contain
479      * white space then the text-wrapping code is too stupid to wrap it.
480      */
481     temp_uri_for_display = xed_utils_str_middle_truncate (full_formatted_uri, MAX_URI_IN_DIALOG_LENGTH);
482     g_free (full_formatted_uri);
483 
484     uri_for_display = g_markup_printf_escaped ("<i>%s</i>", temp_uri_for_display);
485     g_free (temp_uri_for_display);
486 
487     if (is_gio_error (error, G_IO_ERROR_TOO_MANY_LINKS))
488     {
489         message_details = g_strdup (_("The number of followed links is limited and the actual file could not be found within this limit."));
490     }
491     else if (is_gio_error (error, G_IO_ERROR_PERMISSION_DENIED))
492     {
493         message_details = g_strdup (_("You do not have the permissions necessary to open the file."));
494     }
495     else if ((is_gio_error (error, G_IO_ERROR_INVALID_DATA) && encoding == NULL) ||
496              (error->domain == GTK_SOURCE_FILE_LOADER_ERROR &&
497               error->code == GTK_SOURCE_FILE_LOADER_ERROR_ENCODING_AUTO_DETECTION_FAILED))
498     {
499         message_details = g_strconcat (_("xed has not been able to detect "
500                                          "the character encoding."), "\n",
501                                        _("Please check that you are not trying to open a binary file."), "\n",
502                                        _("Select a character encoding from the menu and try again."), NULL);
503         convert_error = TRUE;
504     }
505     else if (error->domain == GTK_SOURCE_FILE_LOADER_ERROR &&
506              error->code == GTK_SOURCE_FILE_LOADER_ERROR_CONVERSION_FALLBACK)
507     {
508         error_message = g_strdup_printf (_("There was a problem opening the file %s."), uri_for_display);
509         message_details = g_strconcat (_("The file you opened has some invalid characters. "
510                                        "If you continue editing this file you could corrupt this "
511                                        "document."), "\n",
512                                        _("You can also choose another character encoding and try again."),
513                                        NULL);
514         edit_anyway = TRUE;
515         convert_error = TRUE;
516     }
517     else if (is_gio_error (error, G_IO_ERROR_INVALID_DATA) && encoding != NULL)
518     {
519         gchar *encoding_name = gtk_source_encoding_to_string (encoding);
520 
521         error_message = g_strdup_printf (_("Could not open the file %s using the %s character encoding."),
522                                          uri_for_display,
523                                          encoding_name);
524         message_details = g_strconcat (_("Please check that you are not trying to open a binary file."), "\n",
525                                        _("Select a different character encoding from the menu and try again."), NULL);
526         convert_error = TRUE;
527 
528         g_free (encoding_name);
529     }
530     else
531     {
532         parse_error (error, &error_message, &message_details, location, uri_for_display);
533     }
534 
535     if (error_message == NULL)
536     {
537         error_message = g_strdup_printf (_("Could not open the file %s."), uri_for_display);
538     }
539 
540     if (convert_error)
541     {
542         info_bar = create_conversion_error_info_bar (error_message, message_details, edit_anyway);
543     }
544     else
545     {
546         info_bar = create_io_loading_error_info_bar (error_message, message_details, is_recoverable_error (error));
547     }
548 
549     g_free (uri_for_display);
550     g_free (error_message);
551     g_free (message_details);
552 
553     return info_bar;
554 }
555 
556 GtkWidget *
xed_conversion_error_while_saving_info_bar_new(GFile * location,const GtkSourceEncoding * encoding,const GError * error)557 xed_conversion_error_while_saving_info_bar_new (GFile                   *location,
558                                                 const GtkSourceEncoding *encoding,
559                                                 const GError            *error)
560 {
561     gchar *error_message = NULL;
562     gchar *message_details = NULL;
563     gchar *full_formatted_uri;
564     gchar *encoding_name;
565     gchar *uri_for_display;
566     gchar *temp_uri_for_display;
567     GtkWidget *info_bar;
568 
569     g_return_val_if_fail (G_IS_FILE (location), NULL);
570     g_return_val_if_fail (error != NULL, NULL);
571     g_return_val_if_fail (error->domain == G_CONVERT_ERROR ||
572                           error->domain == G_IO_ERROR, NULL);
573     g_return_val_if_fail (encoding != NULL, NULL);
574 
575     full_formatted_uri = g_file_get_parse_name (location);
576 
577     /* Truncate the URI so it doesn't get insanely wide. Note that even
578      * though the dialog uses wrapped text, if the URI doesn't contain
579      * white space then the text-wrapping code is too stupid to wrap it.
580      */
581     temp_uri_for_display = xed_utils_str_middle_truncate (full_formatted_uri, MAX_URI_IN_DIALOG_LENGTH);
582     g_free (full_formatted_uri);
583 
584     uri_for_display = g_markup_printf_escaped ("<i>%s</i>", temp_uri_for_display);
585     g_free (temp_uri_for_display);
586 
587     encoding_name = gtk_source_encoding_to_string (encoding);
588 
589     error_message = g_strdup_printf (_("Could not save the file %s using the %s character encoding."),
590                                      uri_for_display,
591                                      encoding_name);
592     message_details = g_strconcat (_("The document contains one or more characters that cannot be encoded "
593                                      "using the specified character encoding."), "\n",
594                                      _("Select a different character encoding from the menu and try again."), NULL);
595 
596     info_bar = create_conversion_error_info_bar (error_message, message_details, FALSE);
597 
598     g_free (uri_for_display);
599     g_free (encoding_name);
600     g_free (error_message);
601     g_free (message_details);
602 
603     return info_bar;
604 }
605 
606 const GtkSourceEncoding *
xed_conversion_error_info_bar_get_encoding(GtkWidget * info_bar)607 xed_conversion_error_info_bar_get_encoding (GtkWidget *info_bar)
608 {
609     gpointer menu;
610 
611     g_return_val_if_fail (GTK_IS_INFO_BAR (info_bar), NULL);
612 
613     menu = g_object_get_data (G_OBJECT (info_bar), "xed-info-bar-encoding-menu");
614     g_return_val_if_fail (menu, NULL);
615 
616     return xed_encodings_combo_box_get_selected_encoding (XED_ENCODINGS_COMBO_BOX (menu));
617 }
618 
619 GtkWidget *
xed_file_already_open_warning_info_bar_new(GFile * location)620 xed_file_already_open_warning_info_bar_new (GFile *location)
621 {
622     GtkWidget *info_bar;
623     GtkWidget *hbox_content;
624     GtkWidget *image;
625     GtkWidget *vbox;
626     gchar *primary_markup;
627     gchar *secondary_markup;
628     GtkWidget *primary_label;
629     GtkWidget *secondary_label;
630     gchar *primary_text;
631     const gchar *secondary_text;
632     gchar *full_formatted_uri;
633     gchar *uri_for_display;
634     gchar *temp_uri_for_display;
635 
636     g_return_val_if_fail (G_IS_FILE (location), NULL);
637 
638     full_formatted_uri = g_file_get_parse_name (location);
639 
640     /* Truncate the URI so it doesn't get insanely wide. Note that even
641      * though the dialog uses wrapped text, if the URI doesn't contain
642      * white space then the text-wrapping code is too stupid to wrap it.
643      */
644     temp_uri_for_display = xed_utils_str_middle_truncate (full_formatted_uri, MAX_URI_IN_DIALOG_LENGTH);
645     g_free (full_formatted_uri);
646 
647     uri_for_display = g_markup_printf_escaped ("<i>%s</i>", temp_uri_for_display);
648     g_free (temp_uri_for_display);
649 
650     info_bar = gtk_info_bar_new ();
651     gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
652     /* Translators: the access key chosen for this string should be
653      different from other main menu access keys (Open, Edit, View...) */
654                  _("Edit Any_way"),
655                  GTK_RESPONSE_YES);
656     gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
657     /* Translators: the access key chosen for this string should be
658      different from other main menu access keys (Open, Edit, View...) */
659                  _("D_on't Edit"),
660                  GTK_RESPONSE_CANCEL);
661     gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_WARNING);
662 
663     hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
664 
665     image = gtk_image_new_from_icon_name ("dialog-warning-symbolic", GTK_ICON_SIZE_DIALOG);
666     gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0);
667     gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
668     gtk_widget_set_valign (image, GTK_ALIGN_START);
669 
670     vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
671     gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
672 
673     primary_text = g_strdup_printf (_("This file (%s) is already open in another xed window."), uri_for_display);
674     g_free (uri_for_display);
675 
676     primary_markup = g_strdup_printf ("<b>%s</b>", primary_text);
677     g_free (primary_text);
678     primary_label = gtk_label_new (primary_markup);
679     g_free (primary_markup);
680     gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
681     gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
682     gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
683     gtk_widget_set_halign (primary_label, GTK_ALIGN_START);
684     gtk_widget_set_can_focus (primary_label, TRUE);
685     gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
686 
687     secondary_text = _("xed opened this instance of the file in a non-editable way. "
688                      "Do you want to edit it anyway?");
689     secondary_markup = g_strdup_printf ("<small>%s</small>", secondary_text);
690     secondary_label = gtk_label_new (secondary_markup);
691     g_free (secondary_markup);
692     gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
693     gtk_widget_set_can_focus (secondary_label, TRUE);
694     gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
695     gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
696     gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
697     gtk_widget_set_halign (secondary_label, GTK_ALIGN_START);
698 
699     gtk_widget_show_all (hbox_content);
700     set_contents (info_bar, hbox_content);
701 
702     return info_bar;
703 }
704 
705 GtkWidget *
xed_externally_modified_saving_error_info_bar_new(GFile * location,const GError * error)706 xed_externally_modified_saving_error_info_bar_new (GFile        *location,
707                                                    const GError *error)
708 {
709     GtkWidget *info_bar;
710     GtkWidget *hbox_content;
711     GtkWidget *image;
712     GtkWidget *vbox;
713     gchar *primary_markup;
714     gchar *secondary_markup;
715     GtkWidget *primary_label;
716     GtkWidget *secondary_label;
717     gchar *primary_text;
718     const gchar *secondary_text;
719     gchar *full_formatted_uri;
720     gchar *uri_for_display;
721     gchar *temp_uri_for_display;
722 
723     g_return_val_if_fail (G_IS_FILE (location), NULL);
724     g_return_val_if_fail (error != NULL, NULL);
725     g_return_val_if_fail (error->domain == GTK_SOURCE_FILE_SAVER_ERROR, NULL);
726     g_return_val_if_fail (error->code == GTK_SOURCE_FILE_SAVER_ERROR_EXTERNALLY_MODIFIED, NULL);
727 
728     full_formatted_uri = g_file_get_parse_name (location);
729 
730     /* Truncate the URI so it doesn't get insanely wide. Note that even
731      * though the dialog uses wrapped text, if the URI doesn't contain
732      * white space then the text-wrapping code is too stupid to wrap it.
733      */
734     temp_uri_for_display = xed_utils_str_middle_truncate (full_formatted_uri, MAX_URI_IN_DIALOG_LENGTH);
735     g_free (full_formatted_uri);
736 
737     uri_for_display = g_markup_printf_escaped ("<i>%s</i>", temp_uri_for_display);
738     g_free (temp_uri_for_display);
739 
740     info_bar = gtk_info_bar_new ();
741 
742     gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), _("S_ave Anyway"), GTK_RESPONSE_YES);
743     gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), _("D_on't Save"), GTK_RESPONSE_CANCEL);
744     gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_WARNING);
745 
746     hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
747 
748     image = gtk_image_new_from_icon_name ("dialog-warning-symbolic", GTK_ICON_SIZE_DIALOG);
749     gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0);
750     gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
751     gtk_widget_set_valign (image, GTK_ALIGN_START);
752 
753     vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
754     gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
755 
756     /* FIXME: review this message, it's not clear since for the user the "modification"
757      * could be interpreted as the changes he made in the document. beside "reading" is
758      * not accurate (since last load/save)
759      */
760     primary_text = g_strdup_printf (_("The file %s has been modified since reading it."), uri_for_display);
761     g_free (uri_for_display);
762 
763     primary_markup = g_strdup_printf ("<b>%s</b>", primary_text);
764     g_free (primary_text);
765     primary_label = gtk_label_new (primary_markup);
766     g_free (primary_markup);
767     gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
768     gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
769     gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
770     gtk_widget_set_halign (primary_label, GTK_ALIGN_START);
771     gtk_widget_set_can_focus (primary_label, TRUE);
772     gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
773 
774     secondary_text = _("If you save it, all the external changes could be lost. Save it anyway?");
775     secondary_markup = g_strdup_printf ("<small>%s</small>", secondary_text);
776     secondary_label = gtk_label_new (secondary_markup);
777     g_free (secondary_markup);
778     gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
779     gtk_widget_set_can_focus (secondary_label, TRUE);
780     gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
781     gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
782     gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
783     gtk_widget_set_halign (secondary_label, GTK_ALIGN_START);
784 
785     gtk_widget_show_all (hbox_content);
786     set_contents (info_bar, hbox_content);
787 
788     return info_bar;
789 }
790 
791 GtkWidget *
xed_no_backup_saving_error_info_bar_new(GFile * location,const GError * error)792 xed_no_backup_saving_error_info_bar_new (GFile        *location,
793                                          const GError *error)
794 {
795     GtkWidget *info_bar;
796     GtkWidget *hbox_content;
797     GtkWidget *image;
798     GtkWidget *vbox;
799     gchar *primary_markup;
800     gchar *secondary_markup;
801     GtkWidget *primary_label;
802     GtkWidget *secondary_label;
803     gchar *primary_text;
804     const gchar *secondary_text;
805     gchar *full_formatted_uri;
806     gchar *uri_for_display;
807     gchar *temp_uri_for_display;
808     gboolean create_backup_copy;
809     GSettings *editor_settings;
810 
811     g_return_val_if_fail (G_IS_FILE (location), NULL);
812     g_return_val_if_fail (error != NULL, NULL);
813     g_return_val_if_fail (error->domain == G_IO_ERROR &&
814                           error->code == G_IO_ERROR_CANT_CREATE_BACKUP, NULL);
815 
816     full_formatted_uri = g_file_get_parse_name (location);
817 
818     /* Truncate the URI so it doesn't get insanely wide. Note that even
819      * though the dialog uses wrapped text, if the URI doesn't contain
820      * white space then the text-wrapping code is too stupid to wrap it.
821      */
822     temp_uri_for_display = xed_utils_str_middle_truncate (full_formatted_uri, MAX_URI_IN_DIALOG_LENGTH);
823     g_free (full_formatted_uri);
824 
825     uri_for_display = g_markup_printf_escaped ("<i>%s</i>", temp_uri_for_display);
826     g_free (temp_uri_for_display);
827 
828     info_bar = gtk_info_bar_new ();
829 
830     gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), _("S_ave Anyway"), GTK_RESPONSE_YES);
831     gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), _("D_on't Save"), GTK_RESPONSE_CANCEL);
832     gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_WARNING);
833 
834     hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
835 
836     image = gtk_image_new_from_icon_name ("dialog-warning-symbolic", GTK_ICON_SIZE_DIALOG);
837     gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0);
838     gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
839     gtk_widget_set_valign (image, GTK_ALIGN_START);
840 
841     vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
842     gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
843 
844     editor_settings = g_settings_new ("org.x.editor.preferences.editor");
845     create_backup_copy = g_settings_get_boolean (editor_settings, XED_SETTINGS_CREATE_BACKUP_COPY);
846     g_object_unref (editor_settings);
847 
848     // FIXME: review this messages
849     if (create_backup_copy)
850     {
851         primary_text = g_strdup_printf (_("Could not create a backup file while saving %s"), uri_for_display);
852     }
853     else
854     {
855         primary_text = g_strdup_printf (_("Could not create a temporary backup file while saving %s"), uri_for_display);
856     }
857 
858     g_free (uri_for_display);
859 
860     primary_markup = g_strdup_printf ("<b>%s</b>", primary_text);
861     g_free (primary_text);
862     primary_label = gtk_label_new (primary_markup);
863     g_free (primary_markup);
864     gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
865     gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
866     gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
867     gtk_widget_set_halign (primary_label, GTK_ALIGN_START);
868     gtk_widget_set_can_focus (primary_label, TRUE);
869     gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
870 
871     secondary_text = _("xed could not back up the old copy of the file before saving the new one. "
872                     "You can ignore this warning and save the file anyway, but if an error "
873                     "occurs while saving, you could lose the old copy of the file. Save anyway?");
874     secondary_markup = g_strdup_printf ("<small>%s</small>", secondary_text);
875     secondary_label = gtk_label_new (secondary_markup);
876     g_free (secondary_markup);
877     gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
878     gtk_widget_set_can_focus (secondary_label, TRUE);
879     gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
880     gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
881     gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
882     gtk_widget_set_halign (secondary_label, GTK_ALIGN_START);
883 
884     gtk_widget_show_all (hbox_content);
885     set_contents (info_bar, hbox_content);
886 
887     return info_bar;
888 }
889 
890 GtkWidget *
xed_unrecoverable_saving_error_info_bar_new(GFile * location,const GError * error)891 xed_unrecoverable_saving_error_info_bar_new (GFile        *location,
892                                              const GError *error)
893 {
894     gchar *error_message = NULL;
895     gchar *message_details = NULL;
896     gchar *full_formatted_uri;
897     gchar *scheme_string;
898     gchar *scheme_markup;
899     gchar *uri_for_display;
900     gchar *temp_uri_for_display;
901     GtkWidget *info_bar;
902 
903     g_return_val_if_fail (G_IS_FILE (location), NULL);
904     g_return_val_if_fail (error != NULL, NULL);
905     g_return_val_if_fail (error->domain == GTK_SOURCE_FILE_SAVER_ERROR || error->domain == G_IO_ERROR, NULL);
906 
907     full_formatted_uri = g_file_get_parse_name (location);
908 
909     /* Truncate the URI so it doesn't get insanely wide. Note that even
910      * though the dialog uses wrapped text, if the URI doesn't contain
911      * white space then the text-wrapping code is too stupid to wrap it.
912      */
913     temp_uri_for_display = xed_utils_str_middle_truncate (full_formatted_uri, MAX_URI_IN_DIALOG_LENGTH);
914     g_free (full_formatted_uri);
915 
916     uri_for_display = g_markup_printf_escaped ("<i>%s</i>", temp_uri_for_display);
917     g_free (temp_uri_for_display);
918 
919     if (is_gio_error (error, G_IO_ERROR_NOT_SUPPORTED))
920     {
921         scheme_string = g_file_get_uri_scheme (location);
922 
923         if ((scheme_string != NULL) && g_utf8_validate (scheme_string, -1, NULL))
924         {
925             scheme_markup = g_markup_printf_escaped ("<i>%s:</i>", scheme_string);
926 
927             /* Translators: %s is a URI scheme (like for example http:, ftp:, etc.) */
928             message_details = g_strdup_printf (_("xed cannot handle %s locations in write mode. "
929                                                "Please check that you typed the "
930                                                "location correctly and try again."),
931                                                scheme_markup);
932             g_free (scheme_markup);
933         }
934         else
935         {
936             message_details = g_strdup (_("xed cannot handle this location in write mode. "
937                                         "Please check that you typed the "
938                                         "location correctly and try again."));
939         }
940 
941         g_free (scheme_string);
942     }
943     else if (is_gio_error (error, G_IO_ERROR_INVALID_FILENAME))
944     {
945         message_details = g_strdup (_("%s is not a valid location. "
946                                     "Please check that you typed the "
947                                     "location correctly and try again."));
948     }
949     else if (is_gio_error (error, G_IO_ERROR_PERMISSION_DENIED))
950     {
951         message_details = g_strdup (_("You do not have the permissions necessary to save the file. "
952                                     "Please check that you typed the "
953                                     "location correctly and try again."));
954     }
955     else if (is_gio_error (error, G_IO_ERROR_NO_SPACE))
956     {
957         message_details = g_strdup (_("There is not enough disk space to save the file. "
958                                     "Please free some disk space and try again."));
959     }
960     else if (is_gio_error (error, G_IO_ERROR_READ_ONLY))
961     {
962         message_details = g_strdup (_("You are trying to save the file on a read-only disk. "
963                                     "Please check that you typed the location "
964                                     "correctly and try again."));
965     }
966     else if (is_gio_error (error, G_IO_ERROR_EXISTS))
967     {
968         message_details = g_strdup (_("A file with the same name already exists. "
969                                     "Please use a different name."));
970     }
971     else if (is_gio_error (error, G_IO_ERROR_FILENAME_TOO_LONG))
972     {
973         message_details = g_strdup (_("The disk where you are trying to save the file has "
974                                     "a limitation on length of the file names. "
975                                     "Please use a shorter name."));
976     }
977 #if 0
978     /* FIXME this error can not occur for a file saving. Either remove the
979      * code here, or improve the GtkSourceFileSaver so this error can occur.
980      */
981     else if (error->domain == XED_DOCUMENT_ERROR && error->code == XED_DOCUMENT_ERROR_TOO_BIG)
982     {
983         message_details = g_strdup (_("The disk where you are trying to save the file has "
984                                     "a limitation on file sizes. Please try saving "
985                                     "a smaller file or saving it to a disk that does not "
986                                     "have this limitation."));
987     }
988 #endif
989     else
990     {
991         parse_error (error, &error_message, &message_details, location, uri_for_display);
992     }
993 
994     if (error_message == NULL)
995     {
996         error_message = g_strdup_printf (_("Could not save the file %s."), uri_for_display);
997     }
998 
999     info_bar = create_io_loading_error_info_bar (error_message, message_details, FALSE);
1000 
1001     g_free (uri_for_display);
1002     g_free (error_message);
1003     g_free (message_details);
1004 
1005     return info_bar;
1006 }
1007 
1008 GtkWidget *
xed_externally_modified_info_bar_new(GFile * location,gboolean document_modified)1009 xed_externally_modified_info_bar_new (GFile    *location,
1010                                       gboolean  document_modified)
1011 {
1012     gchar *full_formatted_uri;
1013     gchar *uri_for_display;
1014     gchar *temp_uri_for_display;
1015     const gchar *primary_text;
1016     const gchar *secondary_text;
1017     GtkWidget *info_bar;
1018 
1019     g_return_val_if_fail (G_IS_FILE (location), NULL);
1020 
1021     full_formatted_uri = g_file_get_parse_name (location);
1022 
1023     /* Truncate the URI so it doesn't get insanely wide. Note that even
1024      * though the dialog uses wrapped text, if the URI doesn't contain
1025      * white space then the text-wrapping code is too stupid to wrap it.
1026      */
1027     temp_uri_for_display = xed_utils_str_middle_truncate (full_formatted_uri, MAX_URI_IN_DIALOG_LENGTH);
1028     g_free (full_formatted_uri);
1029 
1030     uri_for_display = g_markup_printf_escaped ("<i>%s</i>", temp_uri_for_display);
1031     g_free (temp_uri_for_display);
1032 
1033     // FIXME: review this message, it's not clear since for the user the "modification"
1034     // could be interpreted as the changes he made in the document. beside "reading" is
1035     // not accurate (since last load/save)
1036     primary_text = g_strdup_printf (_("The file %s changed on disk."), uri_for_display);
1037     g_free (uri_for_display);
1038 
1039     if (document_modified)
1040     {
1041         secondary_text = _("Do you want to drop your changes and reload the file?");
1042     }
1043     else
1044     {
1045         secondary_text = _("Do you want to reload the file?");
1046     }
1047 
1048     info_bar = gtk_info_bar_new ();
1049 
1050     gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), _("_Reload"), GTK_RESPONSE_OK);
1051     gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), _("_Cancel"), GTK_RESPONSE_CANCEL);
1052     gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_WARNING);
1053 
1054     set_info_bar_text_and_icon (info_bar, "dialog-warning-symbolic", primary_text, secondary_text);
1055 
1056     return info_bar;
1057 }
1058 
1059 GtkWidget *
xed_invalid_character_info_bar_new(GFile * location)1060 xed_invalid_character_info_bar_new (GFile *location)
1061 {
1062     GtkWidget *info_bar;
1063     GtkWidget *hbox_content;
1064     GtkWidget *image;
1065     GtkWidget *vbox;
1066     GtkWidget *primary_label;
1067     GtkWidget *secondary_label;
1068     gchar *primary_markup;
1069     gchar *secondary_markup;
1070     gchar *primary_text;
1071     gchar *full_formatted_uri;
1072     gchar *uri_for_display;
1073     gchar *temp_uri_for_display;
1074     const gchar *secondary_text;
1075 
1076     g_return_val_if_fail (G_IS_FILE (location), NULL);
1077 
1078     full_formatted_uri = g_file_get_parse_name (location);
1079 
1080     /* Truncate the URI so it doesn't get insanely wide. Note that even
1081     * though the dialog uses wrapped text, if the URI doesn't contain
1082     * white space then the text-wrapping code is too stupid to wrap it.
1083     */
1084     temp_uri_for_display = xed_utils_str_middle_truncate (full_formatted_uri, MAX_URI_IN_DIALOG_LENGTH);
1085     g_free (full_formatted_uri);
1086 
1087     uri_for_display = g_markup_printf_escaped ("<i>%s</i>", temp_uri_for_display);
1088     g_free (temp_uri_for_display);
1089 
1090     info_bar = gtk_info_bar_new ();
1091 
1092     gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), _("S_ave Anyway"), GTK_RESPONSE_YES);
1093     gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
1094                             _("D_on't Save"),
1095                             GTK_RESPONSE_CANCEL);
1096     gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_WARNING);
1097 
1098     hbox_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
1099 
1100     image = gtk_image_new_from_icon_name ("dialog-warning-symbolic", GTK_ICON_SIZE_DIALOG);
1101     gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0);
1102     gtk_widget_set_valign (image, GTK_ALIGN_START);
1103 
1104     vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1105     gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
1106 
1107     primary_text = g_strdup_printf (_("Some invalid chars have been detected while saving %s"), uri_for_display);
1108 
1109     g_free (uri_for_display);
1110 
1111     primary_markup = g_strdup_printf ("<b>%s</b>", primary_text);
1112     g_free (primary_text);
1113     primary_label = gtk_label_new (primary_markup);
1114     g_free (primary_markup);
1115     gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
1116     gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
1117     gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
1118     gtk_widget_set_halign (primary_label, GTK_ALIGN_START);
1119     gtk_widget_set_can_focus (primary_label, TRUE);
1120     gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
1121 
1122     secondary_text = _("If you continue saving this file you can corrupt the document. "
1123                       " Save anyway?");
1124     secondary_markup = g_strdup_printf ("<small>%s</small>", secondary_text);
1125     secondary_label = gtk_label_new (secondary_markup);
1126     g_free (secondary_markup);
1127     gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
1128     gtk_widget_set_can_focus (secondary_label, TRUE);
1129     gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
1130     gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
1131     gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
1132     gtk_widget_set_halign (secondary_label, GTK_ALIGN_START);
1133 
1134     gtk_widget_show_all (hbox_content);
1135     set_contents (info_bar, hbox_content);
1136 
1137     return info_bar;
1138 }
1139