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