1 /*
2 * Copyright (C) 2007 Ignacio Casal Quinteiro <nacho.resa@gmail.com>
3 * Fatih Demir <kabalak@kabalak.net>
4 * Ross Golder <ross@golder.org>
5 * Gediminas Paulauskas <menesis@kabalak.net>
6 * Pablo Sanxiao <psanxiao@gmail.com>
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29 #include <gio/gio.h>
30 #include <string.h>
31 #include <gio/gio.h>
32
33 #include "gtr-profile-manager.h"
34 #include "gtr-close-confirmation-dialog.h"
35 #include "gtr-actions.h"
36 #include "gtr-application.h"
37 #include "gtr-dirs.h"
38 #include "gtr-file-dialogs.h"
39 #include "gtr-notebook.h"
40 #include "gtr-po.h"
41 #include "gtr-tab.h"
42 #include "gtr-utils.h"
43 #include "gtr-window.h"
44
45 #define GTR_TAB_SAVE_AS "gtr-tab-save-as"
46 #define GTR_IS_CLOSING_ALL "gtr-is-closing-all"
47
48 #define API_URL "https://l10n.gnome.org/api/v1/"
49
50 static void load_file_list (GtrWindow * window, const GSList * uris);
51 static GList * get_modified_documents (GtrWindow * window);
52
53 /*
54 * The main file opening function. Checks that the file isn't already open,
55 * and if not, opens it in a new tab.
56 */
57 gboolean
gtr_open(GFile * location,GtrWindow * window,GError ** error)58 gtr_open (GFile * location, GtrWindow * window, GError ** error)
59 {
60 GtrPo *po;
61 GtrTab *tab;
62 GList *current;
63 GtrView *active_view;
64 GtrHeader *header;
65 GtrNotebook *active_notebook;
66 gchar *dl_team;
67 gchar *dl_module;
68 gchar *dl_branch;
69 gchar *dl_domain;
70 gchar *dl_module_state;
71
72 /*
73 * If the filename can't be opened, pass the error back to the caller
74 * to handle.
75 */
76
77 po = gtr_po_new ();
78 if (!gtr_po_parse (po, location, error)) {
79 gtr_window_show_projects (window);
80 // TODO: show error message
81 return FALSE;
82 }
83
84 if ((*error != NULL)
85 && (((GError *) * error)->code != GTR_PO_ERROR_RECOVERY)) {
86 gtr_window_show_projects (window);
87 return FALSE;
88 }
89
90 header = gtr_po_get_header (po);
91 dl_team = gtr_header_get_dl_team (header);
92 dl_module = gtr_header_get_dl_module (header);
93 dl_branch = gtr_header_get_dl_branch (header);
94 dl_domain = gtr_header_get_dl_domain (header);
95 dl_module_state = gtr_header_get_dl_state (header);
96
97 /*
98 * Set Damned Lies info when a po file is opened locally
99 */
100 gtr_po_set_dl_info(po,
101 dl_team,
102 dl_module,
103 dl_branch,
104 dl_domain,
105 dl_module_state);
106
107 /*
108 * Create a page to add to our list of open files
109 */
110 tab = gtr_window_create_tab (window, po);
111 gtr_window_set_active_tab (window, GTK_WIDGET (tab));
112
113 /*
114 * Activate the upload file icon if the po file is in the appropriate
115 * state as on the vertimus workflow
116 */
117 active_notebook = gtr_window_get_notebook (window);
118 gtr_notebook_enable_upload (active_notebook, gtr_po_can_dl_upload (po));
119
120 /*
121 * Show the current message.
122 */
123 current = gtr_po_get_current_message (po);
124 gtr_tab_message_go_to (tab, current->data, FALSE, GTR_TAB_MOVE_NONE);
125
126 /*
127 * Grab the focus
128 */
129 active_view = gtr_tab_get_active_view (tab);
130 gtk_widget_grab_focus (GTK_WIDGET (active_view));
131
132 gtr_window_show_poeditor (window);
133
134 return TRUE;
135 }
136
137 static void
gtr_po_parse_files_from_dialog(GtkWidget * dialog,GtrWindow * window)138 gtr_po_parse_files_from_dialog (GtkWidget * dialog, GtrWindow * window)
139 {
140 GSList *po_files, *l;
141 GSList *locations = NULL;
142 GFile *file, *parent;
143 gchar *uri;
144
145 po_files = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
146 for (l = po_files; l != NULL; l = g_slist_next (l))
147 {
148 GFile *file;
149
150 file = g_file_new_for_uri (l->data);
151 locations = g_slist_prepend (locations, file);
152 }
153
154 /*
155 * We store latest directory
156 */
157 file = g_file_new_for_uri (po_files->data);
158 g_slist_free_full (po_files, g_free);
159
160 parent = g_file_get_parent (file);
161 g_object_unref (file);
162
163 uri = g_file_get_uri (parent);
164 g_object_unref (parent);
165 _gtr_application_set_last_dir (GTR_APP, uri);
166
167 g_free (uri);
168
169 /*
170 * Open the file via our centralized opening function.
171 */
172 load_file_list (window, (const GSList *) locations);
173 g_slist_free_full (locations, g_object_unref);
174
175 /*
176 * Destroy the dialog
177 */
178 gtk_widget_destroy (dialog);
179 }
180
181
182 static void
gtr_file_chooser_analyse(gpointer dialog,FileselMode mode,GtrWindow * window)183 gtr_file_chooser_analyse (gpointer dialog,
184 FileselMode mode, GtrWindow * window)
185 {
186 gint reply;
187
188 reply = gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog));
189 if (reply == GTK_RESPONSE_ACCEPT && mode == FILESEL_OPEN)
190 gtr_po_parse_files_from_dialog (GTK_WIDGET (dialog), window);
191
192 g_object_unref (dialog);
193 }
194
195 gboolean
gtr_want_to_save_current_dialog(GtrWindow * window)196 gtr_want_to_save_current_dialog (GtrWindow * window)
197 {
198 gint res = 0;
199 GtrTab *tab;
200 GtrPo *po;
201
202 GtkWidget *dialog;
203 g_autoptr (GFile) location = NULL;
204 g_autofree gchar *filename = NULL;
205 g_autofree gchar *markup = NULL;
206
207 tab = gtr_window_get_active_tab (window);
208 po = gtr_tab_get_po (tab);
209 location = gtr_po_get_location (po);
210 filename = g_file_get_path (location);
211
212 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
213 GTK_DIALOG_DESTROY_WITH_PARENT,
214 GTK_MESSAGE_WARNING,
215 GTK_BUTTONS_NONE, NULL);
216
217 markup = g_strdup_printf (
218 _("Do you want to save changes to this file: "
219 "<span weight=\"bold\" size=\"large\">%s</span>?"),
220 filename);
221
222 gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), markup);
223 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
224 _("If you don't save, all your unsaved changes will be permanently lost."));
225
226 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
227 _("Save and open"), GTK_RESPONSE_YES,
228 _("Cancel"), GTK_RESPONSE_CANCEL,
229 _("Continue without saving"), GTK_RESPONSE_NO,
230 NULL);
231
232 res = gtk_dialog_run (GTK_DIALOG (dialog));
233 gtk_widget_destroy (dialog);
234
235 if (res == GTK_RESPONSE_CANCEL)
236 return FALSE;
237
238 if (res == GTK_RESPONSE_YES)
239 gtr_save_current_file_dialog (NULL, window);
240
241 return TRUE;
242 }
243
244 /*
245 * The "Open file" dialog.
246 */
247 void
gtr_open_file_dialog(GtkAction * action,GtrWindow * window)248 gtr_open_file_dialog (GtkAction * action, GtrWindow * window)
249 {
250 GtkWidget *dialog = NULL;
251 g_autoptr (GList) list = NULL;
252 list = get_modified_documents (window);
253 if (list != NULL)
254 {
255 if (!gtr_want_to_save_current_dialog (window))
256 return;
257 }
258
259 dialog = gtr_file_chooser_new (GTK_WINDOW (window),
260 FILESEL_OPEN,
261 _("Open file for translation"),
262 _gtr_application_get_last_dir (GTR_APP));
263
264 gtr_file_chooser_analyse ((gpointer) dialog, FILESEL_OPEN, window);
265 }
266
267 static void
save_dialog_response_cb(GtkDialog * dialog,gint response_id,GtrWindow * window)268 save_dialog_response_cb (GtkDialog * dialog,
269 gint response_id, GtrWindow * window)
270 {
271 GError *error = NULL;
272 GtrPo *po;
273 GtrTab *tab;
274 gchar *filename;
275 GFile *location;
276
277 tab = GTR_TAB (g_object_get_data (G_OBJECT (dialog), GTR_TAB_SAVE_AS));
278
279 g_return_if_fail (GTK_IS_FILE_CHOOSER (dialog));
280
281 po = gtr_tab_get_po (tab);
282
283 if (response_id != GTK_RESPONSE_ACCEPT)
284 {
285 g_object_unref (dialog);
286 return;
287 }
288
289 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
290 g_return_if_fail (filename != NULL);
291
292 location = g_file_new_for_path (filename);
293 g_free (filename);
294
295 g_object_unref (dialog);
296
297 if (po != NULL)
298 {
299 gtr_po_set_location (po, location);
300
301 g_object_unref (location);
302
303 gtr_po_save_file (po, &error);
304
305 if (error)
306 {
307 GtkWidget *dialog;
308 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
309 GTK_DIALOG_DESTROY_WITH_PARENT,
310 GTK_MESSAGE_WARNING,
311 GTK_BUTTONS_OK,
312 "%s", error->message);
313 gtk_dialog_run (GTK_DIALOG (dialog));
314 gtk_widget_destroy (dialog);
315 g_clear_error (&error);
316 return;
317 }
318
319 /* We have to change the state of the tab */
320 gtr_po_set_state (po, GTR_PO_STATE_SAVED);
321 }
322 g_object_unref (location);
323 }
324
325 static GtkFileChooserConfirmation
confirm_overwrite_callback(GtkFileChooser * dialog,gpointer data)326 confirm_overwrite_callback (GtkFileChooser * dialog, gpointer data)
327 {
328 gchar *uri;
329 GtkFileChooserConfirmation res;
330
331 uri = gtk_file_chooser_get_uri (dialog);
332
333 /*
334 * FIXME: We have to detect if the file is read-only
335 */
336
337 /* fall back to the default confirmation dialog */
338 res = GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM;
339
340 g_free (uri);
341
342 return res;
343 }
344
345 /*
346 * "Upload file" dialog
347 *
348 */
349 void
gtr_upload_file_dialog(GtkAction * action,GtrWindow * window)350 gtr_upload_file_dialog (GtkAction * action, GtrWindow * window)
351 {
352 GtrTab *tab;
353 GtrPo *po;
354 GtkWidget *dialog, *success_dialog;
355 GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL;
356 GMappedFile *mapped;
357 GError *error = NULL;
358 GtrProfileManager *pmanager = NULL;
359 GtrNotebook *active_notebook;
360 GtrProfile *profile;
361 GtrHeader *header;
362 g_autoptr (SoupMessage) msg = NULL;
363 g_autoptr (SoupMultipart) mpart = NULL;
364 g_autoptr (SoupBuffer) buffer = NULL;
365 g_autoptr (SoupSession) session = NULL;
366 const gchar *content = NULL;
367 g_autofree gchar *mime_type = NULL;
368 g_autofree gchar *filename = NULL;
369 g_autofree gchar *upload_endpoint = NULL;
370 const char *auth_token = NULL;
371 g_autofree char *auth = NULL;
372 gsize size;
373 const gchar *selected_team;
374 const gchar *selected_module;
375 const gchar *selected_branch;
376 const gchar *selected_domain;
377
378 /* Get file content */
379 tab = gtr_window_get_active_tab (window);
380 po = gtr_tab_get_po (tab);
381 filename = g_file_get_path (gtr_po_get_location (po));
382 mapped = g_mapped_file_new (filename, FALSE, &error);
383 if (error != NULL) {
384 g_warning ("Error opening file %s: %s", filename, (error)->message);
385 }
386 content = g_mapped_file_get_contents (mapped);
387 size = g_mapped_file_get_length (mapped);
388 active_notebook = gtr_window_get_notebook (window);
389 header = gtr_po_get_header (po);
390
391 /* Check mimetype */
392 mime_type = g_strdup (g_content_type_get_mime_type(content));
393
394 /* Get the authentication token from the user profile */
395 pmanager = gtr_profile_manager_get_default ();
396 profile = gtr_profile_manager_get_active_profile (pmanager);
397 auth_token = gtr_profile_get_auth_token (profile);
398 auth = g_strconcat ("Bearer ", auth_token, NULL);
399
400 selected_module = gtr_po_get_dl_module (po);
401 if (selected_module == NULL)
402 selected_module = gtr_header_get_dl_module (header);
403
404 selected_branch = gtr_po_get_dl_branch (po);
405 if (selected_branch == NULL)
406 selected_branch = gtr_header_get_dl_branch (header);
407
408 selected_domain = gtr_po_get_dl_domain (po);
409 if (selected_domain == NULL)
410 selected_domain = gtr_header_get_dl_domain (header);
411
412 selected_team = gtr_po_get_dl_team (po);
413 if (selected_team == NULL)
414 selected_team = gtr_header_get_dl_team (header);
415
416 /* API endpoint: modules/[module]/branches/[branch]/domains/[domain]/languages/[team]/upload */
417 upload_endpoint = g_strconcat((const gchar *)API_URL,
418 "modules/", selected_module,
419 "/branches/", selected_branch,
420 "/domains/", selected_domain,
421 "/languages/", selected_team,
422 "/upload", NULL);
423
424 /* Init multipart container */
425 mpart = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART);
426 buffer = soup_buffer_new (SOUP_MEMORY_COPY, content, size);
427 soup_multipart_append_form_string (mpart, "file", "txt");
428 soup_multipart_append_form_file (mpart, "file", filename,
429 mime_type, buffer);
430
431 /* Get the associated message */
432 msg = soup_form_request_new_from_multipart (upload_endpoint, mpart);
433 soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
434
435 /* Append the authentication header*/
436 soup_message_headers_append (msg->request_headers, "Authentication", auth);
437
438 session = soup_session_new ();
439 soup_session_send_message (session, msg);
440
441 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
442 {
443 if (msg->status_code == 403)
444 {
445 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
446 flags,
447 GTK_MESSAGE_INFO,
448 GTK_BUTTONS_OK,
449 _("This file has already been uploaded"));
450 gtk_dialog_run (GTK_DIALOG (dialog));
451 gtk_widget_destroy (dialog);
452 gtr_notebook_enable_upload (active_notebook, FALSE);
453 return;
454 }
455
456 dialog = gtk_message_dialog_new_with_markup (
457 GTK_WINDOW (window),
458 flags,
459 GTK_MESSAGE_WARNING,
460 GTK_BUTTONS_CLOSE,
461 _(
462 "An error occurred while uploading the file: %s\n"
463 "Maybe you've not configured your <i>l10n.gnome.org</i> "
464 "<b>token</b> correctly in your profile or you don't have "
465 "permissions to upload this module."
466 ),
467 soup_status_get_phrase (msg->status_code));
468 gtk_dialog_run (GTK_DIALOG (dialog));
469 gtk_widget_destroy (dialog);
470 return;
471 }
472
473 success_dialog = gtk_message_dialog_new (GTK_WINDOW (window),
474 flags,
475 GTK_MESSAGE_INFO,
476 GTK_BUTTONS_OK,
477 _("The file '%s.%s.%s.%s' has been uploaded!"),
478 selected_module,
479 selected_branch,
480 selected_team,
481 selected_domain);
482
483 gtk_dialog_run (GTK_DIALOG (success_dialog));
484 gtk_widget_destroy (success_dialog);
485 gtr_notebook_enable_upload (active_notebook, FALSE);
486 }
487
488 /*
489 * "Save as" dialog.
490 */
491 void
gtr_save_file_as_dialog(GtkAction * action,GtrWindow * window)492 gtr_save_file_as_dialog (GtkAction * action, GtrWindow * window)
493 {
494 GtkWidget *dialog = NULL;
495 GtrTab *current_page;
496 gint reply = 0;
497
498 if (dialog != NULL)
499 {
500 gtk_window_present (GTK_WINDOW (dialog));
501 return;
502 }
503
504 current_page = gtr_window_get_active_tab (window);
505 dialog = gtr_file_chooser_new (GTK_WINDOW (window),
506 FILESEL_SAVE,
507 _("Save file as…"),
508 g_get_home_dir ());
509
510 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
511 TRUE);
512 g_signal_connect (dialog,
513 "confirm-overwrite",
514 G_CALLBACK (confirm_overwrite_callback), NULL);
515
516 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
517 g_object_set_data (G_OBJECT (dialog), GTR_TAB_SAVE_AS, current_page);
518
519 reply = gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog));
520 save_dialog_response_cb (GTK_DIALOG (dialog), reply, window);
521 }
522
523 /*
524 * A callback for Save
525 */
526 void
gtr_save_current_file_dialog(GtkWidget * widget,GtrWindow * window)527 gtr_save_current_file_dialog (GtkWidget * widget, GtrWindow * window)
528 {
529 GError *error = NULL;
530 GtrTab *current;
531 GtrPo *po;
532
533 current = gtr_window_get_active_tab (window);
534 po = gtr_tab_get_po (current);
535
536 gtr_po_save_file (po, &error);
537
538 if (error)
539 {
540 GtkWidget *dialog;
541 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
542 GTK_DIALOG_DESTROY_WITH_PARENT,
543 GTK_MESSAGE_WARNING,
544 GTK_BUTTONS_OK, "%s", error->message);
545 gtk_dialog_run (GTK_DIALOG (dialog));
546 gtk_widget_destroy (dialog);
547 g_clear_error (&error);
548 return;
549 }
550
551 /* We have to change the state of the tab */
552 gtr_po_set_state (po, GTR_PO_STATE_SAVED);
553 }
554
555 static gboolean
is_duplicated_location(const GSList * locations,GFile * u)556 is_duplicated_location (const GSList * locations, GFile * u)
557 {
558 GSList *l;
559
560 for (l = (GSList *) locations; l != NULL; l = g_slist_next (l))
561 {
562 if (g_file_equal (u, l->data))
563 return TRUE;
564 }
565
566 return FALSE;
567 }
568
569 static void
load_file_list(GtrWindow * window,const GSList * locations)570 load_file_list (GtrWindow * window, const GSList * locations)
571 {
572 GSList *locations_to_load = NULL;
573 const GSList *l;
574 GError *error = NULL;
575 GtkWidget *tab;
576
577 g_return_if_fail ((locations != NULL) && (locations->data != NULL));
578
579 // removing other tabs, for now on, we'll using single tab and multiples windows
580 gtr_window_remove_all_pages (window);
581
582 /* Remove the uris corresponding to documents already open
583 * in "window" and remove duplicates from "uris" list */
584 l = locations;
585 while (locations != NULL)
586 {
587 if (!is_duplicated_location (locations_to_load, locations->data))
588 {
589 /*We need to now if is already loaded in any tab */
590 tab = gtr_window_get_tab_from_location (window,
591 (GFile *) locations->data);
592
593 if (tab != NULL)
594 {
595 if (locations == l)
596 gtr_window_set_active_tab (window, tab);
597 }
598 else
599 locations_to_load = g_slist_prepend (locations_to_load,
600 locations->data);
601
602 }
603
604 locations = g_slist_next (locations);
605 }
606
607 if (locations_to_load == NULL)
608 return;
609
610 locations_to_load = g_slist_reverse (locations_to_load);
611 l = locations_to_load;
612
613 while (locations_to_load != NULL)
614 {
615 g_return_if_fail (locations_to_load->data != NULL);
616
617 if (!gtr_open (locations_to_load->data, window, &error))
618 break;
619
620 locations_to_load = g_slist_next (locations_to_load);
621 }
622
623 /*
624 * Now if there are any error we have to manage it
625 * and free the path
626 */
627 if (error != NULL)
628 {
629 GtkWidget *dialog;
630 /*
631 * We have to show the error in a dialog
632 */
633 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
634 GTK_DIALOG_DESTROY_WITH_PARENT,
635 GTK_MESSAGE_ERROR,
636 GTK_BUTTONS_CLOSE,
637 "%s", error->message);
638 gtk_dialog_run (GTK_DIALOG (dialog));
639 gtk_widget_destroy (dialog);
640 g_error_free (error);
641 }
642
643 /* Free uris_to_load. Note that l points to the first element of uris_to_load */
644 g_slist_free ((GSList *) l);
645 }
646
647
648 /**
649 * gtr_actions_load_uris:
650 *
651 * Ignore non-existing URIs
652 */
653 void
gtr_actions_load_locations(GtrWindow * window,const GSList * locations)654 gtr_actions_load_locations (GtrWindow * window, const GSList * locations)
655 {
656 g_return_if_fail (GTR_IS_WINDOW (window));
657 g_return_if_fail ((locations != NULL) && (locations->data != NULL));
658
659 load_file_list (window, locations);
660 }
661
662 static void
save_and_close_document(GtrPo * po,GtrWindow * window)663 save_and_close_document (GtrPo * po, GtrWindow * window)
664 {
665 GtrTab *tab;
666
667 gtr_save_current_file_dialog (NULL, window);
668
669 tab = gtr_tab_get_from_document (po);
670
671 _gtr_window_close_tab (window, tab);
672 }
673
674 static void
close_all_tabs(GtrWindow * window)675 close_all_tabs (GtrWindow * window)
676 {
677 GtrNotebook *nb;
678
679 nb = gtr_window_get_notebook (window);
680 gtr_notebook_remove_all_pages (nb);
681
682 //FIXME: This has to change once we add the close all documents menuitem
683 gtk_widget_destroy (GTK_WIDGET (window));
684 }
685
686 static void
save_and_close_all_documents(GList * unsaved_documents,GtrWindow * window)687 save_and_close_all_documents (GList * unsaved_documents, GtrWindow * window)
688 {
689 GtrTab *tab;
690 GList *l;
691 GError *error = NULL;
692
693 for (l = unsaved_documents; l != NULL; l = g_list_next (l))
694 {
695 gtr_po_save_file (l->data, &error);
696
697 if (error)
698 {
699 GtkWidget *dialog;
700 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
701 GTK_DIALOG_DESTROY_WITH_PARENT,
702 GTK_MESSAGE_WARNING,
703 GTK_BUTTONS_OK,
704 "%s", error->message);
705 gtk_dialog_run (GTK_DIALOG (dialog));
706 gtk_widget_destroy (dialog);
707 g_clear_error (&error);
708
709 return;
710 }
711
712 tab = gtr_tab_get_from_document (l->data);
713
714 _gtr_window_close_tab (window, tab);
715 }
716
717 gtk_widget_destroy (GTK_WIDGET (window));
718 }
719
720 static void
close_confirmation_dialog_response_handler(GtrCloseConfirmationDialog * dlg,gint response_id,GtrWindow * window)721 close_confirmation_dialog_response_handler (GtrCloseConfirmationDialog
722 * dlg, gint response_id,
723 GtrWindow * window)
724 {
725 GList *selected_documents;
726 gboolean is_closing_all;
727
728 gtk_widget_hide (GTK_WIDGET (dlg));
729
730 is_closing_all = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window),
731 GTR_IS_CLOSING_ALL));
732
733 switch (response_id)
734 {
735 case GTK_RESPONSE_YES: /* Save and Close */
736 selected_documents =
737 gtr_close_confirmation_dialog_get_selected_documents (dlg);
738 if (selected_documents == NULL)
739 {
740 if (is_closing_all)
741 {
742 gtk_widget_destroy (GTK_WIDGET (dlg));
743
744 close_all_tabs (window);
745
746 return;
747 }
748 else
749 g_return_if_reached ();
750 }
751 else
752 {
753 if (is_closing_all)
754 {
755 save_and_close_all_documents (selected_documents, window);
756 }
757 else
758 {
759 save_and_close_document (selected_documents->data, window);
760 }
761 }
762
763 g_list_free (selected_documents);
764
765 break;
766
767 case GTK_RESPONSE_NO: /* Close without Saving */
768 if (is_closing_all)
769 {
770 gtk_widget_destroy (GTK_WIDGET (dlg));
771
772 close_all_tabs (window);
773
774 return;
775 }
776 else
777 {
778 const GList *unsaved_documents;
779
780 unsaved_documents =
781 gtr_close_confirmation_dialog_get_unsaved_documents (dlg);
782 g_return_if_fail (unsaved_documents->next == NULL);
783
784 _gtr_window_close_tab (window,
785 gtr_tab_get_from_document
786 (unsaved_documents->data));
787 }
788
789 break;
790 default: /* Do not close */
791 break;
792 }
793
794 gtk_widget_destroy (GTK_WIDGET (dlg));
795 }
796
797 void
gtr_close_tab(GtrTab * tab,GtrWindow * window)798 gtr_close_tab (GtrTab * tab, GtrWindow * window)
799 {
800 g_object_set_data (G_OBJECT (window),
801 GTR_IS_CLOSING_ALL, GINT_TO_POINTER (0));
802
803 if (!_gtr_tab_can_close (tab))
804 {
805 GtkWidget *dlg;
806
807 dlg =
808 gtr_close_confirmation_dialog_new_single (GTK_WINDOW (window),
809 gtr_tab_get_po
810 (tab), FALSE);
811
812 g_signal_connect (dlg,
813 "response",
814 G_CALLBACK
815 (close_confirmation_dialog_response_handler), window);
816
817 gtk_widget_show (dlg);
818 }
819 else
820 _gtr_window_close_tab (window, tab);
821 }
822
823 void
gtr_file_close(GtkAction * widget,GtrWindow * window)824 gtr_file_close (GtkAction * widget, GtrWindow * window)
825 {
826 GtrTab *tab;
827
828 tab = gtr_window_get_active_tab (window);
829
830 gtr_close_tab (tab, window);
831 }
832
833 static GList *
get_modified_documents(GtrWindow * window)834 get_modified_documents (GtrWindow * window)
835 {
836 GtrNotebook *nb;
837 GtrTab *tab;
838 GtrPo *po;
839 gint pages;
840 GList *list = NULL;
841
842 nb = gtr_window_get_notebook (window);
843 pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb));
844
845 while (pages > 0)
846 {
847 tab = GTR_TAB (gtk_notebook_get_nth_page (GTK_NOTEBOOK (nb),
848 pages - 1));
849
850 po = gtr_tab_get_po (tab);
851 if (gtr_po_get_state (po) == GTR_PO_STATE_MODIFIED)
852 list = g_list_prepend (list, po);
853
854 pages--;
855 }
856
857 return list;
858 }
859
860 static void
close_all_documents(GtrWindow * window,gboolean logout_mode)861 close_all_documents (GtrWindow * window, gboolean logout_mode)
862 {
863 GList *list;
864
865 list = get_modified_documents (window);
866
867 if (list != NULL)
868 {
869 GtkWidget *dlg;
870
871 dlg = gtr_close_confirmation_dialog_new (GTK_WINDOW (window),
872 list, logout_mode);
873
874 g_signal_connect (dlg,
875 "response",
876 G_CALLBACK
877 (close_confirmation_dialog_response_handler), window);
878
879 g_list_free (list);
880
881 gtk_widget_show (dlg);
882 }
883 else
884 {
885 close_all_tabs (window);
886
887 if (logout_mode)
888 {
889 gtk_widget_destroy (GTK_WIDGET (window));
890 }
891 }
892 }
893
894 void
gtr_file_quit(GtkAction * action,GtrWindow * window)895 gtr_file_quit (GtkAction * action, GtrWindow * window)
896 {
897 g_object_set_data (G_OBJECT (window),
898 GTR_IS_CLOSING_ALL, GINT_TO_POINTER (1));
899
900 close_all_documents (window, TRUE);
901 }
902
903 void
_gtr_actions_file_close_all(GtkAction * action,GtrWindow * window)904 _gtr_actions_file_close_all (GtkAction * action, GtrWindow * window)
905 {
906 close_all_documents (window, FALSE);
907 }
908
909 void
_gtr_actions_file_save_all(GtkAction * action,GtrWindow * window)910 _gtr_actions_file_save_all (GtkAction * action, GtrWindow * window)
911 {
912 GList *list, *l;
913
914 list = get_modified_documents (window);
915
916 for (l = list; l != NULL; l = g_list_next (l))
917 {
918 GError *error = NULL;
919
920 gtr_po_save_file (GTR_PO (l->data), &error);
921
922 if (error)
923 {
924 GtkWidget *dialog;
925
926 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
927 GTK_DIALOG_DESTROY_WITH_PARENT,
928 GTK_MESSAGE_WARNING,
929 GTK_BUTTONS_OK,
930 "%s", error->message);
931 gtk_dialog_run (GTK_DIALOG (dialog));
932 gtk_widget_destroy (dialog);
933 g_clear_error (&error);
934
935 return;
936 }
937
938 /* We have to change the state of the tab */
939 gtr_po_set_state (GTR_PO (l->data), GTR_PO_STATE_SAVED);
940 }
941
942 g_list_free (list);
943 }
944