1 /*
2  * xed-commands-file.c
3  * This file is part of xed
4  *
5  * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
6  * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
7  * Copyright (C) 2002-2005 Paolo Maggi
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 /*
26  * Modified by the xed Team, 1998-2005. See the AUTHORS file for a
27  * list of people on the xed Team.
28  * See the ChangeLog files for a list of changes.
29  *
30  * $Id$
31  */
32 
33 #include <config.h>
34 #include <glib/gi18n.h>
35 #include <gio/gio.h>
36 #include <gtk/gtk.h>
37 
38 #include "xed-debug.h"
39 #include "xed-document.h"
40 #include "xed-document-private.h"
41 #include "xed-commands.h"
42 #include "xed-window.h"
43 #include "xed-window-private.h"
44 #include "xed-statusbar.h"
45 #include "xed-utils.h"
46 #include "xed-file-chooser-dialog.h"
47 #include "xed-close-confirmation-dialog.h"
48 
49 /* Defined constants */
50 #define XED_OPEN_DIALOG_KEY         "xed-open-dialog-key"
51 #define XED_IS_CLOSING_ALL            "xed-is-closing-all"
52 #define XED_IS_QUITTING             "xed-is-quitting"
53 #define XED_IS_QUITTING_ALL     "xed-is-quitting-all"
54 
55 static void tab_state_changed_while_saving (XedTab    *tab,
56                                             GParamSpec  *pspec,
57                                             XedWindow *window);
58 
59 void
_xed_cmd_file_new(GtkAction * action,XedWindow * window)60 _xed_cmd_file_new (GtkAction   *action,
61                    XedWindow *window)
62 {
63     xed_debug (DEBUG_COMMANDS);
64 
65     xed_window_create_tab (window, TRUE);
66 }
67 
68 static XedTab *
get_tab_from_file(GList * docs,GFile * file)69 get_tab_from_file (GList *docs,
70                    GFile *file)
71 {
72     XedTab *tab = NULL;
73 
74     while (docs != NULL)
75     {
76         XedDocument *d;
77         GtkSourceFile *source_file;
78         GFile *l;
79 
80         d = XED_DOCUMENT (docs->data);
81         source_file = xed_document_get_file (d);
82 
83         l = gtk_source_file_get_location (source_file);
84         if (l != NULL && g_file_equal (l, file))
85         {
86             tab = xed_tab_get_from_document (d);
87             break;
88         }
89 
90         docs = g_list_next (docs);
91     }
92 
93     return tab;
94 }
95 
96 static gboolean
is_duplicated_file(GSList * files,GFile * file)97 is_duplicated_file (GSList *files,
98                     GFile *file)
99 {
100     while (files != NULL)
101     {
102         if (g_file_equal (files->data, file))
103         {
104             return TRUE;
105         }
106 
107         files = g_slist_next (files);
108     }
109 
110     return FALSE;
111 }
112 
113 /* File loading */
114 static GSList *
load_file_list(XedWindow * window,const GSList * files,const GtkSourceEncoding * encoding,gint line_pos,gboolean create)115 load_file_list (XedWindow               *window,
116                 const GSList            *files,
117                 const GtkSourceEncoding *encoding,
118                 gint                     line_pos,
119                 gboolean                 create)
120 {
121     XedTab *tab;
122     GSList *loaded_files = NULL; /* Number of files to load */
123     gboolean jump_to = TRUE; /* Whether to jump to the new tab */
124     GList *win_docs;
125     GSList *files_to_load = NULL;
126     const GSList *l;
127     gint num_loaded_files = 0;
128 
129     xed_debug (DEBUG_COMMANDS);
130 
131     win_docs = xed_window_get_documents (window);
132 
133     /* Remove the uris corresponding to documents already open
134      * in "window" and remove duplicates from "uris" list */
135     for (l = files; l != NULL; l = l->next)
136     {
137         if (!is_duplicated_file (files_to_load, l->data))
138         {
139             tab = get_tab_from_file (win_docs, l->data);
140             if (tab != NULL)
141             {
142                 if (l == files)
143                 {
144                     XedDocument *doc;
145 
146                     xed_window_set_active_tab (window, tab);
147                     jump_to = FALSE;
148                     doc = xed_tab_get_document (tab);
149 
150                     if (line_pos > 0)
151                     {
152                         xed_document_goto_line (doc, line_pos - 1);
153                         xed_view_scroll_to_cursor (xed_tab_get_view (tab));
154                     }
155                 }
156 
157                 ++num_loaded_files;
158                 loaded_files = g_slist_prepend (loaded_files, xed_tab_get_document (tab));
159             }
160             else
161             {
162                 files_to_load = g_slist_prepend (files_to_load, l->data);
163             }
164         }
165     }
166 
167     g_list_free (win_docs);
168 
169     if (files_to_load == NULL)
170     {
171         return g_slist_reverse (loaded_files);
172     }
173 
174     files_to_load = g_slist_reverse (files_to_load);
175     l = files_to_load;
176 
177     tab = xed_window_get_active_tab (window);
178     if (tab != NULL)
179     {
180         XedDocument *doc;
181 
182         doc = xed_tab_get_document (tab);
183 
184         if (xed_document_is_untouched (doc) && (xed_tab_get_state (tab) == XED_TAB_STATE_NORMAL))
185         {
186             _xed_tab_load (tab, l->data, encoding, line_pos, create);
187 
188             /* make sure the view has focus */
189             gtk_widget_grab_focus (GTK_WIDGET (xed_tab_get_view (tab)));
190 
191             l = g_slist_next (l);
192             jump_to = FALSE;
193 
194             ++num_loaded_files;
195             loaded_files = g_slist_prepend (loaded_files, xed_tab_get_document (tab));
196         }
197     }
198 
199     while (l != NULL)
200     {
201         g_return_val_if_fail (l->data != NULL, 0);
202 
203         tab = xed_window_create_tab_from_location (window, l->data, encoding, line_pos, create, jump_to);
204 
205         if (tab != NULL)
206         {
207             jump_to = FALSE;
208             ++num_loaded_files;
209             loaded_files = g_slist_prepend (loaded_files, xed_tab_get_document (tab));
210         }
211 
212         l = g_slist_next (l);
213     }
214 
215     loaded_files = g_slist_reverse (loaded_files);
216 
217     if (num_loaded_files == 1)
218     {
219         XedDocument *doc;
220         gchar *uri_for_display;
221 
222         g_return_val_if_fail (tab != NULL, loaded_files);
223 
224         doc = xed_tab_get_document (tab);
225         uri_for_display = xed_document_get_uri_for_display (doc);
226 
227         xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
228                                      window->priv->generic_message_cid,
229                                      _("Loading file '%s'\342\200\246"),
230                                      uri_for_display);
231 
232         g_free (uri_for_display);
233     }
234     else
235     {
236         xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
237                                      window->priv->generic_message_cid,
238                                      ngettext("Loading %d file\342\200\246",
239                                      "Loading %d files\342\200\246",
240                                      num_loaded_files),
241                                      num_loaded_files);
242     }
243 
244     /* Free uris_to_load. Note that l points to the first element of uris_to_load */
245     g_slist_free (files_to_load);
246 
247     return loaded_files;
248 }
249 
250 /**
251  * xed_commands_load_location:
252  * @window: a #XedWindow
253  * @location: a #GFile to be loaded
254  * @encoding: (allow-none): the #GtkSourceEncoding of @location
255  * @line_pos: the line column to place the cursor when @location is loaded
256  *
257  * Loads @location. Ignores non-existing locations
258  */
259 void
xed_commands_load_location(XedWindow * window,GFile * location,const GtkSourceEncoding * encoding,gint line_pos)260 xed_commands_load_location (XedWindow               *window,
261                             GFile                   *location,
262                             const GtkSourceEncoding *encoding,
263                             gint                     line_pos)
264 {
265     GSList *locations = NULL;
266     gchar *uri;
267     GSList *ret;
268 
269     g_return_if_fail (XED_IS_WINDOW (window));
270     g_return_if_fail (G_IS_FILE (location));
271     g_return_if_fail (xed_utils_is_valid_location (location));
272 
273     uri = g_file_get_uri (location);
274     xed_debug_message (DEBUG_COMMANDS, "Loading URI '%s'", uri);
275     g_free (uri);
276 
277     locations = g_slist_prepend (locations, location);
278 
279     ret = load_file_list (window, locations, encoding, line_pos, FALSE);
280     g_slist_free (ret);
281 
282     g_slist_free (locations);
283 }
284 
285 /**
286  * xed_commands_load_locations:
287  * @window: a #XedWindow
288  * @locations: (element-type Gio.File): the locations to load
289  * @encoding: (allow-none): the #GtkSourceEncoding
290  * @line_pos: the line position to place the cursor
291  *
292  * Loads @locataions. Ignore non-existing locations
293  *
294  * Returns: (element-type Xed.Document) (transfer container): the locations
295  * that were loaded.
296  */
297 GSList *
xed_commands_load_locations(XedWindow * window,const GSList * locations,const GtkSourceEncoding * encoding,gint line_pos)298 xed_commands_load_locations (XedWindow               *window,
299                              const GSList            *locations,
300                              const GtkSourceEncoding *encoding,
301                              gint                     line_pos)
302 {
303     g_return_val_if_fail (XED_IS_WINDOW (window), 0);
304     g_return_val_if_fail ((locations != NULL) && (locations->data != NULL), 0);
305 
306     xed_debug (DEBUG_COMMANDS);
307 
308     return load_file_list (window, locations, encoding, line_pos, FALSE);
309 }
310 
311 /*
312  * From the command line we can specify a line position for the
313  * first doc. Beside specifying a not existing uri creates a
314  * titled document.
315  */
316 GSList *
_xed_cmd_load_files_from_prompt(XedWindow * window,GSList * files,const GtkSourceEncoding * encoding,gint line_pos)317 _xed_cmd_load_files_from_prompt (XedWindow               *window,
318                                  GSList                  *files,
319                                  const GtkSourceEncoding *encoding,
320                                  gint                     line_pos)
321 {
322     xed_debug (DEBUG_COMMANDS);
323 
324     return load_file_list (window, files, encoding, line_pos, TRUE);
325 }
326 
327 static void
open_dialog_destroyed(XedWindow * window,XedFileChooserDialog * dialog)328 open_dialog_destroyed (XedWindow            *window,
329                        XedFileChooserDialog *dialog)
330 {
331     xed_debug (DEBUG_COMMANDS);
332 
333     g_object_set_data (G_OBJECT (window), XED_OPEN_DIALOG_KEY, NULL);
334 }
335 
336 static void
open_dialog_response_cb(XedFileChooserDialog * dialog,gint response_id,XedWindow * window)337 open_dialog_response_cb (XedFileChooserDialog *dialog,
338                          gint                  response_id,
339                          XedWindow            *window)
340 {
341     GSList *files;
342     const GtkSourceEncoding *encoding;
343     GSList *loaded;
344 
345     xed_debug (DEBUG_COMMANDS);
346 
347     if (response_id != GTK_RESPONSE_OK)
348     {
349         gtk_widget_destroy (GTK_WIDGET (dialog));
350 
351         return;
352     }
353 
354     files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (dialog));
355     g_return_if_fail (files != NULL);
356 
357     encoding = xed_file_chooser_dialog_get_encoding (dialog);
358 
359     gtk_widget_destroy (GTK_WIDGET (dialog));
360 
361     /* Remember the folder we navigated to */
362      _xed_window_set_default_location (window, files->data);
363 
364     loaded = xed_commands_load_locations (window, files, encoding, 0);
365 
366     g_slist_free (loaded);
367 
368     g_slist_foreach (files, (GFunc) g_object_unref, NULL);
369     g_slist_free (files);
370 }
371 
372 void
_xed_cmd_file_open(GtkAction * action,XedWindow * window)373 _xed_cmd_file_open (GtkAction *action,
374                     XedWindow *window)
375 {
376     GtkWidget *open_dialog;
377     gpointer data;
378     XedDocument *doc;
379     GFile *default_path = NULL;
380 
381     xed_debug (DEBUG_COMMANDS);
382 
383     data = g_object_get_data (G_OBJECT (window), XED_OPEN_DIALOG_KEY);
384 
385     if (data != NULL)
386     {
387         g_return_if_fail (XED_IS_FILE_CHOOSER_DIALOG (data));
388 
389         gtk_window_present (GTK_WINDOW (data));
390 
391         return;
392     }
393 
394     /* Translators: "Open Files" is the title of the file chooser window */
395     open_dialog = xed_file_chooser_dialog_new (_("Open Files"),
396                                                GTK_WINDOW (window),
397                                                GTK_FILE_CHOOSER_ACTION_OPEN,
398                                                NULL,
399                                                _("_Cancel"), GTK_RESPONSE_CANCEL,
400                                                _("_Open"), GTK_RESPONSE_OK,
401                                                NULL);
402 
403     g_object_set_data (G_OBJECT (window), XED_OPEN_DIALOG_KEY, open_dialog);
404 
405     g_object_weak_ref (G_OBJECT (open_dialog), (GWeakNotify) open_dialog_destroyed, window);
406 
407     /* Set the curret folder uri */
408     doc = xed_window_get_active_document (window);
409     if (doc != NULL)
410     {
411         GtkSourceFile *file = xed_document_get_file (doc);
412         GFile *location = gtk_source_file_get_location (file);
413 
414         if (location != NULL)
415         {
416             default_path = g_file_get_parent (location);
417         }
418     }
419 
420     if (default_path == NULL)
421     {
422         default_path = _xed_window_get_default_location (window);
423     }
424 
425     if (default_path != NULL)
426     {
427         gchar *uri;
428 
429         uri = g_file_get_uri (default_path);
430         gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (open_dialog), uri);
431 
432         g_free (uri);
433         g_object_unref (default_path);
434     }
435 
436     g_signal_connect (open_dialog, "response", G_CALLBACK (open_dialog_response_cb), window);
437 
438     gtk_widget_show (open_dialog);
439 }
440 
441 static gboolean
is_read_only(GFile * location)442 is_read_only (GFile *location)
443 {
444     gboolean ret = TRUE; /* default to read only */
445     GFileInfo *info;
446 
447     xed_debug (DEBUG_COMMANDS);
448 
449     info = g_file_query_info (location,
450                               G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
451                               G_FILE_QUERY_INFO_NONE,
452                               NULL,
453                               NULL);
454 
455     if (info != NULL)
456     {
457         if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
458         {
459             ret = !g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
460         }
461 
462         g_object_unref (info);
463     }
464 
465     return ret;
466 }
467 
468 /* FIXME: modify this dialog to be similar to the one provided by gtk+ for
469  * already existing files - Paolo (Oct. 11, 2005) */
470 static gboolean
replace_read_only_file(GtkWindow * parent,GFile * file)471 replace_read_only_file (GtkWindow *parent,
472                         GFile     *file)
473 {
474     GtkWidget *dialog;
475     gint ret;
476     gchar *parse_name;
477     gchar *name_for_display;
478 
479     xed_debug (DEBUG_COMMANDS);
480 
481     parse_name = g_file_get_parse_name (file);
482 
483     /* Truncate the name so it doesn't get insanely wide. Note that even
484      * though the dialog uses wrapped text, if the name doesn't contain
485      * white space then the text-wrapping code is too stupid to wrap it.
486      */
487     name_for_display = xed_utils_str_middle_truncate (parse_name, 50);
488     g_free (parse_name);
489 
490     dialog = gtk_message_dialog_new (parent,
491                                      GTK_DIALOG_DESTROY_WITH_PARENT,
492                                      GTK_MESSAGE_QUESTION,
493                                      GTK_BUTTONS_NONE,
494                                      _("The file \"%s\" is read-only."),
495                                      name_for_display);
496     g_free (name_for_display);
497 
498     gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
499                                               _("Do you want to try to replace it "
500                                               "with the one you are saving?"));
501 
502     gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL);
503     gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Replace"), GTK_RESPONSE_YES);
504 
505     gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
506 
507     gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
508 
509     ret = gtk_dialog_run (GTK_DIALOG (dialog));
510 
511     gtk_widget_destroy (dialog);
512 
513     return (ret == GTK_RESPONSE_YES);
514 }
515 
516 static void
tab_save_as_ready_cb(XedTab * tab,GAsyncResult * result,GTask * task)517 tab_save_as_ready_cb (XedTab     *tab,
518                       GAsyncResult *result,
519                       GTask        *task)
520 {
521     gboolean success = _xed_tab_save_finish (tab, result);
522     g_task_return_boolean (task, success);
523     g_object_unref (task);
524 }
525 
526 static void
save_dialog_response_cb(XedFileChooserDialog * dialog,gint response_id,GTask * task)527 save_dialog_response_cb (XedFileChooserDialog *dialog,
528                          gint                  response_id,
529                          GTask                *task)
530 {
531     XedTab *tab;
532     XedWindow *window;
533     GFile *location;
534     gchar *parse_name;
535     GtkSourceNewlineType newline_type;
536     const GtkSourceEncoding *encoding;
537 
538     xed_debug (DEBUG_COMMANDS);
539 
540     tab = g_task_get_source_object (task);
541     window = g_task_get_task_data (task);
542 
543     if (response_id != GTK_RESPONSE_OK)
544     {
545         gtk_widget_destroy (GTK_WIDGET (dialog));
546 
547         g_task_return_boolean (task, FALSE);
548         g_object_unref (task);
549         return;
550     }
551 
552     location = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
553     g_return_if_fail (location != NULL);
554 
555     encoding = xed_file_chooser_dialog_get_encoding (dialog);
556     newline_type = xed_file_chooser_dialog_get_newline_type (dialog);
557 
558     gtk_widget_destroy (GTK_WIDGET (dialog));
559 
560     parse_name = g_file_get_parse_name (location);
561 
562     xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
563                                  window->priv->generic_message_cid,
564                                  _("Saving file '%s'\342\200\246"),
565                                  parse_name);
566 
567     g_free (parse_name);
568 
569         /* let's remember the dir we navigated too, even if the saving fails... */
570     _xed_window_set_default_location (window, location);
571 
572     _xed_tab_save_as_async (tab,
573                             location,
574                             encoding,
575                             newline_type,
576                             g_task_get_cancellable (task),
577                             (GAsyncReadyCallback) tab_save_as_ready_cb,
578                             task);
579 
580     g_object_unref (location);
581 }
582 
583 static GtkFileChooserConfirmation
confirm_overwrite_callback(GtkFileChooser * dialog,gpointer data)584 confirm_overwrite_callback (GtkFileChooser *dialog,
585                             gpointer        data)
586 {
587     gchar *uri;
588     GFile *file;
589     GtkFileChooserConfirmation res;
590 
591     xed_debug (DEBUG_COMMANDS);
592 
593     uri = gtk_file_chooser_get_uri (dialog);
594     file = g_file_new_for_uri (uri);
595     g_free (uri);
596 
597     if (is_read_only (file))
598     {
599         if (replace_read_only_file (GTK_WINDOW (dialog), file))
600         {
601             res = GTK_FILE_CHOOSER_CONFIRMATION_ACCEPT_FILENAME;
602         }
603         else
604         {
605             res = GTK_FILE_CHOOSER_CONFIRMATION_SELECT_AGAIN;
606         }
607     }
608     else
609     {
610         /* fall back to the default confirmation dialog */
611         res = GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM;
612     }
613 
614     g_object_unref (file);
615 
616     return res;
617 }
618 
619 /* Call save_as_tab_finish() in @callback. */
620 static void
save_as_tab_async(XedTab * tab,XedWindow * window,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)621 save_as_tab_async (XedTab              *tab,
622                    XedWindow           *window,
623                    GCancellable        *cancellable,
624                    GAsyncReadyCallback  callback,
625                    gpointer             user_data)
626 {
627     GTask *task;
628     GtkWidget *save_dialog;
629     GtkWindowGroup *wg;
630     XedDocument *doc;
631     GtkSourceFile *file;
632     GFile *location;
633     const GtkSourceEncoding *encoding;
634     GtkSourceNewlineType newline_type;
635 
636     g_return_if_fail (XED_IS_TAB (tab));
637     g_return_if_fail (XED_IS_WINDOW (window));
638 
639     xed_debug (DEBUG_COMMANDS);
640 
641     task = g_task_new (tab, cancellable, callback, user_data);
642     g_task_set_task_data (task, g_object_ref (window), g_object_unref);
643 
644     save_dialog = xed_file_chooser_dialog_new (_("Save As\342\200\246"),
645                                                GTK_WINDOW (window),
646                                                GTK_FILE_CHOOSER_ACTION_SAVE,
647                                                NULL,
648                                                _("_Cancel"), GTK_RESPONSE_CANCEL,
649                                                _("_Save"), GTK_RESPONSE_OK,
650                                                NULL);
651 
652     gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (save_dialog), TRUE);
653     g_signal_connect (save_dialog, "confirm-overwrite", G_CALLBACK (confirm_overwrite_callback), NULL);
654 
655     wg = xed_window_get_group (window);
656 
657     gtk_window_group_add_window (wg, GTK_WINDOW (save_dialog));
658 
659     /* Save As dialog is modal to its main window */
660     gtk_window_set_modal (GTK_WINDOW (save_dialog), TRUE);
661 
662     /* Set the suggested file name */
663     doc = xed_tab_get_document (tab);
664     file = xed_document_get_file (doc);
665     location = gtk_source_file_get_location (file);
666 
667     if (location != NULL)
668     {
669         gtk_file_chooser_set_file (GTK_FILE_CHOOSER (save_dialog), location, NULL);
670     }
671 
672 
673     else
674     {
675         GFile *default_path;
676         gchar *docname;
677 
678         default_path = _xed_window_get_default_location (window);
679         docname = xed_document_get_short_name_for_display (doc);
680 
681         if (default_path != NULL)
682         {
683             gchar *uri;
684 
685             uri = g_file_get_uri (default_path);
686             gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), uri);
687 
688             g_free (uri);
689             g_object_unref (default_path);
690         }
691 
692         gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog), docname);
693 
694         g_free (docname);
695     }
696 
697     /* Set suggested encoding and newline type */
698     encoding = gtk_source_file_get_encoding (file);
699 
700     if (encoding == NULL)
701     {
702         encoding = gtk_source_encoding_get_utf8 ();
703     }
704 
705     newline_type = gtk_source_file_get_newline_type (file);
706 
707     xed_file_chooser_dialog_set_encoding (XED_FILE_CHOOSER_DIALOG (save_dialog), encoding);
708 
709     xed_file_chooser_dialog_set_newline_type (XED_FILE_CHOOSER_DIALOG (save_dialog), newline_type);
710 
711     g_signal_connect (save_dialog, "response", G_CALLBACK (save_dialog_response_cb), task);
712 
713     gtk_widget_show (save_dialog);
714 }
715 
716 static gboolean
save_as_tab_finish(XedTab * tab,GAsyncResult * result)717 save_as_tab_finish (XedTab       *tab,
718                     GAsyncResult *result)
719 {
720    g_return_val_if_fail (g_task_is_valid (result, tab), FALSE);
721 
722    return g_task_propagate_boolean (G_TASK (result), NULL);
723 }
724 
725 static void
save_as_tab_ready_cb(XedTab * tab,GAsyncResult * result,GTask * task)726 save_as_tab_ready_cb (XedTab       *tab,
727                       GAsyncResult *result,
728                       GTask        *task)
729 {
730     gboolean success = save_as_tab_finish (tab, result);
731 
732     g_task_return_boolean (task, success);
733     g_object_unref (task);
734 }
735 
736 static void
tab_save_ready_cb(XedTab * tab,GAsyncResult * result,GTask * task)737 tab_save_ready_cb (XedTab       *tab,
738                    GAsyncResult *result,
739                    GTask        *task)
740 {
741     gboolean success = _xed_tab_save_finish (tab, result);
742 
743     g_task_return_boolean (task, success);
744     g_object_unref (task);
745 }
746 
747 /**
748  * xed_commands_save_document_async:
749  * @document: the #XedDocument to save.
750  * @window: a #XedWindow.
751  * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
752  * @callback: (scope async): a #GAsyncReadyCallback to call when the operation
753  *   is finished.
754  * @user_data: (closure): the data to pass to the @callback function.
755  *
756  * Asynchronously save the @document. @document must belong to @window. The
757  * source object of the async task is @document (which will be the first
758  * parameter of the #GAsyncReadyCallback).
759  *
760  * When the operation is finished, @callback will be called. You can then call
761  * xed_commands_save_document_finish() to get the result of the operation.
762  */
763 void
xed_commands_save_document_async(XedDocument * document,XedWindow * window,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)764 xed_commands_save_document_async (XedDocument         *document,
765                                   XedWindow           *window,
766                                   GCancellable        *cancellable,
767                                   GAsyncReadyCallback  callback,
768                                   gpointer             user_data)
769 {
770     GTask *task;
771     XedTab *tab;
772     gchar *uri_for_display;
773 
774     xed_debug (DEBUG_COMMANDS);
775 
776     g_return_if_fail (XED_IS_DOCUMENT (document));
777     g_return_if_fail (XED_IS_WINDOW (window));
778     g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
779 
780     task = g_task_new (document, cancellable, callback, user_data);
781 
782     tab = xed_tab_get_from_document (document);
783 
784     if (xed_document_is_untitled (document) ||
785         xed_document_get_readonly (document))
786     {
787         xed_debug_message (DEBUG_COMMANDS, "Untitled or Readonly");
788 
789         save_as_tab_async (tab,
790                            window,
791                            cancellable,
792                            (GAsyncReadyCallback) save_as_tab_ready_cb,
793                            task);
794 
795         return;
796     }
797 
798     uri_for_display = xed_document_get_uri_for_display (document);
799     xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
800                                  window->priv->generic_message_cid,
801                                  _("Saving file '%s'\342\200\246"),
802                                  uri_for_display);
803 
804     g_free (uri_for_display);
805 
806     _xed_tab_save_async (tab,
807                          cancellable,
808                          (GAsyncReadyCallback) tab_save_ready_cb,
809                          task);
810 }
811 
812 /**
813  * xed_commands_save_document_finish:
814  * @document: a #XedDocument.
815  * @result: a #GAsyncResult.
816  *
817  * Finishes an asynchronous document saving operation started with
818  * xed_commands_save_document_async().
819  *
820  * Note that there is no error parameter because the errors are already handled
821  * by xed.
822  *
823  * Returns: %TRUE if the document has been correctly saved, %FALSE otherwise.
824  */
825 gboolean
xed_commands_save_document_finish(XedDocument * document,GAsyncResult * result)826 xed_commands_save_document_finish (XedDocument  *document,
827                                    GAsyncResult *result)
828 {
829     g_return_val_if_fail (g_task_is_valid (result, document), FALSE);
830 
831     return g_task_propagate_boolean (G_TASK (result), NULL);
832 }
833 
834 static void
save_tab_ready_cb(XedDocument * doc,GAsyncResult * result,gpointer user_data)835 save_tab_ready_cb (XedDocument  *doc,
836                    GAsyncResult *result,
837                    gpointer      user_data)
838 {
839     xed_commands_save_document_finish (doc, result);
840 }
841 
842 /* Save tab asynchronously, but without results. */
843 static void
save_tab(XedTab * tab,XedWindow * window)844 save_tab (XedTab    *tab,
845           XedWindow *window)
846 {
847     XedDocument *doc = xed_tab_get_document (tab);
848 
849     xed_commands_save_document_async (doc,
850                                       window,
851                                       NULL,
852                                       (GAsyncReadyCallback) save_tab_ready_cb,
853                                       NULL);
854 }
855 
856 void
_xed_cmd_file_save(GtkAction * action,XedWindow * window)857 _xed_cmd_file_save (GtkAction *action,
858                     XedWindow *window)
859 {
860     XedTab *tab;
861 
862     xed_debug (DEBUG_COMMANDS);
863 
864     tab = xed_window_get_active_tab (window);
865     if (tab != NULL)
866     {
867         save_tab (tab, window);
868     }
869 }
870 
871 static void
_xed_cmd_file_save_as_cb(XedTab * tab,GAsyncResult * result,gpointer user_data)872 _xed_cmd_file_save_as_cb (XedTab     *tab,
873                           GAsyncResult *result,
874                           gpointer      user_data)
875 {
876     save_as_tab_finish (tab, result);
877 }
878 
879 void
_xed_cmd_file_save_as(GtkAction * action,XedWindow * window)880 _xed_cmd_file_save_as (GtkAction *action,
881                        XedWindow *window)
882 {
883     XedTab *tab;
884 
885     xed_debug (DEBUG_COMMANDS);
886 
887     tab = xed_window_get_active_tab (window);
888     if (tab != NULL)
889     {
890         save_as_tab_async (tab,
891                            window,
892                            NULL,
893                            (GAsyncReadyCallback) _xed_cmd_file_save_as_cb,
894                            NULL);
895     }
896 }
897 
898 static void
quit_if_needed(XedWindow * window)899 quit_if_needed (XedWindow *window)
900 {
901     gboolean is_quitting;
902     gboolean is_quitting_all;
903 
904     is_quitting = GPOINTER_TO_BOOLEAN (g_object_get_data (G_OBJECT (window), XED_IS_QUITTING));
905 
906     is_quitting_all = GPOINTER_TO_BOOLEAN (g_object_get_data (G_OBJECT (window), XED_IS_QUITTING_ALL));
907 
908     if (is_quitting)
909     {
910        gtk_widget_destroy (GTK_WIDGET (window));
911     }
912 
913     if (is_quitting_all)
914     {
915         GtkApplication *app;
916 
917         app = GTK_APPLICATION (g_application_get_default ());
918 
919         if (gtk_application_get_windows (app) == NULL)
920         {
921             g_application_quit (G_APPLICATION (app));
922         }
923     }
924 }
925 
926 static gboolean
really_close_tab(XedTab * tab)927 really_close_tab (XedTab *tab)
928 {
929     GtkWidget *toplevel;
930     XedWindow *window;
931 
932     xed_debug (DEBUG_COMMANDS);
933 
934     g_return_val_if_fail (xed_tab_get_state (tab) == XED_TAB_STATE_CLOSING, FALSE);
935 
936     toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tab));
937     g_return_val_if_fail (XED_IS_WINDOW (toplevel), FALSE);
938 
939     window = XED_WINDOW (toplevel);
940 
941     xed_window_close_tab (window, tab);
942 
943     if (xed_window_get_active_tab (window) == NULL)
944     {
945         quit_if_needed (window);
946     }
947 
948     return FALSE;
949 }
950 
951 static void
close_tab(XedTab * tab)952 close_tab (XedTab *tab)
953 {
954     XedDocument *doc;
955 
956     doc = xed_tab_get_document (tab);
957     g_return_if_fail (doc != NULL);
958 
959     /* If the user has modified again the document, do not close the tab. */
960     if (_xed_document_needs_saving (doc))
961     {
962         return;
963     }
964 
965     /* Close the document only if it has been succesfully saved.
966      * Tab state is set to CLOSING (it is a state without exiting
967      * transitions) and the tab is closed in an idle handler.
968      */
969     _xed_tab_mark_for_closing (tab);
970 
971     g_idle_add_full (G_PRIORITY_HIGH_IDLE,
972                      (GSourceFunc) really_close_tab,
973                      tab,
974                      NULL);
975 }
976 
977 typedef struct _SaveAsData SaveAsData;
978 
979 struct _SaveAsData
980 {
981     /* Reffed */
982     XedWindow *window;
983 
984     /* List of reffed GeditTab's */
985     GSList *tabs_to_save_as;
986 
987     guint close_tabs : 1;
988 };
989 
990 static void save_as_documents_list (SaveAsData *data);
991 
992 static void
save_as_documents_list_cb(XedTab * tab,GAsyncResult * result,SaveAsData * data)993 save_as_documents_list_cb (XedTab       *tab,
994                            GAsyncResult *result,
995                            SaveAsData   *data)
996 {
997     gboolean saved = save_as_tab_finish (tab, result);
998 
999     if (saved && data->close_tabs)
1000     {
1001         close_tab (tab);
1002     }
1003 
1004     g_return_if_fail (tab == XED_TAB (data->tabs_to_save_as->data));
1005     g_object_unref (data->tabs_to_save_as->data);
1006     data->tabs_to_save_as = g_slist_delete_link (data->tabs_to_save_as, data->tabs_to_save_as);
1007 
1008     if (data->tabs_to_save_as != NULL)
1009     {
1010         save_as_documents_list (data);
1011     }
1012     else
1013     {
1014        g_object_unref (data->window);
1015        g_slice_free (SaveAsData, data);
1016     }
1017 }
1018 
1019 static void
save_as_documents_list(SaveAsData * data)1020 save_as_documents_list (SaveAsData *data)
1021 {
1022     XedTab *next_tab = XED_TAB (data->tabs_to_save_as->data);
1023 
1024     xed_window_set_active_tab (data->window, next_tab);
1025 
1026     save_as_tab_async (next_tab,
1027                        data->window,
1028                        NULL,
1029                        (GAsyncReadyCallback) save_as_documents_list_cb,
1030                        data);
1031 }
1032 
1033 /*
1034  * The docs in the list must belong to the same XedWindow.
1035  */
1036 static void
save_documents_list(XedWindow * window,GList * docs)1037 save_documents_list (XedWindow *window,
1038                      GList     *docs)
1039 {
1040     SaveAsData *data = NULL;
1041     GList *l;
1042 
1043     xed_debug (DEBUG_COMMANDS);
1044 
1045     g_return_if_fail (!(xed_window_get_state (window) & (XED_WINDOW_STATE_PRINTING | XED_WINDOW_STATE_SAVING_SESSION)));
1046 
1047     l = docs;
1048     while (l != NULL)
1049     {
1050         XedDocument *doc;
1051         XedTab *t;
1052         XedTabState state;
1053 
1054         g_return_if_fail (XED_IS_DOCUMENT (l->data));
1055 
1056         doc = XED_DOCUMENT (l->data);
1057         t = xed_tab_get_from_document (doc);
1058         state = xed_tab_get_state (t);
1059 
1060         g_return_if_fail (state != XED_TAB_STATE_PRINTING);
1061         g_return_if_fail (state != XED_TAB_STATE_PRINT_PREVIEWING);
1062         g_return_if_fail (state != XED_TAB_STATE_CLOSING);
1063 
1064         if ((state == XED_TAB_STATE_NORMAL) ||
1065             (state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW) ||
1066             (state == XED_TAB_STATE_GENERIC_NOT_EDITABLE))
1067         {
1068             /* FIXME: manage the case of local readonly files owned by the
1069                user is running xed - Paolo (Dec. 8, 2005) */
1070             if (xed_document_is_untitled (doc) || xed_document_get_readonly (doc))
1071             {
1072                 if (_xed_document_needs_saving (doc))
1073                 {
1074                     if (data == NULL)
1075                     {
1076                         data = g_slice_new (SaveAsData);
1077                         data->window = g_object_ref (window);
1078                         data->tabs_to_save_as = NULL;
1079                         data->close_tabs = FALSE;
1080                     }
1081 
1082                     data->tabs_to_save_as = g_slist_prepend (data->tabs_to_save_as, g_object_ref (t));
1083                 }
1084             }
1085             else
1086             {
1087                 save_tab (t, window);
1088             }
1089         }
1090         else
1091         {
1092             /* If the state is:
1093                - XED_TAB_STATE_LOADING: we do not save since we are sure the file is unmodified
1094                - XED_TAB_STATE_REVERTING: we do not save since the user wants
1095                  to return back to the version of the file she previously saved
1096                - XED_TAB_STATE_SAVING: well, we are already saving (no need to save again)
1097                - XED_TAB_STATE_PRINTING, XED_TAB_STATE_PRINT_PREVIEWING: there is not a
1098                  real reason for not saving in this case, we do not save to avoid to run
1099                  two operations using the message area at the same time (may be we can remove
1100                  this limitation in the future). Note that SaveAll, ClosAll
1101                  and Quit are unsensitive if the window state is PRINTING.
1102                - XED_TAB_STATE_GENERIC_ERROR: we do not save since the document contains
1103                  errors (I don't think this is a very frequent case, we should probably remove
1104                  this state)
1105                - XED_TAB_STATE_LOADING_ERROR: there is nothing to save
1106                - XED_TAB_STATE_REVERTING_ERROR: there is nothing to save and saving the current
1107                  document will overwrite the copy of the file the user wants to go back to
1108                - XED_TAB_STATE_SAVING_ERROR: we do not save since we just failed to save, so there is
1109                  no reason to automatically retry... we wait for user intervention
1110                - XED_TAB_STATE_CLOSING: this state is invalid in this case
1111             */
1112 
1113             gchar *uri_for_display;
1114 
1115             uri_for_display = xed_document_get_uri_for_display (doc);
1116             xed_debug_message (DEBUG_COMMANDS,
1117                                "File '%s' not saved. State: %d",
1118                                uri_for_display,
1119                                state);
1120             g_free (uri_for_display);
1121         }
1122 
1123         l = g_list_next (l);
1124     }
1125 
1126     if (data != NULL)
1127     {
1128         data->tabs_to_save_as = g_slist_reverse (data->tabs_to_save_as);
1129         save_as_documents_list (data);
1130     }
1131 }
1132 
1133 /**
1134  * xed_commands_save_all_documents:
1135  * @window: a #XedWindow.
1136  *
1137  * Asynchronously save all documents belonging to @window. The result of the
1138  * operation is not available, so it's difficult to know whether all the
1139  * documents are correctly saved.
1140  */
1141 void
xed_commands_save_all_documents(XedWindow * window)1142 xed_commands_save_all_documents (XedWindow *window)
1143 {
1144     GList *docs;
1145 
1146     g_return_if_fail (XED_IS_WINDOW (window));
1147 
1148     xed_debug (DEBUG_COMMANDS);
1149 
1150     docs = xed_window_get_documents (window);
1151 
1152     save_documents_list (window, docs);
1153 
1154     g_list_free (docs);
1155 }
1156 
1157 void
_xed_cmd_file_save_all(GtkAction * action,XedWindow * window)1158 _xed_cmd_file_save_all (GtkAction *action,
1159                         XedWindow *window)
1160 {
1161     xed_commands_save_all_documents (window);
1162 }
1163 
1164 /**
1165  * xed_commands_save_document:
1166  * @window: a #XedWindow.
1167  * @document: the #XedDocument to save.
1168  *
1169  * Asynchronously save @document. @document must belong to @window. If you need
1170  * the result of the operation, use xed_commands_save_document_async().
1171  */
1172 void
xed_commands_save_document(XedWindow * window,XedDocument * document)1173 xed_commands_save_document (XedWindow   *window,
1174                             XedDocument *document)
1175 {
1176     XedTab *tab;
1177 
1178     g_return_if_fail (XED_IS_WINDOW (window));
1179     g_return_if_fail (XED_IS_DOCUMENT (document));
1180 
1181     xed_debug (DEBUG_COMMANDS);
1182 
1183     tab = xed_tab_get_from_document (document);
1184     save_tab (tab, window);
1185 }
1186 
1187 /* File revert */
1188 static void
do_revert(XedWindow * window,XedTab * tab)1189 do_revert (XedWindow *window,
1190            XedTab    *tab)
1191 {
1192     XedDocument *doc;
1193     gchar *docname;
1194 
1195     xed_debug (DEBUG_COMMANDS);
1196 
1197     doc = xed_tab_get_document (tab);
1198     docname = xed_document_get_short_name_for_display (doc);
1199 
1200     xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
1201                                  window->priv->generic_message_cid,
1202                                  _("Reverting the document '%s'\342\200\246"),
1203                                  docname);
1204 
1205     g_free (docname);
1206 
1207     _xed_tab_revert (tab);
1208 }
1209 
1210 static void
revert_dialog_response_cb(GtkDialog * dialog,gint response_id,XedWindow * window)1211 revert_dialog_response_cb (GtkDialog *dialog,
1212                            gint       response_id,
1213                            XedWindow *window)
1214 {
1215     XedTab *tab;
1216 
1217     xed_debug (DEBUG_COMMANDS);
1218 
1219     /* FIXME: we are relying on the fact that the dialog is
1220        modal so the active tab can't be changed...
1221        not very nice - Paolo (Oct 11, 2005) */
1222     tab = xed_window_get_active_tab (window);
1223     if (tab == NULL)
1224     {
1225         return;
1226     }
1227 
1228     gtk_widget_destroy (GTK_WIDGET (dialog));
1229 
1230     if (response_id == GTK_RESPONSE_OK)
1231     {
1232         do_revert (window, tab);
1233     }
1234 }
1235 
1236 static GtkWidget *
revert_dialog(XedWindow * window,XedDocument * doc)1237 revert_dialog (XedWindow   *window,
1238                XedDocument *doc)
1239 {
1240     GtkWidget *dialog;
1241     gchar *docname;
1242     gchar *primary_msg;
1243     gchar *secondary_msg;
1244     glong seconds;
1245 
1246     xed_debug (DEBUG_COMMANDS);
1247 
1248     docname = xed_document_get_short_name_for_display (doc);
1249     primary_msg = g_strdup_printf (_("Revert unsaved changes to document '%s'?"), docname);
1250     g_free (docname);
1251 
1252     seconds = MAX (1, _xed_document_get_seconds_since_last_save_or_load (doc));
1253 
1254     if (seconds < 55)
1255     {
1256         secondary_msg = g_strdup_printf (ngettext ("Changes made to the document in the last %ld second "
1257                                                    "will be permanently lost.",
1258                                                    "Changes made to the document in the last %ld seconds "
1259                                                    "will be permanently lost.",
1260                                                    seconds),
1261                                                    seconds);
1262     }
1263     else if (seconds < 75) /* 55 <= seconds < 75 */
1264     {
1265         secondary_msg = g_strdup (_("Changes made to the document in the last minute "
1266                                   "will be permanently lost."));
1267     }
1268     else if (seconds < 110) /* 75 <= seconds < 110 */
1269     {
1270         secondary_msg = g_strdup_printf (ngettext ("Changes made to the document in the last minute and "
1271                                                    "%ld second will be permanently lost.",
1272                                                    "Changes made to the document in the last minute and "
1273                                                    "%ld seconds will be permanently lost.",
1274                                                    seconds - 60 ),
1275                                                    seconds - 60);
1276     }
1277     else if (seconds < 3600)
1278     {
1279         secondary_msg = g_strdup_printf (ngettext ("Changes made to the document in the last %ld minute "
1280                                                    "will be permanently lost.",
1281                                                    "Changes made to the document in the last %ld minutes "
1282                                                    "will be permanently lost.",
1283                                                    seconds / 60),
1284                                                    seconds / 60);
1285     }
1286     else if (seconds < 7200)
1287     {
1288         gint minutes;
1289         seconds -= 3600;
1290 
1291         minutes = seconds / 60;
1292         if (minutes < 5)
1293         {
1294             secondary_msg = g_strdup (_("Changes made to the document in the last hour "
1295                                       "will be permanently lost."));
1296         }
1297         else
1298         {
1299             secondary_msg = g_strdup_printf (ngettext ("Changes made to the document in the last hour and "
1300                                                        "%d minute will be permanently lost.",
1301                                                        "Changes made to the document in the last hour and "
1302                                                        "%d minutes will be permanently lost.",
1303                                                        minutes),
1304                                                        minutes);
1305         }
1306     }
1307     else
1308     {
1309         gint hours;
1310 
1311         hours = seconds / 3600;
1312 
1313         secondary_msg = g_strdup_printf (ngettext ("Changes made to the document in the last %d hour "
1314                                                    "will be permanently lost.",
1315                                                    "Changes made to the document in the last %d hours "
1316                                                    "will be permanently lost.",
1317                                                    hours),
1318                                                    hours);
1319     }
1320 
1321     dialog = gtk_message_dialog_new (GTK_WINDOW (window),
1322                                      GTK_DIALOG_DESTROY_WITH_PARENT,
1323                                      GTK_MESSAGE_QUESTION,
1324                                      GTK_BUTTONS_NONE,
1325                                      "%s", primary_msg);
1326 
1327     gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", secondary_msg);
1328     g_free (primary_msg);
1329     g_free (secondary_msg);
1330 
1331     gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
1332 
1333     gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL);
1334     gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Revert"), GTK_RESPONSE_OK);
1335     gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
1336 
1337     return dialog;
1338 }
1339 
1340 void
_xed_cmd_file_revert(GtkAction * action,XedWindow * window)1341 _xed_cmd_file_revert (GtkAction   *action,
1342                       XedWindow *window)
1343 {
1344     XedTab *tab;
1345     XedDocument *doc;
1346     GtkWidget *dialog;
1347     GtkWindowGroup *wg;
1348 
1349     xed_debug (DEBUG_COMMANDS);
1350 
1351     tab = xed_window_get_active_tab (window);
1352     g_return_if_fail (tab != NULL);
1353 
1354     /* If we are already displaying a notification
1355      * reverting will drop local modifications, do
1356      * not bug the user further */
1357     if (xed_tab_get_state (tab) == XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION || _xed_tab_get_can_close (tab))
1358     {
1359         do_revert (window, tab);
1360         return;
1361     }
1362 
1363     doc = xed_tab_get_document (tab);
1364     g_return_if_fail (doc != NULL);
1365     g_return_if_fail (!xed_document_is_untitled (doc));
1366 
1367     dialog = revert_dialog (window, doc);
1368 
1369     wg = xed_window_get_group (window);
1370 
1371     gtk_window_group_add_window (wg, GTK_WINDOW (dialog));
1372 
1373     gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
1374 
1375     g_signal_connect (dialog, "response", G_CALLBACK (revert_dialog_response_cb), window);
1376 
1377     gtk_widget_show (dialog);
1378 }
1379 
1380 static void
tab_state_changed_while_saving(XedTab * tab,GParamSpec * pspec,XedWindow * window)1381 tab_state_changed_while_saving (XedTab     *tab,
1382                                 GParamSpec *pspec,
1383                                 XedWindow  *window)
1384 {
1385     XedTabState ts;
1386 
1387     ts = xed_tab_get_state (tab);
1388 
1389     xed_debug_message (DEBUG_COMMANDS, "State while saving: %d\n", ts);
1390 
1391     /* When the state become NORMAL, it means the saving operation is
1392        finished */
1393     if (ts == XED_TAB_STATE_NORMAL)
1394     {
1395         g_signal_handlers_disconnect_by_func (tab, G_CALLBACK (tab_state_changed_while_saving), window);
1396 
1397         close_tab (tab);
1398     }
1399 }
1400 
1401 static void
save_and_close(XedTab * tab,XedWindow * window)1402 save_and_close (XedTab    *tab,
1403                 XedWindow *window)
1404 {
1405     xed_debug (DEBUG_COMMANDS);
1406 
1407     /* Trace tab state changes */
1408     g_signal_connect (tab, "notify::state", G_CALLBACK (tab_state_changed_while_saving), window);
1409 
1410     save_tab (tab, window);
1411 }
1412 
1413 static void
save_and_close_all_documents(const GList * docs,XedWindow * window)1414 save_and_close_all_documents (const GList *docs,
1415                               XedWindow   *window)
1416 {
1417     GList  *tabs;
1418     GList  *l;
1419     GSList *sl;
1420     SaveAsData *data = NULL;
1421     GSList *tabs_to_save_and_close = NULL;
1422     GList  *tabs_to_close = NULL;
1423 
1424     xed_debug (DEBUG_COMMANDS);
1425 
1426     g_return_if_fail (!(xed_window_get_state (window) & XED_WINDOW_STATE_PRINTING));
1427 
1428     tabs = gtk_container_get_children (GTK_CONTAINER (_xed_window_get_notebook (window)));
1429 
1430     l = tabs;
1431     while (l != NULL)
1432     {
1433         XedTab *t = XED_TAB (l->data);;
1434         XedTabState state;
1435         XedDocument *doc;
1436 
1437         state = xed_tab_get_state (t);
1438         doc = xed_tab_get_document (t);
1439 
1440         /* If the state is: ([*] invalid states)
1441            - XED_TAB_STATE_NORMAL: close (and if needed save)
1442            - XED_TAB_STATE_LOADING: close, we are sure the file is unmodified
1443            - XED_TAB_STATE_REVERTING: since the user wants
1444              to return back to the version of the file she previously saved, we can close
1445              without saving (CHECK: are we sure this is the right behavior, suppose the case
1446              the original file has been deleted)
1447            - [*] XED_TAB_STATE_SAVING: invalid, ClosAll
1448              and Quit are unsensitive if the window state is SAVING.
1449            - [*] XED_TAB_STATE_PRINTING, XED_TAB_STATE_PRINT_PREVIEWING: there is not a
1450              real reason for not closing in this case, we do not save to avoid to run
1451              two operations using the message area at the same time (may be we can remove
1452              this limitation in the future). Note that ClosAll
1453              and Quit are unsensitive if the window state is PRINTING.
1454            - XED_TAB_STATE_SHOWING_PRINT_PREVIEW: close (and if needed save)
1455            - XED_TAB_STATE_LOADING_ERROR: close without saving (if the state is LOADING_ERROR then the
1456              document is not modified)
1457            - XED_TAB_STATE_REVERTING_ERROR: we do not close since the document contains errors
1458            - XED_TAB_STATE_SAVING_ERROR: we do not close since the document contains errors
1459            - XED_TAB_STATE_GENERIC_ERROR: we do not close since the document contains
1460              errors (CHECK: we should problably remove this state)
1461            - [*] XED_TAB_STATE_CLOSING: this state is invalid in this case
1462         */
1463 
1464         g_return_if_fail (state != XED_TAB_STATE_PRINTING);
1465         g_return_if_fail (state != XED_TAB_STATE_PRINT_PREVIEWING);
1466         g_return_if_fail (state != XED_TAB_STATE_CLOSING);
1467         g_return_if_fail (state != XED_TAB_STATE_SAVING);
1468 
1469         if ((state != XED_TAB_STATE_SAVING_ERROR) &&
1470             (state != XED_TAB_STATE_GENERIC_ERROR) &&
1471             (state != XED_TAB_STATE_REVERTING_ERROR))
1472         {
1473             if ((g_list_index ((GList *)docs, doc) >= 0) &&
1474                 (state != XED_TAB_STATE_LOADING) &&
1475                 (state != XED_TAB_STATE_LOADING_ERROR) &&
1476                 (state != XED_TAB_STATE_REVERTING)) /* CHECK: is this the right behavior with REVERTING ?*/
1477             {
1478                 /* The document must be saved before closing */
1479                 g_return_if_fail (_xed_document_needs_saving (doc));
1480 
1481                 /* FIXME: manage the case of local readonly files owned by the
1482                    user is running xed - Paolo (Dec. 8, 2005) */
1483                 if (xed_document_is_untitled (doc) || xed_document_get_readonly (doc))
1484                 {
1485                     if (data == NULL)
1486                     {
1487                         data = g_slice_new (SaveAsData);
1488                         data->window = g_object_ref (window);
1489                         data->tabs_to_save_as = NULL;
1490                         data->close_tabs = TRUE;
1491                     }
1492 
1493                     data->tabs_to_save_as = g_slist_prepend (data->tabs_to_save_as, g_object_ref (t));
1494                 }
1495                 else
1496                 {
1497                     tabs_to_save_and_close = g_slist_prepend (tabs_to_save_and_close, t);
1498                 }
1499             }
1500             else
1501             {
1502                 /* The document must be closed without saving */
1503                 tabs_to_close = g_list_prepend (tabs_to_close, t);
1504             }
1505         }
1506 
1507         l = g_list_next (l);
1508     }
1509 
1510     g_list_free (tabs);
1511 
1512     /* Close all tabs to close (in a sync way) */
1513     xed_window_close_tabs (window, tabs_to_close);
1514     g_list_free (tabs_to_close);
1515 
1516     /* Save and close all the files in tabs_to_save_and_close */
1517     sl = tabs_to_save_and_close;
1518     while (sl != NULL)
1519     {
1520         save_and_close (XED_TAB (sl->data), window);
1521         sl = g_slist_next (sl);
1522     }
1523     g_slist_free (tabs_to_save_and_close);
1524 
1525     /* Save As and close all the files in data->tabs_to_save_as. */
1526     if (data != NULL)
1527     {
1528         data->tabs_to_save_as = g_slist_reverse (data->tabs_to_save_as);
1529         save_as_documents_list (data);
1530     }
1531 }
1532 
1533 static void
save_and_close_document(const GList * docs,XedWindow * window)1534 save_and_close_document (const GList *docs,
1535                          XedWindow   *window)
1536 {
1537     XedTab *tab;
1538 
1539     xed_debug (DEBUG_COMMANDS);
1540 
1541     g_return_if_fail (docs->next == NULL);
1542 
1543     tab = xed_tab_get_from_document (XED_DOCUMENT (docs->data));
1544     g_return_if_fail (tab != NULL);
1545 
1546     save_and_close (tab, window);
1547 }
1548 
1549 static void
close_all_tabs(XedWindow * window)1550 close_all_tabs (XedWindow *window)
1551 {
1552     gboolean is_quitting;
1553 
1554     xed_debug (DEBUG_COMMANDS);
1555 
1556     /* There is no document to save -> close all tabs */
1557     xed_window_close_all_tabs (window);
1558 
1559     is_quitting = GPOINTER_TO_BOOLEAN (g_object_get_data (G_OBJECT (window), XED_IS_QUITTING));
1560 
1561     if (is_quitting)
1562     {
1563         gtk_widget_destroy (GTK_WIDGET (window));
1564     }
1565 
1566     return;
1567 }
1568 
1569 static void
close_document(XedWindow * window,XedDocument * doc)1570 close_document (XedWindow   *window,
1571                 XedDocument *doc)
1572 {
1573     XedTab *tab;
1574 
1575     xed_debug (DEBUG_COMMANDS);
1576 
1577     tab = xed_tab_get_from_document (doc);
1578     g_return_if_fail (tab != NULL);
1579 
1580     xed_window_close_tab (window, tab);
1581 }
1582 
1583 static void
close_confirmation_dialog_response_handler(XedCloseConfirmationDialog * dlg,gint response_id,XedWindow * window)1584 close_confirmation_dialog_response_handler (XedCloseConfirmationDialog *dlg,
1585                                             gint                        response_id,
1586                                             XedWindow                  *window)
1587 {
1588     GList *selected_documents;
1589     gboolean is_closing_all;
1590 
1591     xed_debug (DEBUG_COMMANDS);
1592 
1593     is_closing_all = GPOINTER_TO_BOOLEAN (g_object_get_data (G_OBJECT (window), XED_IS_CLOSING_ALL));
1594 
1595     gtk_widget_hide (GTK_WIDGET (dlg));
1596 
1597     switch (response_id)
1598     {
1599         case GTK_RESPONSE_YES: /* Save and Close */
1600             selected_documents = xed_close_confirmation_dialog_get_selected_documents (dlg);
1601             if (selected_documents == NULL)
1602             {
1603                 if (is_closing_all)
1604                 {
1605                     /* There is no document to save -> close all tabs */
1606                     /* We call gtk_widget_destroy before close_all_tabs
1607                      * because close_all_tabs could destroy the xed window */
1608                     gtk_widget_destroy (GTK_WIDGET (dlg));
1609 
1610                     close_all_tabs (window);
1611 
1612                     return;
1613                 }
1614                 else
1615                     g_return_if_reached ();
1616             }
1617             else
1618             {
1619                 if (is_closing_all)
1620                 {
1621                     save_and_close_all_documents (selected_documents, window);
1622                 }
1623                 else
1624                 {
1625                     save_and_close_document (selected_documents, window);
1626                 }
1627             }
1628 
1629             g_list_free (selected_documents);
1630 
1631             break;
1632 
1633         case GTK_RESPONSE_NO: /* Close without Saving */
1634             if (is_closing_all)
1635             {
1636                 /* We call gtk_widget_destroy before close_all_tabs
1637                  * because close_all_tabs could destroy the xed window */
1638                 gtk_widget_destroy (GTK_WIDGET (dlg));
1639 
1640                 close_all_tabs (window);
1641 
1642                 return;
1643             }
1644             else
1645             {
1646                 const GList *unsaved_documents;
1647 
1648                 unsaved_documents = xed_close_confirmation_dialog_get_unsaved_documents (dlg);
1649                 g_return_if_fail (unsaved_documents->next == NULL);
1650 
1651                 close_document (window, XED_DOCUMENT (unsaved_documents->data));
1652             }
1653 
1654             break;
1655         default: /* Do not close */
1656 
1657             /* Reset is_quitting flag */
1658             g_object_set_data (G_OBJECT (window), XED_IS_QUITTING, GBOOLEAN_TO_POINTER (FALSE));
1659 
1660             break;
1661     }
1662 
1663     gtk_widget_destroy (GTK_WIDGET (dlg));
1664 }
1665 
1666 /* Returns TRUE if the tab can be immediately closed */
1667 static gboolean
tab_can_close(XedTab * tab,GtkWindow * window)1668 tab_can_close (XedTab  *tab,
1669                GtkWindow *window)
1670 {
1671     XedDocument *doc;
1672 
1673     xed_debug (DEBUG_COMMANDS);
1674 
1675     doc = xed_tab_get_document (tab);
1676 
1677     if (!_xed_tab_get_can_close (tab))
1678     {
1679         GtkWidget *dlg;
1680 
1681         xed_window_set_active_tab (XED_WINDOW (window), tab);
1682 
1683         dlg = xed_close_confirmation_dialog_new_single (window, doc, FALSE);
1684 
1685         g_signal_connect (dlg, "response",
1686                           G_CALLBACK (close_confirmation_dialog_response_handler), window);
1687 
1688         gtk_widget_show (dlg);
1689 
1690         return FALSE;
1691     }
1692 
1693     return TRUE;
1694 }
1695 
1696 /* CHECK: we probably need this one public for plugins...
1697  * maybe even a _list variant. Or maybe it's better make
1698  * xed_window_close_tab always run the confirm dialog?
1699  * we should not allow closing a tab without resetting the
1700  * XED_IS_CLOSING_ALL flag!
1701  */
1702 void
_xed_cmd_file_close_tab(XedTab * tab,XedWindow * window)1703 _xed_cmd_file_close_tab (XedTab    *tab,
1704                          XedWindow *window)
1705 {
1706     xed_debug (DEBUG_COMMANDS);
1707 
1708     g_return_if_fail (GTK_WIDGET (window) == gtk_widget_get_toplevel (GTK_WIDGET (tab)));
1709 
1710     g_object_set_data (G_OBJECT (window), XED_IS_CLOSING_ALL, GBOOLEAN_TO_POINTER (FALSE));
1711     g_object_set_data (G_OBJECT (window), XED_IS_QUITTING, GBOOLEAN_TO_POINTER (FALSE));
1712     g_object_set_data (G_OBJECT (window), XED_IS_QUITTING_ALL, GINT_TO_POINTER (FALSE));
1713 
1714 
1715     if (tab_can_close (tab, GTK_WINDOW (window)))
1716     {
1717         xed_window_close_tab (window, tab);
1718     }
1719 }
1720 
1721 void
_xed_cmd_file_close(GtkAction * action,XedWindow * window)1722 _xed_cmd_file_close (GtkAction   *action,
1723                      XedWindow *window)
1724 {
1725     XedTab *active_tab;
1726 
1727     xed_debug (DEBUG_COMMANDS);
1728 
1729     active_tab = xed_window_get_active_tab (window);
1730 
1731     if (active_tab == NULL)
1732     {
1733         return;
1734     }
1735 
1736     _xed_cmd_file_close_tab (active_tab, window);
1737 }
1738 
1739 /* Close all tabs */
1740 static void
file_close_all(XedWindow * window,gboolean is_quitting)1741 file_close_all (XedWindow *window,
1742                 gboolean   is_quitting)
1743 {
1744     GList     *unsaved_docs;
1745     GtkWidget *dlg;
1746 
1747     xed_debug (DEBUG_COMMANDS);
1748 
1749     g_return_if_fail (!(xed_window_get_state (window) &
1750                         (XED_WINDOW_STATE_SAVING |
1751                          XED_WINDOW_STATE_PRINTING |
1752                          XED_WINDOW_STATE_SAVING_SESSION)));
1753 
1754     g_object_set_data (G_OBJECT (window), XED_IS_CLOSING_ALL, GBOOLEAN_TO_POINTER (TRUE));
1755     g_object_set_data (G_OBJECT (window), XED_IS_QUITTING, GBOOLEAN_TO_POINTER (is_quitting));
1756 
1757     unsaved_docs = xed_window_get_unsaved_documents (window);
1758 
1759     if (unsaved_docs == NULL)
1760     {
1761         /* There is no document to save -> close all tabs */
1762         xed_window_close_all_tabs (window);
1763 
1764         if (is_quitting)
1765         {
1766             gtk_widget_destroy (GTK_WIDGET (window));
1767         }
1768 
1769         return;
1770     }
1771 
1772     if (unsaved_docs->next == NULL)
1773     {
1774         /* There is only one unsaved document */
1775         XedTab      *tab;
1776         XedDocument *doc;
1777 
1778         doc = XED_DOCUMENT (unsaved_docs->data);
1779 
1780         tab = xed_tab_get_from_document (doc);
1781         g_return_if_fail (tab != NULL);
1782 
1783         xed_window_set_active_tab (window, tab);
1784 
1785         dlg = xed_close_confirmation_dialog_new_single (GTK_WINDOW (window), doc, FALSE);
1786     }
1787     else
1788     {
1789         dlg = xed_close_confirmation_dialog_new (GTK_WINDOW (window), unsaved_docs, FALSE);
1790     }
1791 
1792     g_list_free (unsaved_docs);
1793 
1794     g_signal_connect (dlg, "response",
1795                       G_CALLBACK (close_confirmation_dialog_response_handler), window);
1796 
1797     gtk_widget_show (dlg);
1798 }
1799 
1800 void
_xed_cmd_file_close_all(GtkAction * action,XedWindow * window)1801 _xed_cmd_file_close_all (GtkAction   *action,
1802                          XedWindow *window)
1803 {
1804     xed_debug (DEBUG_COMMANDS);
1805 
1806     g_return_if_fail (!(xed_window_get_state (window) &
1807                         (XED_WINDOW_STATE_SAVING |
1808                         XED_WINDOW_STATE_PRINTING |
1809                         XED_WINDOW_STATE_SAVING_SESSION)));
1810 
1811     file_close_all (window, FALSE);
1812 }
1813 
1814 void
_xed_cmd_file_quit(GtkAction * action,XedWindow * window)1815 _xed_cmd_file_quit (GtkAction *action,
1816                     XedWindow *window)
1817 {
1818     xed_debug (DEBUG_COMMANDS);
1819 
1820     g_return_if_fail (!(xed_window_get_state (window) &
1821                         (XED_WINDOW_STATE_SAVING |
1822                          XED_WINDOW_STATE_PRINTING |
1823                          XED_WINDOW_STATE_SAVING_SESSION)));
1824 
1825     file_close_all (window, TRUE);
1826 }
1827