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