1 /*
2  * xed-tab.c
3  * This file is part of xed
4  *
5  * Copyright (C) 2005 - Paolo Maggi
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 /*
24  * Modified by the xed Team, 2005. See the AUTHORS file for a
25  * list of people on the xed Team.
26  * See the ChangeLog files for a list of changes.
27  */
28 
29 #include <config.h>
30 #include <stdlib.h>
31 #include <glib/gi18n.h>
32 #include <gio/gio.h>
33 
34 #include "xed-app.h"
35 #include "xed-notebook.h"
36 #include "xed-tab.h"
37 #include "xed-utils.h"
38 #include "xed-io-error-info-bar.h"
39 #include "xed-print-job.h"
40 #include "xed-print-preview.h"
41 #include "xed-progress-info-bar.h"
42 #include "xed-debug.h"
43 #include "xed-document.h"
44 #include "xed-document-private.h"
45 #include "xed-enum-types.h"
46 #include "xed-settings.h"
47 #include "xed-view-frame.h"
48 
49 #define XED_TAB_KEY "XED_TAB_KEY"
50 
51 struct _XedTabPrivate
52 {
53     GSettings *editor;
54 
55     XedTabState state;
56 
57     XedViewFrame *frame;
58 
59     GtkWidget *info_bar;
60     GtkWidget *print_preview;
61 
62     XedPrintJob *print_job;
63 
64     GTask *task_saver;
65     GtkSourceFileSaverFlags save_flags;
66 
67     /* tmp data for loading */
68     GtkSourceFileLoader *loader;
69     GCancellable *cancellable;
70     gint tmp_line_pos;
71     guint idle_scroll;
72 
73     GTimer *timer;
74     guint times_called;
75 
76     guint auto_save_interval;
77     guint auto_save_timeout;
78 
79     gint editable : 1;
80     gint auto_save : 1;
81 
82     gint ask_if_externally_modified : 1;
83 
84     /*tmp data for loading */
85     guint user_requested_encoding : 1;
86 };
87 
88 typedef struct _SaverData SaverData;
89 
90 struct _SaverData
91 {
92     GtkSourceFileSaver *saver;
93 
94     /* Notes about the create_backup saver flag:
95      * - At the beginning of a new file saving, force_no_backup is FALSE.
96      *   The create_backup flag is set to the saver if it is enabled in
97      *   GSettings and if it isn't an auto-save.
98      * - If creating the backup gives an error, and if the user wants to
99      *   save the file without the backup, force_no_backup is set to TRUE
100      *   and the create_backup flag is removed from the saver.
101      *   force_no_backup as TRUE means that the create_backup flag should
102      *   never be added again to the saver (for the current file saving).
103      * - When another error occurs and if the user explicitly retry again
104      *   the file saving, the create_backup flag is added to the saver if
105      *   (1) it is enabled in GSettings, (2) if force_no_backup is FALSE.
106      * - The create_backup flag is added when the user expressed his or her
107      *   willing to save the file, by pressing a button for example. For an
108      *   auto-save, the create_backup flag is thus not added initially, but
109      *   can be added later when an error occurs and the user clicks on a
110      *   button in the info bar to retry the file saving.
111      */
112     guint force_no_backup : 1;
113 };
114 
115 G_DEFINE_TYPE_WITH_PRIVATE (XedTab, xed_tab, GTK_TYPE_BOX)
116 
117 enum
118 {
119     PROP_0,
120     PROP_NAME,
121     PROP_STATE,
122     PROP_AUTO_SAVE,
123     PROP_AUTO_SAVE_INTERVAL,
124     PROP_CAN_CLOSE
125 };
126 
127 static gboolean xed_tab_auto_save (XedTab *tab);
128 
129 static void load (XedTab                  *tab,
130                   const GtkSourceEncoding *encoding,
131                   gint                     line_pos);
132 
133 static void save (XedTab *tab);
134 
135 static SaverData *
saver_data_new(void)136 saver_data_new (void)
137 {
138     return g_slice_new0 (SaverData);
139 }
140 
141 static void
saver_data_free(SaverData * data)142 saver_data_free (SaverData *data)
143 {
144     if (data != NULL)
145     {
146         if (data->saver != NULL)
147         {
148             g_object_unref (data->saver);
149         }
150 
151         g_slice_free (SaverData, data);
152     }
153 }
154 
155 static void
install_auto_save_timeout(XedTab * tab)156 install_auto_save_timeout (XedTab *tab)
157 {
158     if (tab->priv->auto_save_timeout == 0)
159     {
160         g_return_if_fail (tab->priv->auto_save_interval > 0);
161 
162         tab->priv->auto_save_timeout = g_timeout_add_seconds (tab->priv->auto_save_interval * 60,
163                                                               (GSourceFunc) xed_tab_auto_save,
164                                                               tab);
165     }
166 }
167 
168 static void
remove_auto_save_timeout(XedTab * tab)169 remove_auto_save_timeout (XedTab *tab)
170 {
171     xed_debug (DEBUG_TAB);
172 
173     if (tab->priv->auto_save_timeout > 0)
174     {
175         g_source_remove (tab->priv->auto_save_timeout);
176         tab->priv->auto_save_timeout = 0;
177     }
178 }
179 
180 static void
update_auto_save_timeout(XedTab * tab)181 update_auto_save_timeout (XedTab *tab)
182 {
183     gboolean good_state;
184     XedDocument *doc;
185 
186     xed_debug (DEBUG_TAB);
187 
188     good_state = (tab->priv->state == XED_TAB_STATE_NORMAL ||
189                   tab->priv->state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW);
190 
191     doc = xed_tab_get_document (tab);
192 
193     if (good_state &&
194        tab->priv->auto_save &&
195        !xed_document_is_untitled (doc) &&
196        !xed_document_get_readonly (doc))
197     {
198         install_auto_save_timeout (tab);
199     }
200     else
201     {
202         remove_auto_save_timeout (tab);
203     }
204 }
205 
206 static void
xed_tab_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)207 xed_tab_get_property (GObject    *object,
208                       guint       prop_id,
209                       GValue     *value,
210                       GParamSpec *pspec)
211 {
212     XedTab *tab = XED_TAB (object);
213 
214     switch (prop_id)
215     {
216         case PROP_NAME:
217             g_value_take_string (value, _xed_tab_get_name (tab));
218             break;
219         case PROP_STATE:
220             g_value_set_enum (value, xed_tab_get_state (tab));
221             break;
222         case PROP_AUTO_SAVE:
223             g_value_set_boolean (value, xed_tab_get_auto_save_enabled (tab));
224             break;
225         case PROP_AUTO_SAVE_INTERVAL:
226             g_value_set_int (value, xed_tab_get_auto_save_interval (tab));
227             break;
228         case PROP_CAN_CLOSE:
229             g_value_set_boolean (value, _xed_tab_get_can_close (tab));
230         default:
231             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
232             break;
233     }
234 }
235 
236 static void
xed_tab_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)237 xed_tab_set_property (GObject      *object,
238                       guint         prop_id,
239                       const GValue *value,
240                       GParamSpec   *pspec)
241 {
242     XedTab *tab = XED_TAB (object);
243 
244     switch (prop_id)
245     {
246         case PROP_AUTO_SAVE:
247             xed_tab_set_auto_save_enabled (tab, g_value_get_boolean (value));
248             break;
249         case PROP_AUTO_SAVE_INTERVAL:
250             xed_tab_set_auto_save_interval (tab, g_value_get_int (value));
251             break;
252         default:
253             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
254             break;
255     }
256 }
257 
258 static void
clear_loading(XedTab * tab)259 clear_loading (XedTab *tab)
260 {
261     g_clear_object (&tab->priv->loader);
262     g_clear_object (&tab->priv->cancellable);
263 }
264 
265 static void
xed_tab_dispose(GObject * object)266 xed_tab_dispose (GObject *object)
267 {
268     XedTab *tab = XED_TAB (object);
269 
270     g_clear_object (&tab->priv->task_saver);
271 
272     clear_loading (tab);
273 
274     GAction *action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
275                                                   "print-now");
276 
277     g_signal_handlers_disconnect_by_data (action, tab);
278 
279     G_OBJECT_CLASS (xed_tab_parent_class)->dispose (object);
280 }
281 
282 static void
xed_tab_finalize(GObject * object)283 xed_tab_finalize (GObject *object)
284 {
285     XedTab *tab = XED_TAB (object);
286 
287     g_clear_object (&tab->priv->editor);
288 
289     if (tab->priv->timer != NULL)
290     {
291         g_timer_destroy (tab->priv->timer);
292     }
293 
294     remove_auto_save_timeout (tab);
295 
296     if (tab->priv->idle_scroll != 0)
297     {
298         g_source_remove (tab->priv->idle_scroll);
299         tab->priv->idle_scroll = 0;
300     }
301 
302     G_OBJECT_CLASS (xed_tab_parent_class)->finalize (object);
303 }
304 
305 static void
xed_tab_class_init(XedTabClass * klass)306 xed_tab_class_init (XedTabClass *klass)
307 {
308     GObjectClass *object_class = G_OBJECT_CLASS (klass);
309 
310     object_class->dispose = xed_tab_dispose;
311     object_class->finalize = xed_tab_finalize;
312     object_class->get_property = xed_tab_get_property;
313     object_class->set_property = xed_tab_set_property;
314 
315     g_object_class_install_property (object_class,
316                                      PROP_NAME,
317                                      g_param_spec_string ("name",
318                                                           "Name",
319                                                           "The tab's name",
320                                                           NULL,
321                                                           G_PARAM_READABLE |
322                                                           G_PARAM_STATIC_STRINGS));
323 
324     g_object_class_install_property (object_class,
325                                      PROP_STATE,
326                                      g_param_spec_enum ("state",
327                                                         "State",
328                                                         "The tab's state",
329                                                         XED_TYPE_TAB_STATE,
330                                                         XED_TAB_STATE_NORMAL,
331                                                         G_PARAM_READABLE |
332                                                         G_PARAM_STATIC_STRINGS));
333 
334     g_object_class_install_property (object_class,
335                                      PROP_AUTO_SAVE,
336                                      g_param_spec_boolean ("autosave",
337                                                            "Autosave",
338                                                            "Autosave feature",
339                                                            TRUE,
340                                                            G_PARAM_READWRITE |
341                                                            G_PARAM_STATIC_STRINGS));
342 
343     g_object_class_install_property (object_class,
344                                      PROP_AUTO_SAVE_INTERVAL,
345                                      g_param_spec_int ("autosave-interval",
346                                                        "AutosaveInterval",
347                                                        "Time between two autosaves",
348                                                        0,
349                                                        G_MAXINT,
350                                                        0,
351                                                        G_PARAM_READWRITE |
352                                                        G_PARAM_STATIC_STRINGS));
353 
354     g_object_class_install_property (object_class,
355                                      PROP_CAN_CLOSE,
356                                      g_param_spec_boolean ("can-close",
357                                                            "Can close",
358                                                            "Wheather the tab can be closed",
359                                                            TRUE,
360                                                            G_PARAM_READABLE |
361                                                            G_PARAM_STATIC_STRINGS));
362 }
363 
364 /**
365  * xed_tab_get_state:
366  * @tab: a #XedTab
367  *
368  * Gets the #XedTabState of @tab.
369  *
370  * Returns: the #XedTabState of @tab
371  */
372 XedTabState
xed_tab_get_state(XedTab * tab)373 xed_tab_get_state (XedTab *tab)
374 {
375     g_return_val_if_fail (XED_IS_TAB (tab), XED_TAB_STATE_NORMAL);
376 
377     return tab->priv->state;
378 }
379 
380 static void
set_cursor_according_to_state(GtkTextView * view,XedTabState state)381 set_cursor_according_to_state (GtkTextView *view,
382                                XedTabState  state)
383 {
384     GdkCursor *cursor;
385     GdkWindow *text_window;
386     GdkWindow *left_window;
387 
388     text_window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_TEXT);
389     left_window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_LEFT);
390 
391     if ((state == XED_TAB_STATE_LOADING)          ||
392         (state == XED_TAB_STATE_REVERTING)        ||
393         (state == XED_TAB_STATE_SAVING)           ||
394         (state == XED_TAB_STATE_PRINTING)         ||
395         (state == XED_TAB_STATE_PRINT_PREVIEWING) ||
396         (state == XED_TAB_STATE_CLOSING))
397     {
398         cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (view)), GDK_WATCH);
399 
400         if (text_window != NULL)
401         {
402             gdk_window_set_cursor (text_window, cursor);
403         }
404         if (left_window != NULL)
405         {
406             gdk_window_set_cursor (left_window, cursor);
407         }
408 
409         g_object_unref (cursor);
410     }
411     else
412     {
413         cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (view)), GDK_XTERM);
414 
415         if (text_window != NULL)
416         {
417             gdk_window_set_cursor (text_window, cursor);
418         }
419         if (left_window != NULL)
420         {
421             gdk_window_set_cursor (left_window, NULL);
422         }
423 
424         g_object_unref (cursor);
425     }
426 }
427 
428 static void
view_realized(GtkTextView * view,XedTab * tab)429 view_realized (GtkTextView *view,
430                XedTab      *tab)
431 {
432     set_cursor_according_to_state (view, tab->priv->state);
433 }
434 
435 static void
set_view_properties_according_to_state(XedTab * tab,XedTabState state)436 set_view_properties_according_to_state (XedTab      *tab,
437                                         XedTabState  state)
438 {
439     XedView *view;
440     gboolean val;
441     gboolean hl_current_line;
442 
443     hl_current_line = g_settings_get_boolean (tab->priv->editor, XED_SETTINGS_HIGHLIGHT_CURRENT_LINE);
444     view = xed_view_frame_get_view (tab->priv->frame);
445     val = ((state == XED_TAB_STATE_NORMAL) && (tab->priv->print_preview == NULL) && tab->priv->editable);
446     gtk_text_view_set_editable (GTK_TEXT_VIEW (view), val);
447 
448     val = ((state != XED_TAB_STATE_LOADING) && (state != XED_TAB_STATE_CLOSING));
449     gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), val);
450 
451     val = ((state != XED_TAB_STATE_LOADING) &&
452            (state != XED_TAB_STATE_CLOSING) &&
453            (hl_current_line));
454     gtk_source_view_set_highlight_current_line (GTK_SOURCE_VIEW (view), val);
455 }
456 
457 static void
xed_tab_set_state(XedTab * tab,XedTabState state)458 xed_tab_set_state (XedTab      *tab,
459                    XedTabState  state)
460 {
461     g_return_if_fail (XED_IS_TAB (tab));
462     g_return_if_fail ((state >= 0) && (state < XED_TAB_NUM_OF_STATES));
463 
464     if (tab->priv->state == state)
465     {
466         return;
467     }
468 
469     tab->priv->state = state;
470 
471     set_view_properties_according_to_state (tab, state);
472 
473     if ((state == XED_TAB_STATE_LOADING_ERROR) || /* FIXME: add other states if needed */
474         (state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW))
475     {
476         gtk_widget_hide (GTK_WIDGET (tab->priv->frame));
477     }
478     else
479     {
480         if (tab->priv->print_preview == NULL)
481         {
482             gtk_widget_show (GTK_WIDGET (tab->priv->frame));
483         }
484     }
485 
486     set_cursor_according_to_state (GTK_TEXT_VIEW (xed_view_frame_get_view (tab->priv->frame)), state);
487 
488     update_auto_save_timeout (tab);
489 
490     g_object_notify (G_OBJECT (tab), "state");
491     g_object_notify (G_OBJECT (tab), "can-close");
492 }
493 
494 static void
document_location_notify_handler(GtkSourceFile * file,GParamSpec * pspec,XedTab * tab)495 document_location_notify_handler (GtkSourceFile *file,
496                                   GParamSpec    *pspec,
497                                   XedTab        *tab)
498 {
499     xed_debug (DEBUG_TAB);
500 
501     /* Notify the change in the location */
502     g_object_notify (G_OBJECT (tab), "name");
503 }
504 
505 static void
document_shortname_notify_handler(XedDocument * document,GParamSpec * pspec,XedTab * tab)506 document_shortname_notify_handler (XedDocument *document,
507                                    GParamSpec  *pspec,
508                                    XedTab      *tab)
509 {
510     xed_debug (DEBUG_TAB);
511 
512     /* Notify the change in the shortname */
513     g_object_notify (G_OBJECT (tab), "name");
514 }
515 
516 static void
document_modified_changed(GtkTextBuffer * document,XedTab * tab)517 document_modified_changed (GtkTextBuffer *document,
518                            XedTab        *tab)
519 {
520     g_object_notify (G_OBJECT (tab), "name");
521     g_object_notify (G_OBJECT (tab), "can-close");
522 }
523 
524 static void
set_info_bar(XedTab * tab,GtkWidget * info_bar)525 set_info_bar (XedTab    *tab,
526               GtkWidget *info_bar)
527 {
528     if (tab->priv->info_bar == info_bar)
529     {
530         return;
531     }
532 
533     if (tab->priv->info_bar != NULL)
534     {
535         gtk_widget_destroy (tab->priv->info_bar);
536     }
537 
538     tab->priv->info_bar = info_bar;
539 
540     if (info_bar == NULL)
541     {
542         return;
543     }
544 
545     gtk_box_pack_start (GTK_BOX (tab), tab->priv->info_bar, FALSE, FALSE, 0);
546 
547     g_object_add_weak_pointer (G_OBJECT (tab->priv->info_bar), (gpointer *)&tab->priv->info_bar);
548 }
549 
550 static void
remove_tab(XedTab * tab)551 remove_tab (XedTab *tab)
552 {
553     XedNotebook *notebook;
554 
555     notebook = XED_NOTEBOOK (gtk_widget_get_parent (GTK_WIDGET (tab)));
556 
557     xed_notebook_remove_tab (notebook, tab);
558 }
559 
560 static void
io_loading_error_info_bar_response(GtkWidget * info_bar,gint response_id,XedTab * tab)561 io_loading_error_info_bar_response (GtkWidget *info_bar,
562                                     gint       response_id,
563                                     XedTab    *tab)
564 {
565     XedView *view;
566     GFile *location;
567     const GtkSourceEncoding *encoding;
568 
569     g_return_if_fail (tab->priv->loader != NULL);
570 
571     view = xed_tab_get_view (tab);
572     location = gtk_source_file_loader_get_location (tab->priv->loader);
573 
574     switch (response_id)
575     {
576         case GTK_RESPONSE_OK:
577             encoding = xed_conversion_error_info_bar_get_encoding (GTK_WIDGET (info_bar));
578 
579             set_info_bar (tab, NULL);
580             xed_tab_set_state (tab, XED_TAB_STATE_LOADING);
581 
582             load (tab, encoding, tab->priv->tmp_line_pos);
583             break;
584 
585         case GTK_RESPONSE_YES:
586             /* This means that we want to edit the document anyway */
587             tab->priv->editable = TRUE;
588             gtk_text_view_set_editable (GTK_TEXT_VIEW (view), TRUE);
589             set_info_bar (tab, NULL);
590             clear_loading (tab);
591             break;
592 
593         default:
594             _xed_recent_remove (XED_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tab))), location);
595 
596             remove_tab (tab);
597             break;
598     }
599 }
600 
601 static void
file_already_open_warning_info_bar_response(GtkWidget * info_bar,gint response_id,XedTab * tab)602 file_already_open_warning_info_bar_response (GtkWidget *info_bar,
603                                              gint       response_id,
604                                              XedTab    *tab)
605 {
606     XedView *view;
607 
608     view = xed_tab_get_view (tab);
609 
610     if (response_id == GTK_RESPONSE_YES)
611     {
612         tab->priv->editable = TRUE;
613         gtk_text_view_set_editable (GTK_TEXT_VIEW (view), TRUE);
614     }
615 
616     gtk_widget_destroy (info_bar);
617 
618     gtk_widget_grab_focus (GTK_WIDGET (view));
619 }
620 
621 static void
load_cancelled(GtkWidget * area,gint response_id,XedTab * tab)622 load_cancelled (GtkWidget *area,
623                 gint       response_id,
624                 XedTab    *tab)
625 {
626     g_return_if_fail (XED_IS_PROGRESS_INFO_BAR (tab->priv->info_bar));
627     g_return_if_fail (G_IS_CANCELLABLE (tab->priv->cancellable));
628 
629     g_cancellable_cancel (tab->priv->cancellable);
630 }
631 
632 static void
unrecoverable_reverting_error_info_bar_response(GtkWidget * info_bar,gint response_id,XedTab * tab)633 unrecoverable_reverting_error_info_bar_response (GtkWidget *info_bar,
634                                                  gint       response_id,
635                                                  XedTab    *tab)
636 {
637     XedView *view;
638 
639     xed_tab_set_state (tab, XED_TAB_STATE_NORMAL);
640 
641     set_info_bar (tab, NULL);
642 
643     clear_loading (tab);
644 
645     view = xed_tab_get_view (tab);
646     gtk_widget_grab_focus (GTK_WIDGET (view));
647 }
648 
649 #define MAX_MSG_LENGTH 100
650 
651 static void
show_loading_info_bar(XedTab * tab)652 show_loading_info_bar (XedTab *tab)
653 {
654     GtkWidget *bar;
655     XedDocument *doc = NULL;
656     gchar *name;
657     gchar *dirname = NULL;
658     gchar *msg = NULL;
659     gchar *name_markup;
660     gchar *dirname_markup;
661     gint len;
662 
663     if (tab->priv->info_bar != NULL)
664     {
665         return;
666     }
667 
668     xed_debug (DEBUG_TAB);
669 
670     doc = xed_tab_get_document (tab);
671     g_return_if_fail (doc != NULL);
672 
673     name = xed_document_get_short_name_for_display (doc);
674     len = g_utf8_strlen (name, -1);
675 
676     /* if the name is awfully long, truncate it and be done with it,
677      * otherwise also show the directory (ellipsized if needed)
678      */
679     if (len > MAX_MSG_LENGTH)
680     {
681         gchar *str;
682 
683         str = xed_utils_str_middle_truncate (name, MAX_MSG_LENGTH);
684         g_free (name);
685         name = str;
686     }
687     else
688     {
689         GtkSourceFile *file = xed_document_get_file (doc);
690         GFile *location = gtk_source_file_get_location (file);
691 
692         if (location != NULL)
693         {
694             gchar *str = xed_utils_location_get_dirname_for_display (location);
695 
696             /* use the remaining space for the dir, but use a min of 20 chars
697              * so that we do not end up with a dirname like "(a...b)".
698              * This means that in the worst case when the filename is long 99
699              * we have a title long 99 + 20, but I think it's a rare enough
700              * case to be acceptable. It's justa darn title afterall :)
701              */
702             dirname = xed_utils_str_middle_truncate (str, MAX (20, MAX_MSG_LENGTH - len));
703             g_free (str);
704         }
705     }
706 
707     name_markup = g_markup_printf_escaped ("<b>%s</b>", name);
708 
709     if (tab->priv->state == XED_TAB_STATE_REVERTING)
710     {
711         if (dirname != NULL)
712         {
713             dirname_markup = g_markup_printf_escaped ("<b>%s</b>", dirname);
714 
715             /* Translators: the first %s is a file name (e.g. test.txt) the second one
716                is a directory (e.g. ssh://master.gnome.org/home/users/paolo) */
717             msg = g_strdup_printf (_("Reverting %s from %s"), name_markup, dirname_markup);
718             g_free (dirname_markup);
719         }
720         else
721         {
722             msg = g_strdup_printf (_("Reverting %s"), name_markup);
723         }
724 
725         bar = xed_progress_info_bar_new ("document-revert-symbolic", msg, TRUE);
726     }
727     else
728     {
729         if (dirname != NULL)
730         {
731             dirname_markup = g_markup_printf_escaped ("<b>%s</b>", dirname);
732 
733             /* Translators: the first %s is a file name (e.g. test.txt) the second one
734                is a directory (e.g. ssh://master.gnome.org/home/users/paolo) */
735             msg = g_strdup_printf (_("Loading %s from %s"), name_markup, dirname_markup);
736             g_free (dirname_markup);
737         }
738         else
739         {
740             msg = g_strdup_printf (_("Loading %s"), name_markup);
741         }
742 
743         bar = xed_progress_info_bar_new ("document-open-symbolic", msg, TRUE);
744     }
745 
746     g_signal_connect (bar, "response",
747                       G_CALLBACK (load_cancelled), tab);
748 
749     gtk_widget_show (bar);
750 
751     set_info_bar (tab, bar);
752 
753     g_free (msg);
754     g_free (name);
755     g_free (name_markup);
756     g_free (dirname);
757 }
758 
759 static void
show_saving_info_bar(XedTab * tab)760 show_saving_info_bar (XedTab *tab)
761 {
762     GtkWidget *bar;
763     XedDocument *doc = NULL;
764     gchar *short_name;
765     gchar *from;
766     gchar *to = NULL;
767     gchar *from_markup;
768     gchar *to_markup;
769     gchar *msg = NULL;
770     gint len;
771 
772     g_return_if_fail (tab->priv->task_saver != NULL);
773 
774     if (tab->priv->info_bar != NULL)
775     {
776         return;
777     }
778 
779     xed_debug (DEBUG_TAB);
780 
781     doc = xed_tab_get_document (tab);
782     g_return_if_fail (doc != NULL);
783 
784     short_name = xed_document_get_short_name_for_display (doc);
785 
786     len = g_utf8_strlen (short_name, -1);
787 
788     /* if the name is awfully long, truncate it and be done with it,
789      * otherwise also show the directory (ellipsized if needed)
790      */
791     if (len > MAX_MSG_LENGTH)
792     {
793         from = xed_utils_str_middle_truncate (short_name, MAX_MSG_LENGTH);
794         g_free (short_name);
795     }
796     else
797     {
798         gchar *str;
799         SaverData *data;
800         GFile *location;
801 
802         data = g_task_get_task_data (tab->priv->task_saver);
803         location = gtk_source_file_saver_get_location (data->saver);
804 
805         from = short_name;
806         to = g_file_get_parse_name (location);
807         str = xed_utils_str_middle_truncate (to, MAX (20, MAX_MSG_LENGTH - len));
808         g_free (to);
809 
810         to = str;
811     }
812 
813     from_markup = g_markup_printf_escaped ("<b>%s</b>", from);
814 
815     if (to != NULL)
816     {
817         to_markup = g_markup_printf_escaped ("<b>%s</b>", to);
818 
819         /* Translators: the first %s is a file name (e.g. test.txt) the second one
820            is a directory (e.g. ssh://master.gnome.org/home/users/paolo) */
821         msg = g_strdup_printf (_("Saving %s to %s"), from_markup, to_markup);
822         g_free (to_markup);
823     }
824     else
825     {
826         msg = g_strdup_printf (_("Saving %s"), from_markup);
827     }
828 
829     bar = xed_progress_info_bar_new ("document-save-symbolic", msg, FALSE);
830 
831     gtk_widget_show (bar);
832 
833     set_info_bar (tab, bar);
834 
835     g_free (msg);
836     g_free (to);
837     g_free (from);
838     g_free (from_markup);
839 }
840 
841 static void
info_bar_set_progress(XedTab * tab,goffset size,goffset total_size)842 info_bar_set_progress (XedTab  *tab,
843                        goffset  size,
844                        goffset  total_size)
845 {
846     if (tab->priv->info_bar == NULL)
847     {
848         return;
849     }
850 
851     xed_debug_message (DEBUG_TAB, "%" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT, size, total_size);
852 
853     g_return_if_fail (XED_IS_PROGRESS_INFO_BAR (tab->priv->info_bar));
854 
855     if (total_size == 0)
856     {
857         if (size != 0)
858             xed_progress_info_bar_pulse (XED_PROGRESS_INFO_BAR (tab->priv->info_bar));
859         else
860             xed_progress_info_bar_set_fraction (XED_PROGRESS_INFO_BAR (tab->priv->info_bar), 0);
861     }
862     else
863     {
864         gdouble frac;
865 
866         frac = (gdouble)size / (gdouble)total_size;
867 
868         xed_progress_info_bar_set_fraction (XED_PROGRESS_INFO_BAR (tab->priv->info_bar), frac);
869     }
870 }
871 
872 static gboolean
scroll_to_cursor(XedTab * tab)873 scroll_to_cursor (XedTab *tab)
874 {
875     XedView *view;
876 
877     view = xed_tab_get_view (tab);
878     xed_view_scroll_to_cursor (view);
879 
880     tab->priv->idle_scroll = 0;
881     return G_SOURCE_REMOVE;
882 }
883 
884 static void
unrecoverable_saving_error_info_bar_response(GtkWidget * info_bar,gint response_id,XedTab * tab)885 unrecoverable_saving_error_info_bar_response (GtkWidget *info_bar,
886                                               gint       response_id,
887                                               XedTab    *tab)
888 {
889     XedView *view;
890 
891     if (tab->priv->print_preview != NULL)
892     {
893         xed_tab_set_state (tab, XED_TAB_STATE_SHOWING_PRINT_PREVIEW);
894     }
895     else
896     {
897         xed_tab_set_state (tab, XED_TAB_STATE_NORMAL);
898     }
899 
900     set_info_bar (tab, NULL);
901 
902     g_return_if_fail (tab->priv->task_saver != NULL);
903     g_task_return_boolean (tab->priv->task_saver, FALSE);
904 
905     view = xed_tab_get_view (tab);
906 
907     gtk_widget_grab_focus (GTK_WIDGET (view));
908 }
909 
910 /* Sets the save flags after an info bar response. */
911 static void
response_set_save_flags(XedTab * tab,GtkSourceFileSaverFlags save_flags)912 response_set_save_flags (XedTab                  *tab,
913                          GtkSourceFileSaverFlags  save_flags)
914 {
915     SaverData *data;
916     gboolean create_backup;
917 
918     data = g_task_get_task_data (tab->priv->task_saver);
919 
920     create_backup = g_settings_get_boolean (tab->priv->editor, XED_SETTINGS_CREATE_BACKUP_COPY);
921 
922     /* If we are here, it means that the user expressed his or her willing
923     * to save the file, by pressing a button in the info bar. So even if
924     * the file saving was initially an auto-save, we set the create_backup
925     * flag (if the conditions are met).
926     */
927     if (create_backup && !data->force_no_backup)
928     {
929         save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_CREATE_BACKUP;
930     }
931     else
932     {
933         save_flags &= ~GTK_SOURCE_FILE_SAVER_FLAGS_CREATE_BACKUP;
934     }
935 
936     gtk_source_file_saver_set_flags (data->saver, save_flags);
937 }
938 
939 static void
invalid_character_info_bar_response(GtkWidget * info_bar,gint response_id,XedTab * tab)940 invalid_character_info_bar_response (GtkWidget *info_bar,
941                                      gint       response_id,
942                                      XedTab    *tab)
943 {
944     if (response_id == GTK_RESPONSE_YES)
945     {
946         SaverData *data;
947         GtkSourceFileSaverFlags save_flags;
948 
949         set_info_bar (tab, NULL);
950 
951         g_return_if_fail (tab->priv->task_saver != NULL);
952         data = g_task_get_task_data (tab->priv->task_saver);
953 
954         /* Don't bug the user again with this... */
955         tab->priv->save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_INVALID_CHARS;
956 
957         save_flags = gtk_source_file_saver_get_flags (data->saver);
958         save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_INVALID_CHARS;
959         response_set_save_flags (tab, save_flags);
960 
961         /* Force saving */
962         save (tab);
963     }
964     else
965     {
966         unrecoverable_saving_error_info_bar_response (info_bar, response_id, tab);
967     }
968 }
969 
970 static void
no_backup_error_info_bar_response(GtkWidget * info_bar,gint response_id,XedTab * tab)971 no_backup_error_info_bar_response (GtkWidget *info_bar,
972                                    gint       response_id,
973                                    XedTab    *tab)
974 {
975     if (response_id == GTK_RESPONSE_YES)
976     {
977         SaverData *data;
978         GtkSourceFileSaverFlags save_flags;
979 
980         set_info_bar (tab, NULL);
981 
982         g_return_if_fail (tab->priv->task_saver != NULL);
983         data = g_task_get_task_data (tab->priv->task_saver);
984 
985         data->force_no_backup = TRUE;
986         save_flags = gtk_source_file_saver_get_flags (data->saver);
987         response_set_save_flags (tab, save_flags);
988 
989         /* Force saving */
990         save (tab);
991     }
992     else
993     {
994         unrecoverable_saving_error_info_bar_response (info_bar, response_id, tab);
995     }
996 }
997 
998 static void
externally_modified_error_info_bar_response(GtkWidget * info_bar,gint response_id,XedTab * tab)999 externally_modified_error_info_bar_response (GtkWidget *info_bar,
1000                                              gint       response_id,
1001                                              XedTab    *tab)
1002 {
1003     if (response_id == GTK_RESPONSE_YES)
1004     {
1005         SaverData *data;
1006         GtkSourceFileSaverFlags save_flags;
1007 
1008         set_info_bar (tab, NULL);
1009 
1010         g_return_if_fail (tab->priv->task_saver != NULL);
1011         data = g_task_get_task_data (tab->priv->task_saver);
1012 
1013         /* ignore_modification_time should not be persisted in save
1014          * flags across saves (i.e. priv->save_flags is not modified).
1015          */
1016 
1017         save_flags = gtk_source_file_saver_get_flags (data->saver);
1018         save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_MODIFICATION_TIME;
1019         response_set_save_flags (tab, save_flags);
1020 
1021         /* Force saving */
1022         save (tab);
1023     }
1024     else
1025     {
1026         unrecoverable_saving_error_info_bar_response (info_bar, response_id, tab);
1027     }
1028 }
1029 
1030 static void
recoverable_saving_error_info_bar_response(GtkWidget * info_bar,gint response_id,XedTab * tab)1031 recoverable_saving_error_info_bar_response (GtkWidget *info_bar,
1032                                             gint       response_id,
1033                                             XedTab    *tab)
1034 {
1035     if (response_id == GTK_RESPONSE_OK)
1036     {
1037         SaverData *data;
1038         const GtkSourceEncoding *encoding;
1039 
1040         set_info_bar (tab, NULL);
1041 
1042         g_return_if_fail (tab->priv->task_saver != NULL);
1043         data = g_task_get_task_data (tab->priv->task_saver);
1044 
1045         encoding = xed_conversion_error_info_bar_get_encoding (GTK_WIDGET (info_bar));
1046         g_return_if_fail (encoding != NULL);
1047 
1048         gtk_source_file_saver_set_encoding (data->saver, encoding);
1049         save (tab);
1050     }
1051     else
1052     {
1053         unrecoverable_saving_error_info_bar_response (info_bar, response_id, tab);
1054     }
1055 }
1056 
1057 static void
externally_modified_notification_info_bar_response(GtkWidget * info_bar,gint response_id,XedTab * tab)1058 externally_modified_notification_info_bar_response (GtkWidget *info_bar,
1059                                                     gint       response_id,
1060                                                     XedTab    *tab)
1061 {
1062     XedView *view;
1063 
1064     set_info_bar (tab, NULL);
1065     view = xed_tab_get_view (tab);
1066 
1067     if (response_id == GTK_RESPONSE_OK)
1068     {
1069         _xed_tab_revert (tab);
1070     }
1071     else
1072     {
1073         tab->priv->ask_if_externally_modified = FALSE;
1074 
1075         /* go back to normal state */
1076         xed_tab_set_state (tab, XED_TAB_STATE_NORMAL);
1077     }
1078 
1079     gtk_widget_grab_focus (GTK_WIDGET (view));
1080 }
1081 
1082 static void
display_externally_modified_notification(XedTab * tab)1083 display_externally_modified_notification (XedTab *tab)
1084 {
1085     GtkWidget *info_bar;
1086     XedDocument *doc;
1087     GtkSourceFile *file;
1088     GFile *location;
1089     gboolean document_modified;
1090 
1091     doc = xed_tab_get_document (tab);
1092     g_return_if_fail (XED_IS_DOCUMENT (doc));
1093     file = xed_document_get_file (doc);
1094 
1095     /* we're here because the file we're editing changed on disk */
1096     location = gtk_source_file_get_location (file);
1097     g_return_if_fail (location != NULL);
1098 
1099     document_modified = gtk_text_buffer_get_modified (GTK_TEXT_BUFFER(doc));
1100     info_bar = xed_externally_modified_info_bar_new (location, document_modified);
1101 
1102     tab->priv->info_bar = NULL;
1103     set_info_bar (tab, info_bar);
1104     gtk_widget_show (info_bar);
1105 
1106     g_signal_connect (info_bar, "response",
1107                       G_CALLBACK (externally_modified_notification_info_bar_response), tab);
1108 }
1109 
1110 static gboolean
view_focused_in(GtkWidget * widget,GdkEventFocus * event,XedTab * tab)1111 view_focused_in (GtkWidget     *widget,
1112                  GdkEventFocus *event,
1113                  XedTab        *tab)
1114 {
1115     XedDocument *doc;
1116     GtkSourceFile *file;
1117 
1118     g_return_val_if_fail (XED_IS_TAB (tab), FALSE);
1119 
1120     /* we try to detect file changes only in the normal state */
1121     if (tab->priv->state != XED_TAB_STATE_NORMAL)
1122     {
1123         return GDK_EVENT_PROPAGATE;
1124     }
1125 
1126     /* we already asked, don't bug the user again */
1127     if (!tab->priv->ask_if_externally_modified)
1128     {
1129         return GDK_EVENT_PROPAGATE;
1130     }
1131 
1132     doc = xed_tab_get_document (tab);
1133     file = xed_document_get_file (doc);
1134 
1135     /* If file was never saved or is remote we do not check */
1136     if (gtk_source_file_is_local (file))
1137     {
1138         gtk_source_file_check_file_on_disk (file);
1139 
1140         if (gtk_source_file_is_externally_modified (file))
1141         {
1142             xed_tab_set_state (tab, XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION);
1143 
1144             display_externally_modified_notification (tab);
1145         }
1146     }
1147 
1148     return GDK_EVENT_PROPAGATE;
1149 }
1150 
1151 static void
print_now_action_cb(XedTab * tab)1152 print_now_action_cb (XedTab   *tab)
1153 {
1154     g_return_if_fail (XED_IS_TAB (tab));
1155 
1156     _xed_tab_print (tab, FALSE);
1157 }
1158 
1159 static void
xed_tab_init(XedTab * tab)1160 xed_tab_init (XedTab *tab)
1161 {
1162     gboolean auto_save;
1163     guint auto_save_interval;
1164     XedDocument *doc;
1165     XedView *view;
1166     GtkSourceFile *file;
1167 
1168     tab->priv = xed_tab_get_instance_private (tab);
1169 
1170     tab->priv->editor = g_settings_new ("org.x.editor.preferences.editor");
1171     tab->priv->state = XED_TAB_STATE_NORMAL;
1172     tab->priv->editable = TRUE;
1173     tab->priv->ask_if_externally_modified = TRUE;
1174 
1175     gtk_orientable_set_orientation (GTK_ORIENTABLE (tab), GTK_ORIENTATION_VERTICAL);
1176 
1177     /* Manage auto save data */
1178     auto_save = g_settings_get_boolean (tab->priv->editor, XED_SETTINGS_AUTO_SAVE);
1179     auto_save_interval = g_settings_get_uint (tab->priv->editor, XED_SETTINGS_AUTO_SAVE_INTERVAL);
1180     tab->priv->auto_save = auto_save;
1181     tab->priv->auto_save = (tab->priv->auto_save != FALSE);
1182 
1183     tab->priv->auto_save_interval = auto_save_interval;
1184 
1185     /* Create the frame */
1186     tab->priv->frame = xed_view_frame_new ();
1187     gtk_widget_show (GTK_WIDGET (tab->priv->frame));
1188 
1189     gtk_box_pack_end (GTK_BOX (tab), GTK_WIDGET (tab->priv->frame), TRUE, TRUE, 0);
1190 
1191     doc = xed_view_frame_get_document (tab->priv->frame);
1192     g_object_set_data (G_OBJECT (doc), XED_TAB_KEY, tab);
1193 
1194     view = xed_view_frame_get_view (tab->priv->frame);
1195     g_object_set_data (G_OBJECT (view), XED_TAB_KEY, tab);
1196 
1197     file = xed_document_get_file (doc);
1198 
1199     g_signal_connect_object (file, "notify::location",
1200                              G_CALLBACK (document_location_notify_handler), tab, 0);
1201     g_signal_connect (doc, "notify::shortname",
1202                       G_CALLBACK (document_shortname_notify_handler), tab);
1203     g_signal_connect (doc, "modified_changed",
1204                       G_CALLBACK (document_modified_changed), tab);
1205 
1206     g_signal_connect_after (view, "focus-in-event",
1207                             G_CALLBACK (view_focused_in), tab);
1208     g_signal_connect_after (view, "realize",
1209                             G_CALLBACK (view_realized), tab);
1210 
1211     GAction *action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
1212                                                   "print-now");
1213 
1214     g_signal_connect_swapped (action, "activate",
1215                               G_CALLBACK (print_now_action_cb), tab);
1216 }
1217 
1218 GtkWidget *
_xed_tab_new(void)1219 _xed_tab_new (void)
1220 {
1221     return GTK_WIDGET (g_object_new (XED_TYPE_TAB, NULL));
1222 }
1223 
1224 /* Whether create is TRUE, creates a new empty document if location does
1225    not refer to an existing file */
1226 GtkWidget *
_xed_tab_new_from_location(GFile * location,const GtkSourceEncoding * encoding,gint line_pos,gboolean create)1227 _xed_tab_new_from_location (GFile                   *location,
1228                             const GtkSourceEncoding *encoding,
1229                             gint                     line_pos,
1230                             gboolean                 create)
1231 {
1232     XedTab *tab;
1233 
1234     g_return_val_if_fail (G_IS_FILE (location), NULL);
1235 
1236     tab = XED_TAB (_xed_tab_new ());
1237 
1238     _xed_tab_load (tab, location, encoding, line_pos, create);
1239 
1240     return GTK_WIDGET (tab);
1241 }
1242 
1243 GtkWidget *
_xed_tab_new_from_stream(GInputStream * stream,const GtkSourceEncoding * encoding,gint line_pos)1244 _xed_tab_new_from_stream (GInputStream            *stream,
1245                           const GtkSourceEncoding *encoding,
1246                           gint                     line_pos)
1247 {
1248     GtkWidget *tab;
1249 
1250     g_return_val_if_fail (G_IS_INPUT_STREAM (stream), NULL);
1251 
1252     tab = _xed_tab_new ();
1253 
1254     _xed_tab_load_stream (XED_TAB (tab), stream, encoding, line_pos);
1255 
1256     return tab;
1257 }
1258 
1259 /**
1260  * xed_tab_get_view:
1261  * @tab: a #XedTab
1262  *
1263  * Gets the #XedView inside @tab.
1264  *
1265  * Returns: (transfer none): the #XedView inside @tab
1266  */
1267 XedView *
xed_tab_get_view(XedTab * tab)1268 xed_tab_get_view (XedTab *tab)
1269 {
1270     g_return_val_if_fail (XED_IS_TAB (tab), NULL);
1271 
1272     return xed_view_frame_get_view (tab->priv->frame);
1273 }
1274 
1275 /**
1276  * xed_tab_get_document:
1277  * @tab: a #XedTab
1278  *
1279  * Gets the #XedDocument associated to @tab.
1280  *
1281  * Returns: (transfer none): the #XedDocument associated to @tab
1282  */
1283 XedDocument *
xed_tab_get_document(XedTab * tab)1284 xed_tab_get_document (XedTab *tab)
1285 {
1286     g_return_val_if_fail (XED_IS_TAB (tab), NULL);
1287 
1288     return xed_view_frame_get_document (tab->priv->frame);
1289 }
1290 
1291 #define MAX_DOC_NAME_LENGTH 40
1292 
1293 gchar *
_xed_tab_get_name(XedTab * tab)1294 _xed_tab_get_name (XedTab *tab)
1295 {
1296     XedDocument *doc;
1297     gchar *name;
1298     gchar *docname;
1299     gchar *tab_name;
1300 
1301     g_return_val_if_fail (XED_IS_TAB (tab), NULL);
1302 
1303     doc = xed_tab_get_document (tab);
1304 
1305     name = xed_document_get_short_name_for_display (doc);
1306 
1307     /* Truncate the name so it doesn't get insanely wide. */
1308     docname = xed_utils_str_middle_truncate (name, MAX_DOC_NAME_LENGTH);
1309 
1310     if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)))
1311     {
1312         tab_name = g_strdup_printf ("*%s", docname);
1313     }
1314     else
1315     {
1316  #if 0
1317         if (xed_document_get_readonly (doc))
1318         {
1319             tab_name = g_strdup_printf ("%s [%s]", docname,
1320                         /*Read only*/ _("RO"));
1321         }
1322         else
1323         {
1324             tab_name = g_strdup_printf ("%s", docname);
1325         }
1326 #endif
1327         tab_name = g_strdup (docname);
1328     }
1329 
1330     g_free (docname);
1331     g_free (name);
1332 
1333     return tab_name;
1334 }
1335 
1336 gchar *
_xed_tab_get_tooltips(XedTab * tab)1337 _xed_tab_get_tooltips (XedTab *tab)
1338 {
1339     XedDocument *doc;
1340     gchar *tip;
1341     gchar *uri;
1342     gchar *ruri;
1343     gchar *ruri_markup;
1344 
1345     g_return_val_if_fail (XED_IS_TAB (tab), NULL);
1346 
1347     doc = xed_tab_get_document (tab);
1348 
1349     uri = xed_document_get_uri_for_display (doc);
1350     g_return_val_if_fail (uri != NULL, NULL);
1351 
1352     ruri =  xed_utils_replace_home_dir_with_tilde (uri);
1353     g_free (uri);
1354 
1355     ruri_markup = g_markup_printf_escaped ("<i>%s</i>", ruri);
1356 
1357     switch (tab->priv->state)
1358     {
1359         gchar *content_type;
1360         gchar *mime_type;
1361         gchar *content_description;
1362         gchar *content_full_description;
1363         gchar *encoding;
1364         GtkSourceFile *file;
1365         const GtkSourceEncoding *enc;
1366 
1367         case XED_TAB_STATE_LOADING_ERROR:
1368             tip = g_strdup_printf (_("Error opening file %s"), ruri_markup);
1369             break;
1370 
1371         case XED_TAB_STATE_REVERTING_ERROR:
1372             tip = g_strdup_printf (_("Error reverting file %s"), ruri_markup);
1373             break;
1374 
1375         case XED_TAB_STATE_SAVING_ERROR:
1376             tip =  g_strdup_printf (_("Error saving file %s"), ruri_markup);
1377             break;
1378         default:
1379             content_type = xed_document_get_content_type (doc);
1380             mime_type = xed_document_get_mime_type (doc);
1381             content_description = g_content_type_get_description (content_type);
1382 
1383             if (content_description == NULL)
1384             {
1385                 content_full_description = g_strdup (mime_type);
1386             }
1387             else
1388             {
1389                 content_full_description = g_strdup_printf ("%s (%s)", content_description, mime_type);
1390             }
1391 
1392             g_free (content_type);
1393             g_free (mime_type);
1394             g_free (content_description);
1395 
1396             file = xed_document_get_file (doc);
1397             enc = gtk_source_file_get_encoding (file);
1398 
1399             if (enc == NULL)
1400             {
1401                 enc = gtk_source_encoding_get_utf8 ();
1402             }
1403 
1404             encoding = gtk_source_encoding_to_string (enc);
1405 
1406             tip =  g_markup_printf_escaped ("<b>%s</b> %s\n\n"
1407                                             "<b>%s</b> %s\n"
1408                                             "<b>%s</b> %s",
1409                                             _("Name:"), ruri,
1410                                             _("MIME Type:"), content_full_description,
1411                                             _("Encoding:"), encoding);
1412 
1413             g_free (encoding);
1414             g_free (content_full_description);
1415 
1416             break;
1417     }
1418 
1419     g_free (ruri);
1420     g_free (ruri_markup);
1421 
1422     return tip;
1423 }
1424 
1425 static GdkPixbuf *
get_icon(GtkIconTheme * theme,GFile * location,gint size)1426 get_icon (GtkIconTheme *theme,
1427           GFile        *location,
1428           gint          size)
1429 {
1430     GdkPixbuf *pixbuf;
1431     GtkIconInfo *icon_info;
1432     GFileInfo *info;
1433     GIcon *gicon;
1434 
1435     if (location == NULL)
1436     {
1437         return gtk_icon_theme_load_icon (theme, "text-x-generic", size, 0, NULL);
1438     }
1439 
1440     /* FIXME: Doing a sync stat is bad, this should be fixed */
1441     info = g_file_query_info (location,
1442                               G_FILE_ATTRIBUTE_STANDARD_ICON,
1443                               G_FILE_QUERY_INFO_NONE,
1444                               NULL,
1445                               NULL);
1446     if (info == NULL)
1447     {
1448         return gtk_icon_theme_load_icon (theme, "text-x-generic", size, 0, NULL);
1449     }
1450 
1451     gicon = g_file_info_get_icon (info);
1452 
1453     if (gicon == NULL)
1454     {
1455         g_object_unref (info);
1456         return gtk_icon_theme_load_icon (theme, "text-x-generic", size, 0, NULL);
1457     }
1458 
1459     icon_info = gtk_icon_theme_lookup_by_gicon (theme, gicon, size, 0);
1460     g_object_unref (info);
1461 
1462     if (icon_info == NULL)
1463     {
1464         return gtk_icon_theme_load_icon (theme, "text-x-generic", size, 0, NULL);
1465     }
1466 
1467     pixbuf = gtk_icon_info_load_icon (icon_info, NULL);
1468     g_object_unref (icon_info);
1469 
1470     if (pixbuf == NULL)
1471     {
1472         return gtk_icon_theme_load_icon (theme, "text-x-generic", size, 0, NULL);
1473     }
1474 
1475     return pixbuf;
1476 }
1477 
1478 /* FIXME: add support for theme changed. I think it should be as easy as
1479    call g_object_notify (tab, "name") when the icon theme changes */
1480 GdkPixbuf *
_xed_tab_get_icon(XedTab * tab)1481 _xed_tab_get_icon (XedTab *tab)
1482 {
1483     GdkScreen *screen;
1484     GtkIconTheme *theme;
1485     gint icon_size;
1486     const gchar *icon_name;
1487     GdkPixbuf *pixbuf = NULL;
1488 
1489     g_return_val_if_fail (XED_IS_TAB (tab), NULL);
1490 
1491     screen = gtk_widget_get_screen (GTK_WIDGET (tab));
1492     theme = gtk_icon_theme_get_for_screen (screen);
1493     g_return_val_if_fail (theme != NULL, NULL);
1494 
1495     gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &icon_size);
1496 
1497     switch (tab->priv->state)
1498     {
1499         case XED_TAB_STATE_LOADING:
1500             icon_name = "document-open-symbolic";
1501             break;
1502 
1503         case XED_TAB_STATE_REVERTING:
1504             icon_name = "document-revert-symbolic";
1505             break;
1506 
1507         case XED_TAB_STATE_SAVING:
1508             icon_name = "document-save-symbolic";
1509             break;
1510 
1511         case XED_TAB_STATE_PRINTING:
1512             icon_name = "printer-printing-symbolic";
1513             break;
1514 
1515         case XED_TAB_STATE_PRINT_PREVIEWING:
1516         case XED_TAB_STATE_SHOWING_PRINT_PREVIEW:
1517             icon_name = "printer-symbolic";
1518             break;
1519 
1520         case XED_TAB_STATE_LOADING_ERROR:
1521         case XED_TAB_STATE_REVERTING_ERROR:
1522         case XED_TAB_STATE_SAVING_ERROR:
1523         case XED_TAB_STATE_GENERIC_ERROR:
1524             icon_name = "dialog-error-symbolic";
1525             break;
1526 
1527         case XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION:
1528             icon_name = "dialog-warning-symbolic";
1529             break;
1530 
1531         default:
1532             icon_name = NULL;
1533     }
1534 
1535     if (icon_name != NULL)
1536     {
1537         pixbuf = gtk_icon_theme_load_icon (theme, icon_name, icon_size, 0, NULL);
1538     }
1539     else
1540     {
1541         GFile *location;
1542         XedDocument *doc;
1543 
1544         doc = xed_tab_get_document (tab);
1545         location = xed_document_get_location (doc);
1546         pixbuf = get_icon (theme, location, icon_size);
1547     }
1548 
1549     return pixbuf;
1550 }
1551 
1552 /**
1553  * xed_tab_get_from_document:
1554  * @doc: a #XedDocument
1555  *
1556  * Gets the #XedTab associated with @doc.
1557  *
1558  * Returns: (transfer none): the #XedTab associated with @doc
1559  */
1560 XedTab *
xed_tab_get_from_document(XedDocument * doc)1561 xed_tab_get_from_document (XedDocument *doc)
1562 {
1563     gpointer res;
1564 
1565     g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
1566 
1567     res = g_object_get_data (G_OBJECT (doc), XED_TAB_KEY);
1568 
1569     return (res != NULL) ? XED_TAB (res) : NULL;
1570 }
1571 
1572 static void
loader_progress_cb(goffset size,goffset total_size,XedTab * tab)1573 loader_progress_cb (goffset  size,
1574                     goffset  total_size,
1575                     XedTab  *tab)
1576 {
1577     gdouble elapsed_time;
1578     gdouble total_time;
1579     gdouble remaining_time;
1580 
1581     g_return_if_fail (tab->priv->state == XED_TAB_STATE_LOADING ||
1582                       tab->priv->state == XED_TAB_STATE_REVERTING);
1583 
1584     if (tab->priv->timer == NULL)
1585     {
1586         tab->priv->timer = g_timer_new ();
1587     }
1588 
1589     elapsed_time = g_timer_elapsed (tab->priv->timer, NULL);
1590 
1591     /* elapsed_time / total_time = size / total_size */
1592     total_time = (elapsed_time * total_size) / size;
1593 
1594     remaining_time = total_time - elapsed_time;
1595 
1596     /* Approximately more than 3 seconds remaining. */
1597     if (remaining_time > 3.0)
1598     {
1599         show_loading_info_bar (tab);
1600     }
1601 
1602     info_bar_set_progress (tab, size, total_size);
1603 }
1604 
1605 static void
goto_line(XedTab * tab)1606 goto_line (XedTab *tab)
1607 {
1608     XedDocument *doc = xed_tab_get_document (tab);
1609     GtkTextIter iter;
1610 
1611     /* Move the cursor at the requested line if any. */
1612     if (tab->priv->tmp_line_pos > 0)
1613     {
1614         xed_document_goto_line_offset (doc, tab->priv->tmp_line_pos - 1, 0);
1615         return;
1616     }
1617 
1618     /* If enabled, move to the position stored in the metadata. */
1619     if (g_settings_get_boolean (tab->priv->editor, XED_SETTINGS_RESTORE_CURSOR_POSITION))
1620     {
1621         gchar *pos;
1622         gint offset;
1623 
1624         pos = xed_document_get_metadata (doc, XED_METADATA_ATTRIBUTE_POSITION);
1625 
1626         offset = pos != NULL ? atoi (pos) : 0;
1627         g_free (pos);
1628 
1629         gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &iter, MAX (0, offset));
1630 
1631         /* make sure it's a valid position, if the file
1632         * changed we may have ended up in the middle of
1633         * a utf8 character cluster */
1634         if (!gtk_text_iter_is_cursor_position (&iter))
1635         {
1636             gtk_text_iter_set_line_offset (&iter, 0);
1637         }
1638     }
1639 
1640     /* Otherwise to the top. */
1641     else
1642     {
1643         gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (doc), &iter);
1644     }
1645 
1646     gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc), &iter);
1647 }
1648 
1649 static void
load_cb(GtkSourceFileLoader * loader,GAsyncResult * result,XedTab * tab)1650 load_cb (GtkSourceFileLoader *loader,
1651          GAsyncResult        *result,
1652          XedTab              *tab)
1653 {
1654     XedDocument *doc = xed_tab_get_document (tab);
1655     GFile *location = gtk_source_file_loader_get_location (loader);
1656     gboolean create_named_new_doc;
1657     GError *error = NULL;
1658 
1659     g_return_if_fail (tab->priv->state == XED_TAB_STATE_LOADING ||
1660                       tab->priv->state == XED_TAB_STATE_REVERTING);
1661 
1662     gtk_source_file_loader_load_finish (loader, result, &error);
1663 
1664     if (error != NULL)
1665     {
1666         xed_debug_message (DEBUG_TAB, "File loading error: %s", error->message);
1667     }
1668 
1669     if (tab->priv->timer != NULL)
1670     {
1671         g_timer_destroy (tab->priv->timer);
1672         tab->priv->timer = NULL;
1673     }
1674 
1675     set_info_bar (tab, NULL);
1676 
1677     /* Load was successful. */
1678     if (error == NULL ||
1679        (error->domain == GTK_SOURCE_FILE_LOADER_ERROR &&
1680         error->code == GTK_SOURCE_FILE_LOADER_ERROR_CONVERSION_FALLBACK))
1681     {
1682         if (tab->priv->user_requested_encoding)
1683         {
1684             const GtkSourceEncoding *encoding = gtk_source_file_loader_get_encoding (loader);
1685             const gchar *charset = gtk_source_encoding_get_charset (encoding);
1686 
1687             xed_document_set_metadata (doc, XED_METADATA_ATTRIBUTE_ENCODING, charset, NULL);
1688         }
1689 
1690         goto_line (tab);
1691     }
1692 
1693     /* Special case creating a named new doc. */
1694     create_named_new_doc = (_xed_document_get_create (doc) &&
1695                             error != NULL &&
1696                             error->domain == G_IO_ERROR &&
1697                             error->code == G_IO_ERROR_NOT_FOUND &&
1698                             g_file_has_uri_scheme (location, "file"));
1699 
1700     if (create_named_new_doc)
1701     {
1702         g_error_free (error);
1703         error = NULL;
1704     }
1705 
1706     /* If the error is CONVERSION FALLBACK don't treat it as a normal error. */
1707     if (error != NULL &&
1708        (error->domain != GTK_SOURCE_FILE_LOADER_ERROR ||
1709         error->code != GTK_SOURCE_FILE_LOADER_ERROR_CONVERSION_FALLBACK))
1710     {
1711         if (tab->priv->state == XED_TAB_STATE_LOADING)
1712         {
1713             xed_tab_set_state (tab, XED_TAB_STATE_LOADING_ERROR);
1714         }
1715         else
1716         {
1717             xed_tab_set_state (tab, XED_TAB_STATE_REVERTING_ERROR);
1718         }
1719 
1720         if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED)
1721         {
1722             remove_tab (tab);
1723         }
1724         else
1725         {
1726             GtkWidget *info_bar;
1727 
1728             if (location != NULL)
1729             {
1730                 _xed_recent_remove (XED_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tab))), location);
1731             }
1732 
1733             if (tab->priv->state == XED_TAB_STATE_LOADING_ERROR)
1734             {
1735                 const GtkSourceEncoding *encoding;
1736 
1737                 encoding = gtk_source_file_loader_get_encoding (loader);
1738 
1739                 info_bar = xed_io_loading_error_info_bar_new (location, encoding, error);
1740 
1741                 g_signal_connect (info_bar, "response",
1742                                   G_CALLBACK (io_loading_error_info_bar_response), tab);
1743             }
1744             else
1745             {
1746                 g_return_if_fail (tab->priv->state == XED_TAB_STATE_REVERTING_ERROR);
1747 
1748                 info_bar = xed_unrecoverable_reverting_error_info_bar_new (location, error);
1749 
1750                 g_signal_connect (info_bar, "response",
1751                                   G_CALLBACK (unrecoverable_reverting_error_info_bar_response), tab);
1752             }
1753 
1754             set_info_bar (tab, info_bar);
1755             gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar), GTK_RESPONSE_CANCEL);
1756             gtk_widget_show (info_bar);
1757         }
1758 
1759         goto end;
1760     }
1761 
1762     if (location != NULL && !create_named_new_doc)
1763     {
1764         gchar *mime = xed_document_get_mime_type (doc);
1765 
1766         _xed_recent_add (XED_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tab))), location, mime);
1767         g_free (mime);
1768     }
1769 
1770     if (error != NULL &&
1771         error->domain == GTK_SOURCE_FILE_LOADER_ERROR &&
1772         error->code == GTK_SOURCE_FILE_LOADER_ERROR_CONVERSION_FALLBACK)
1773     {
1774         GtkWidget *info_bar;
1775         const GtkSourceEncoding *encoding;
1776 
1777         /* Set the tab as not editable as we have an error, the user can
1778         * decide to make it editable again.
1779         */
1780         tab->priv->editable = FALSE;
1781 
1782         encoding = gtk_source_file_loader_get_encoding (loader);
1783 
1784         info_bar = xed_io_loading_error_info_bar_new (location, encoding, error);
1785 
1786         g_signal_connect (info_bar, "response",
1787                          G_CALLBACK (io_loading_error_info_bar_response), tab);
1788 
1789         set_info_bar (tab, info_bar);
1790         gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar), GTK_RESPONSE_CANCEL);
1791         gtk_widget_show (info_bar);
1792     }
1793 
1794     /* Scroll to the cursor when the document is loaded, we need to do it in
1795     * an idle as after the document is loaded the textview is still
1796     * redrawing and relocating its internals.
1797     */
1798     if (tab->priv->idle_scroll == 0)
1799     {
1800        tab->priv->idle_scroll = g_idle_add ((GSourceFunc)scroll_to_cursor, tab);
1801     }
1802 
1803     /* If the document is readonly we don't care how many times the document
1804     * is opened.
1805     */
1806     if (!xed_document_get_readonly (doc))
1807     {
1808         GList *all_documents;
1809         GList *l;
1810 
1811         all_documents = xed_app_get_documents (XED_APP (g_application_get_default ()));
1812 
1813         for (l = all_documents; l != NULL; l = g_list_next (l))
1814         {
1815             XedDocument *cur_doc = l->data;
1816 
1817             if (cur_doc != doc)
1818             {
1819                 GtkSourceFile *cur_file = xed_document_get_file (cur_doc);
1820                 GFile *cur_location = gtk_source_file_get_location (cur_file);
1821 
1822                 if (cur_location != NULL && location != NULL && g_file_equal (location, cur_location))
1823                 {
1824                     GtkWidget *info_bar;
1825 
1826                     tab->priv->editable = FALSE;
1827 
1828                     info_bar = xed_file_already_open_warning_info_bar_new (location);
1829 
1830                     g_signal_connect (info_bar, "response",
1831                                       G_CALLBACK (file_already_open_warning_info_bar_response), tab);
1832 
1833                     set_info_bar (tab, info_bar);
1834                     gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar), GTK_RESPONSE_CANCEL);
1835                     gtk_widget_show (info_bar);
1836 
1837                     break;
1838                 }
1839             }
1840         }
1841 
1842        g_list_free (all_documents);
1843     }
1844 
1845     xed_tab_set_state (tab, XED_TAB_STATE_NORMAL);
1846 
1847     if (location == NULL)
1848     {
1849        /* FIXME: hackish */
1850        gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (doc), TRUE);
1851     }
1852 
1853     tab->priv->ask_if_externally_modified = TRUE;
1854 
1855     if (error == NULL)
1856     {
1857        clear_loading (tab);
1858     }
1859 
1860     g_signal_emit_by_name (doc, "loaded");
1861 
1862 end:
1863     /* Async operation finished. */
1864     g_object_unref (tab);
1865 
1866     if (error != NULL)
1867     {
1868         g_error_free (error);
1869     }
1870 }
1871 
1872 static GSList *
get_candidate_encodings(XedTab * tab)1873 get_candidate_encodings (XedTab *tab)
1874 {
1875     XedDocument *doc;
1876     GSettings *enc_settings;
1877     gchar **enc_strv;
1878     gchar *metadata_charset;
1879     GtkSourceFile *file;
1880     const GtkSourceEncoding *file_encoding;
1881     GSList *encodings;
1882 
1883     enc_settings = g_settings_new ("org.x.editor.preferences.encodings");
1884 
1885     enc_strv = g_settings_get_strv (enc_settings, XED_SETTINGS_ENCODING_AUTO_DETECTED);
1886 
1887     encodings = _xed_utils_encoding_strv_to_list ((const gchar * const *)enc_strv);
1888 
1889     doc = xed_tab_get_document (tab);
1890     metadata_charset = xed_document_get_metadata (doc, XED_METADATA_ATTRIBUTE_ENCODING);
1891 
1892     if (metadata_charset != NULL)
1893     {
1894         const GtkSourceEncoding *metadata_enc;
1895 
1896         metadata_enc = gtk_source_encoding_get_from_charset (metadata_charset);
1897 
1898         if (metadata_enc != NULL)
1899         {
1900             encodings = g_slist_prepend (encodings, (gpointer)metadata_enc);
1901         }
1902     }
1903 
1904     file = xed_document_get_file (doc);
1905     file_encoding = gtk_source_file_get_encoding (file);
1906 
1907     if (file_encoding != NULL)
1908     {
1909         encodings = g_slist_prepend (encodings, (gpointer)file_encoding);
1910     }
1911 
1912     g_object_unref (enc_settings);
1913     g_strfreev (enc_strv);
1914     g_free (metadata_charset);
1915 
1916     return encodings;
1917 }
1918 
1919 static void
load(XedTab * tab,const GtkSourceEncoding * encoding,gint line_pos)1920 load (XedTab                  *tab,
1921       const GtkSourceEncoding *encoding,
1922       gint                     line_pos)
1923 {
1924     GSList *candidate_encodings = NULL;
1925     XedDocument *doc;
1926 
1927     g_return_if_fail (GTK_SOURCE_IS_FILE_LOADER (tab->priv->loader));
1928 
1929     if (encoding != NULL)
1930     {
1931         tab->priv->user_requested_encoding = TRUE;
1932         candidate_encodings = g_slist_append (NULL, (gpointer) encoding);
1933     }
1934     else
1935     {
1936         tab->priv->user_requested_encoding = FALSE;
1937         candidate_encodings = get_candidate_encodings (tab);
1938     }
1939 
1940     gtk_source_file_loader_set_candidate_encodings (tab->priv->loader, candidate_encodings);
1941     g_slist_free (candidate_encodings);
1942 
1943     tab->priv->tmp_line_pos = line_pos;
1944 
1945     g_clear_object (&tab->priv->cancellable);
1946     tab->priv->cancellable = g_cancellable_new ();
1947 
1948     doc = xed_tab_get_document (tab);
1949     g_signal_emit_by_name (doc, "load");
1950 
1951     /* Keep the tab alive during the async operation. */
1952     g_object_ref (tab);
1953 
1954     gtk_source_file_loader_load_async (tab->priv->loader,
1955                                        G_PRIORITY_DEFAULT,
1956                                        tab->priv->cancellable,
1957                                        (GFileProgressCallback) loader_progress_cb,
1958                                        tab,
1959                                        NULL,
1960                                        (GAsyncReadyCallback) load_cb,
1961                                        tab);
1962 }
1963 
1964 void
_xed_tab_load(XedTab * tab,GFile * location,const GtkSourceEncoding * encoding,gint line_pos,gboolean create)1965 _xed_tab_load (XedTab                  *tab,
1966                GFile                   *location,
1967                const GtkSourceEncoding *encoding,
1968                gint                     line_pos,
1969                gboolean                 create)
1970 {
1971     XedDocument *doc;
1972     GtkSourceFile *file;
1973 
1974     g_return_if_fail (XED_IS_TAB (tab));
1975     g_return_if_fail (G_IS_FILE (location));
1976     g_return_if_fail (tab->priv->state == XED_TAB_STATE_NORMAL);
1977 
1978     xed_tab_set_state (tab, XED_TAB_STATE_LOADING);
1979 
1980     doc = xed_tab_get_document (tab);
1981     file = xed_document_get_file (doc);
1982 
1983     if (tab->priv->loader != NULL)
1984     {
1985         g_warning ("XedTab: file loader already exists.");
1986         g_object_unref (tab->priv->loader);
1987     }
1988 
1989     gtk_source_file_set_location (file, location);
1990     tab->priv->loader = gtk_source_file_loader_new (GTK_SOURCE_BUFFER (doc), file);
1991 
1992     _xed_document_set_create (doc, create);
1993 
1994     load (tab, encoding, line_pos);
1995 }
1996 
1997 void
_xed_tab_load_stream(XedTab * tab,GInputStream * stream,const GtkSourceEncoding * encoding,gint line_pos)1998 _xed_tab_load_stream (XedTab                  *tab,
1999                       GInputStream            *stream,
2000                       const GtkSourceEncoding *encoding,
2001                       gint                     line_pos)
2002 {
2003     XedDocument *doc;
2004     GtkSourceFile *file;
2005 
2006     g_return_if_fail (XED_IS_TAB (tab));
2007     g_return_if_fail (G_IS_INPUT_STREAM (stream));
2008     g_return_if_fail (tab->priv->state == XED_TAB_STATE_NORMAL);
2009 
2010     xed_tab_set_state (tab, XED_TAB_STATE_LOADING);
2011 
2012     doc = xed_tab_get_document (tab);
2013     file = xed_document_get_file (doc);
2014 
2015     if (tab->priv->loader != NULL)
2016     {
2017         g_warning ("XedTab: file loader already exists.");
2018         g_object_unref (tab->priv->loader);
2019     }
2020 
2021     gtk_source_file_set_location (file, NULL);
2022 
2023     tab->priv->loader = gtk_source_file_loader_new_from_stream (GTK_SOURCE_BUFFER (doc), file, stream);
2024 
2025     _xed_document_set_create (doc, FALSE);
2026 
2027     load (tab, encoding, line_pos);
2028 }
2029 
2030 void
_xed_tab_revert(XedTab * tab)2031 _xed_tab_revert (XedTab *tab)
2032 {
2033     XedDocument *doc;
2034     GtkSourceFile *file;
2035     GFile *location;
2036 
2037     g_return_if_fail (XED_IS_TAB (tab));
2038     g_return_if_fail (tab->priv->state == XED_TAB_STATE_NORMAL ||
2039                       tab->priv->state == XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION);
2040 
2041     if (tab->priv->state == XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION)
2042     {
2043         set_info_bar (tab, NULL);
2044     }
2045 
2046     doc = xed_tab_get_document (tab);
2047     file = xed_document_get_file (doc);
2048     location = gtk_source_file_get_location (file);
2049     g_return_if_fail (location != NULL);
2050 
2051     xed_tab_set_state (tab, XED_TAB_STATE_REVERTING);
2052 
2053     if (tab->priv->loader != NULL)
2054     {
2055         g_warning ("XedTab: file loader already exists.");
2056         g_object_unref (tab->priv->loader);
2057     }
2058 
2059     tab->priv->loader = gtk_source_file_loader_new (GTK_SOURCE_BUFFER (doc), file);
2060 
2061     load (tab, NULL, 0);
2062 }
2063 
2064 static void
saver_progress_cb(goffset size,goffset total_size,XedTab * tab)2065 saver_progress_cb (goffset size,
2066                    goffset total_size,
2067                    XedTab *tab)
2068 {
2069     gdouble elapsed_time;
2070     gdouble total_time;
2071     gdouble remaining_time;
2072 
2073     g_return_if_fail (tab->priv->state == XED_TAB_STATE_SAVING);
2074 
2075     if (tab->priv->timer == NULL)
2076     {
2077         tab->priv->timer = g_timer_new ();
2078     }
2079 
2080     elapsed_time = g_timer_elapsed (tab->priv->timer, NULL);
2081 
2082     /* elapsed_time / total_time = size / total_size */
2083     total_time = (elapsed_time * total_size) / size;
2084 
2085     remaining_time = total_time - elapsed_time;
2086 
2087     /* Approximately more than 3 seconds remaining. */
2088     if (remaining_time > 3.0)
2089     {
2090         show_saving_info_bar (tab);
2091     }
2092 
2093     info_bar_set_progress (tab, size, total_size);
2094 }
2095 
2096 static void
save_cb(GtkSourceFileSaver * saver,GAsyncResult * result,XedTab * tab)2097 save_cb (GtkSourceFileSaver *saver,
2098          GAsyncResult       *result,
2099          XedTab             *tab)
2100 {
2101     XedDocument *doc = xed_tab_get_document (tab);
2102     GFile *location = gtk_source_file_saver_get_location (saver);
2103     GError *error = NULL;
2104 
2105     g_return_if_fail (tab->priv->task_saver != NULL);
2106 
2107     gtk_source_file_saver_save_finish (saver, result, &error);
2108 
2109     if (error != NULL)
2110     {
2111         xed_debug_message (DEBUG_TAB, "File saving error: %s", error->message);
2112     }
2113 
2114     if (tab->priv->timer != NULL)
2115     {
2116         g_timer_destroy (tab->priv->timer);
2117         tab->priv->timer = NULL;
2118     }
2119 
2120     set_info_bar (tab, NULL);
2121 
2122     if (error != NULL)
2123     {
2124         GtkWidget *info_bar;
2125 
2126         xed_tab_set_state (tab, XED_TAB_STATE_SAVING_ERROR);
2127 
2128         if (error->domain == GTK_SOURCE_FILE_SAVER_ERROR &&
2129             error->code == GTK_SOURCE_FILE_SAVER_ERROR_EXTERNALLY_MODIFIED)
2130         {
2131             /* This error is recoverable */
2132             info_bar = xed_externally_modified_saving_error_info_bar_new (location, error);
2133             g_return_if_fail (info_bar != NULL);
2134 
2135             g_signal_connect (info_bar, "response",
2136                               G_CALLBACK (externally_modified_error_info_bar_response), tab);
2137         }
2138         else if (error->domain == G_IO_ERROR &&
2139                  error->code == G_IO_ERROR_CANT_CREATE_BACKUP)
2140         {
2141             /* This error is recoverable */
2142             info_bar = xed_no_backup_saving_error_info_bar_new (location, error);
2143             g_return_if_fail (info_bar != NULL);
2144 
2145             g_signal_connect (info_bar, "response",
2146                               G_CALLBACK (no_backup_error_info_bar_response), tab);
2147         }
2148         else if (error->domain == GTK_SOURCE_FILE_SAVER_ERROR &&
2149                  error->code == GTK_SOURCE_FILE_SAVER_ERROR_INVALID_CHARS)
2150         {
2151             /* If we have any invalid char in the document we must warn the user
2152              * as it can make the document useless if it is saved.
2153              */
2154             info_bar = xed_invalid_character_info_bar_new (location);
2155             g_return_if_fail (info_bar != NULL);
2156 
2157             g_signal_connect (info_bar, "response",
2158                               G_CALLBACK (invalid_character_info_bar_response), tab);
2159         }
2160         else if (error->domain == GTK_SOURCE_FILE_SAVER_ERROR ||
2161                  (error->domain == G_IO_ERROR &&
2162                  error->code != G_IO_ERROR_INVALID_DATA &&
2163                  error->code != G_IO_ERROR_PARTIAL_INPUT))
2164         {
2165             /* These errors are _NOT_ recoverable */
2166             _xed_recent_remove (XED_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tab))), location);
2167 
2168             info_bar = xed_unrecoverable_saving_error_info_bar_new (location, error);
2169             g_return_if_fail (info_bar != NULL);
2170 
2171             g_signal_connect (info_bar, "response",
2172                               G_CALLBACK (unrecoverable_saving_error_info_bar_response), tab);
2173         }
2174         else
2175         {
2176             const GtkSourceEncoding *encoding;
2177 
2178             /* This error is recoverable */
2179             g_return_if_fail (error->domain == G_CONVERT_ERROR || error->domain == G_IO_ERROR);
2180 
2181             encoding = gtk_source_file_saver_get_encoding (saver);
2182 
2183             info_bar = xed_conversion_error_while_saving_info_bar_new (location, encoding, error);
2184             g_return_if_fail (info_bar != NULL);
2185 
2186             g_signal_connect (info_bar, "response",
2187                               G_CALLBACK (recoverable_saving_error_info_bar_response), tab);
2188         }
2189 
2190         set_info_bar (tab, info_bar);
2191         gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar), GTK_RESPONSE_CANCEL);
2192         gtk_widget_show (info_bar);
2193     }
2194     else
2195     {
2196         gchar *mime = xed_document_get_mime_type (doc);
2197 
2198         _xed_recent_add (XED_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tab))), location, mime);
2199         g_free (mime);
2200 
2201         if (tab->priv->print_preview != NULL)
2202         {
2203             xed_tab_set_state (tab, XED_TAB_STATE_SHOWING_PRINT_PREVIEW);
2204         }
2205         else
2206         {
2207             xed_tab_set_state (tab, XED_TAB_STATE_NORMAL);
2208         }
2209 
2210         tab->priv->ask_if_externally_modified = TRUE;
2211 
2212         g_signal_emit_by_name (doc, "saved");
2213         g_task_return_boolean (tab->priv->task_saver, TRUE);
2214     }
2215 
2216     if (error != NULL)
2217     {
2218         g_error_free (error);
2219     }
2220 }
2221 
2222 static void
save(XedTab * tab)2223 save (XedTab *tab)
2224 {
2225     XedDocument *doc;
2226     SaverData *data;
2227 
2228     g_return_if_fail (G_IS_TASK (tab->priv->task_saver));
2229 
2230     xed_tab_set_state (tab, XED_TAB_STATE_SAVING);
2231 
2232     doc = xed_tab_get_document (tab);
2233     g_signal_emit_by_name (doc, "save");
2234 
2235     data = g_task_get_task_data (tab->priv->task_saver);
2236 
2237     gtk_source_file_saver_save_async (data->saver,
2238                                       G_PRIORITY_DEFAULT,
2239                                       g_task_get_cancellable (tab->priv->task_saver),
2240                                       (GFileProgressCallback) saver_progress_cb,
2241                                       tab,
2242                                       NULL,
2243                                       (GAsyncReadyCallback) save_cb,
2244                                       tab);
2245 }
2246 
2247 /* Gets the initial save flags, when launching a new FileSaver. */
2248 static GtkSourceFileSaverFlags
get_initial_save_flags(XedTab * tab,gboolean auto_save)2249 get_initial_save_flags (XedTab   *tab,
2250                         gboolean  auto_save)
2251 {
2252     GtkSourceFileSaverFlags save_flags;
2253     gboolean create_backup;
2254 
2255     save_flags = tab->priv->save_flags;
2256 
2257     create_backup = g_settings_get_boolean (tab->priv->editor, XED_SETTINGS_CREATE_BACKUP_COPY);
2258 
2259     /* In case of autosaving, we need to preserve the backup that was produced
2260     * the last time the user "manually" saved the file. So we don't set the
2261     * CREATE_BACKUP flag for an automatic file saving.
2262     */
2263     if (create_backup && !auto_save)
2264     {
2265        save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_CREATE_BACKUP;
2266     }
2267 
2268     return save_flags;
2269 }
2270 
2271 void
_xed_tab_save_async(XedTab * tab,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2272 _xed_tab_save_async (XedTab              *tab,
2273                      GCancellable        *cancellable,
2274                      GAsyncReadyCallback  callback,
2275                      gpointer             user_data)
2276 {
2277     SaverData *data;
2278     XedDocument *doc;
2279     GtkSourceFile *file;
2280     GtkSourceFileSaverFlags save_flags;
2281 
2282     g_return_if_fail (XED_IS_TAB (tab));
2283     g_return_if_fail ((tab->priv->state == XED_TAB_STATE_NORMAL) ||
2284                       (tab->priv->state == XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
2285                       (tab->priv->state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW));
2286 
2287     if (tab->priv->task_saver != NULL)
2288     {
2289         g_warning ("XedTab: file saver already exists.");
2290         return;
2291     }
2292 
2293     doc = xed_tab_get_document (tab);
2294     // g_return_if_fail (XED_IS_DOCUMENT (doc));
2295     g_return_if_fail (!xed_document_is_untitled (doc));
2296 
2297     tab->priv->task_saver = g_task_new (tab, cancellable, callback, user_data);
2298 
2299     data = saver_data_new ();
2300     g_task_set_task_data (tab->priv->task_saver,
2301                           data,
2302                           (GDestroyNotify) saver_data_free);
2303 
2304     save_flags = get_initial_save_flags (tab, FALSE);
2305 
2306     if (tab->priv->state == XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION)
2307     {
2308         /* We already told the user about the external modification:
2309          * hide the message bar and set the save flag.
2310          */
2311 
2312         set_info_bar (tab, NULL);
2313         save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_MODIFICATION_TIME;
2314     }
2315 
2316     file = xed_document_get_file (doc);
2317 
2318     data->saver = gtk_source_file_saver_new (GTK_SOURCE_BUFFER (doc), file);
2319     gtk_source_file_saver_set_flags (data->saver, save_flags);
2320 
2321     save (tab);
2322 }
2323 
2324 gboolean
_xed_tab_save_finish(XedTab * tab,GAsyncResult * result)2325 _xed_tab_save_finish (XedTab       *tab,
2326                       GAsyncResult *result)
2327 {
2328     gboolean success;
2329 
2330     g_return_val_if_fail (g_task_is_valid (result, tab), FALSE);
2331     g_return_val_if_fail (tab->priv->task_saver == G_TASK (result), FALSE);
2332 
2333     success = g_task_propagate_boolean (tab->priv->task_saver, NULL);
2334     g_clear_object (&tab->priv->task_saver);
2335 
2336     return success;
2337 }
2338 
2339 static void
auto_save_finished_cb(XedTab * tab,GAsyncResult * result,gpointer user_data)2340 auto_save_finished_cb (XedTab       *tab,
2341                        GAsyncResult *result,
2342                        gpointer      user_data)
2343 {
2344     _xed_tab_save_finish (tab, result);
2345 }
2346 
2347 static gboolean
xed_tab_auto_save(XedTab * tab)2348 xed_tab_auto_save (XedTab *tab)
2349 {
2350     SaverData *data;
2351     XedDocument *doc;
2352     GtkSourceFile *file;
2353     GtkSourceFileSaverFlags save_flags;
2354 
2355     xed_debug (DEBUG_TAB);
2356 
2357     doc = xed_tab_get_document (tab);
2358     g_return_val_if_fail (!xed_document_is_untitled (doc), G_SOURCE_REMOVE);
2359     g_return_val_if_fail (!xed_document_get_readonly (doc), G_SOURCE_REMOVE);
2360 
2361     if (!gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)))
2362     {
2363         xed_debug_message (DEBUG_TAB, "Document not modified");
2364 
2365         return G_SOURCE_CONTINUE;
2366     }
2367 
2368     if ((tab->priv->state != XED_TAB_STATE_NORMAL) && (tab->priv->state != XED_TAB_STATE_SHOWING_PRINT_PREVIEW))
2369     {
2370         xed_debug_message (DEBUG_TAB, "Retry after 30 seconds");
2371 
2372         tab->priv->auto_save_timeout = g_timeout_add_seconds (30, (GSourceFunc) xed_tab_auto_save, tab);
2373 
2374         /* Destroy the old timeout */
2375         return G_SOURCE_REMOVE;
2376     }
2377 
2378     /* Set auto_save_timeout to 0 since the timeout is going to be destroyed */
2379     tab->priv->auto_save_timeout = 0;
2380 
2381     if (tab->priv->task_saver != NULL)
2382     {
2383         g_warning ("XedTab: file saver already exists.");
2384         return G_SOURCE_REMOVE;
2385     }
2386 
2387     tab->priv->task_saver = g_task_new (tab,
2388                                         NULL,
2389                                         (GAsyncReadyCallback) auto_save_finished_cb,
2390                                         NULL);
2391 
2392     data = saver_data_new ();
2393     g_task_set_task_data (tab->priv->task_saver,
2394                           data,
2395                           (GDestroyNotify) saver_data_free);
2396 
2397     file = xed_document_get_file (doc);
2398 
2399     data->saver = gtk_source_file_saver_new (GTK_SOURCE_BUFFER (doc), file);
2400 
2401     save_flags = get_initial_save_flags (tab, TRUE);
2402     gtk_source_file_saver_set_flags (data->saver, save_flags);
2403 
2404     save (tab);
2405 
2406     return G_SOURCE_REMOVE;
2407 }
2408 
2409 /* Call _xed_tab_save_finish() in @callback, there is no
2410  * _xed_tab_save_as_finish().
2411  */
2412 void
_xed_tab_save_as_async(XedTab * tab,GFile * location,const GtkSourceEncoding * encoding,GtkSourceNewlineType newline_type,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2413 _xed_tab_save_as_async (XedTab                   *tab,
2414                         GFile                    *location,
2415                         const GtkSourceEncoding  *encoding,
2416                         GtkSourceNewlineType      newline_type,
2417                         GCancellable             *cancellable,
2418                         GAsyncReadyCallback       callback,
2419                         gpointer                  user_data)
2420 {
2421     SaverData *data;
2422     XedDocument *doc;
2423     GtkSourceFile *file;
2424     GtkSourceFileSaverFlags save_flags;
2425 
2426     g_return_if_fail (XED_IS_TAB (tab));
2427     g_return_if_fail ((tab->priv->state == XED_TAB_STATE_NORMAL) ||
2428                       (tab->priv->state == XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) ||
2429                       (tab->priv->state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW));
2430     g_return_if_fail (G_IS_FILE (location));
2431     g_return_if_fail (encoding != NULL);
2432 
2433     if (tab->priv->task_saver != NULL)
2434     {
2435         g_warning ("XedTab: file saver already exists.");
2436         return;
2437     }
2438 
2439     tab->priv->task_saver = g_task_new (tab, cancellable, callback, user_data);
2440 
2441     data = saver_data_new ();
2442     g_task_set_task_data (tab->priv->task_saver,
2443                           data,
2444                           (GDestroyNotify) saver_data_free);
2445 
2446     doc = xed_tab_get_document (tab);
2447     g_return_if_fail (XED_IS_DOCUMENT (doc));
2448 
2449     /* reset the save flags, when saving as */
2450     tab->priv->save_flags = GTK_SOURCE_FILE_SAVER_FLAGS_NONE;
2451     save_flags = get_initial_save_flags (tab, FALSE);
2452 
2453     if (tab->priv->state == XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION)
2454     {
2455         /* We already told the user about the external modification:
2456          * hide the message bar and set the save flag.
2457          */
2458 
2459         set_info_bar (tab, NULL);
2460         save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_MODIFICATION_TIME;
2461     }
2462 
2463     file = xed_document_get_file (doc);
2464 
2465     data->saver = gtk_source_file_saver_new_with_target (GTK_SOURCE_BUFFER (doc), file, location);
2466 
2467     gtk_source_file_saver_set_encoding (data->saver, encoding);
2468     gtk_source_file_saver_set_newline_type (data->saver, newline_type);
2469     gtk_source_file_saver_set_flags (data->saver, save_flags);
2470 
2471     save (tab);
2472 }
2473 
2474 #define XED_PAGE_SETUP_KEY "xed-page-setup-key"
2475 #define XED_PRINT_SETTINGS_KEY "xed-print-settings-key"
2476 
2477 static GtkPageSetup *
get_page_setup(XedTab * tab)2478 get_page_setup (XedTab *tab)
2479 {
2480     gpointer data;
2481     XedDocument *doc;
2482 
2483     doc = xed_tab_get_document (tab);
2484     data = g_object_get_data (G_OBJECT (doc), XED_PAGE_SETUP_KEY);
2485 
2486     if (data == NULL)
2487     {
2488         return _xed_app_get_default_page_setup (XED_APP (g_application_get_default ()));
2489     }
2490     else
2491     {
2492         return gtk_page_setup_copy (GTK_PAGE_SETUP (data));
2493     }
2494 }
2495 
2496 static GtkPrintSettings *
get_print_settings(XedTab * tab)2497 get_print_settings (XedTab *tab)
2498 {
2499     gpointer data;
2500     XedDocument *doc;
2501     GtkPrintSettings *settings;
2502     gchar *uri, *name;
2503 
2504     doc = xed_tab_get_document (tab);
2505 
2506     data = g_object_get_data (G_OBJECT (doc), XED_PRINT_SETTINGS_KEY);
2507 
2508     if (data == NULL)
2509     {
2510         settings = _xed_app_get_default_print_settings (XED_APP (g_application_get_default ()));
2511     }
2512     else
2513     {
2514         settings = gtk_print_settings_copy (GTK_PRINT_SETTINGS (data));
2515     }
2516 
2517     name = xed_document_get_short_name_for_display (doc);
2518     uri = g_strconcat ("file://",
2519                        g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS),
2520                        "/", name, ".pdf", NULL);
2521 
2522     gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_OUTPUT_URI, uri);
2523 
2524     g_free (uri);
2525     g_free (name);
2526 
2527     return settings;
2528 }
2529 
2530 /* FIXME: show the message area only if the operation will be "long" */
2531 static void
printing_cb(XedPrintJob * job,XedPrintJobStatus status,XedTab * tab)2532 printing_cb (XedPrintJob       *job,
2533              XedPrintJobStatus  status,
2534              XedTab            *tab)
2535 {
2536     g_return_if_fail (XED_IS_PROGRESS_INFO_BAR (tab->priv->info_bar));
2537 
2538     gtk_widget_show (tab->priv->info_bar);
2539 
2540     xed_progress_info_bar_set_text (XED_PROGRESS_INFO_BAR (tab->priv->info_bar),
2541                                     xed_print_job_get_status_string (job));
2542 
2543     xed_progress_info_bar_set_fraction (XED_PROGRESS_INFO_BAR (tab->priv->info_bar),
2544                                         xed_print_job_get_progress (job));
2545 }
2546 
2547 static void
store_print_settings(XedTab * tab,XedPrintJob * job)2548 store_print_settings (XedTab      *tab,
2549                       XedPrintJob *job)
2550 {
2551     XedDocument *doc;
2552     GtkPrintSettings *settings;
2553     GtkPageSetup *page_setup;
2554 
2555     doc = xed_tab_get_document (tab);
2556 
2557     settings = xed_print_job_get_print_settings (job);
2558 
2559     /* clear n-copies settings since we do not want to
2560      * persist that one */
2561     gtk_print_settings_unset (settings, GTK_PRINT_SETTINGS_N_COPIES);
2562 
2563     /* remember settings for this document */
2564     g_object_set_data_full (G_OBJECT (doc), XED_PRINT_SETTINGS_KEY,
2565                             g_object_ref (settings), (GDestroyNotify)g_object_unref);
2566 
2567     /* make them the default */
2568     _xed_app_set_default_print_settings (XED_APP (g_application_get_default ()), settings);
2569 
2570     page_setup = xed_print_job_get_page_setup (job);
2571 
2572     /* remember page setup for this document */
2573     g_object_set_data_full (G_OBJECT (doc), XED_PAGE_SETUP_KEY,
2574                             g_object_ref (page_setup), (GDestroyNotify)g_object_unref);
2575 
2576     /* make it the default */
2577     _xed_app_set_default_page_setup (XED_APP (g_application_get_default ()), page_setup);
2578 }
2579 
2580 static void
done_printing_cb(XedPrintJob * job,XedPrintJobResult result,const GError * error,XedTab * tab)2581 done_printing_cb (XedPrintJob       *job,
2582                   XedPrintJobResult  result,
2583                   const GError      *error,
2584                   XedTab            *tab)
2585 {
2586     XedView *view;
2587 
2588     g_return_if_fail (tab->priv->state == XED_TAB_STATE_PRINT_PREVIEWING ||
2589                       tab->priv->state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW ||
2590                       tab->priv->state == XED_TAB_STATE_PRINTING);
2591 
2592     if (tab->priv->state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW)
2593     {
2594         /* print preview has been destroyed... */
2595         tab->priv->print_preview = NULL;
2596     }
2597     else
2598     {
2599         g_return_if_fail (XED_IS_PROGRESS_INFO_BAR (tab->priv->info_bar));
2600 
2601         set_info_bar (tab, NULL); /* destroy the message area */
2602     }
2603 
2604     // TODO: check status and error
2605 
2606     if (result ==  XED_PRINT_JOB_RESULT_OK)
2607     {
2608         store_print_settings (tab, job);
2609     }
2610 
2611 #if 0
2612     if (tab->priv->print_preview != NULL)
2613     {
2614         /* If we were printing while showing the print preview,
2615            see bug #352658 */
2616         gtk_widget_destroy (tab->priv->print_preview);
2617         g_return_if_fail (tab->priv->state == XED_TAB_STATE_PRINTING);
2618     }
2619 #endif
2620 
2621     xed_tab_set_state (tab, XED_TAB_STATE_NORMAL);
2622 
2623     view = xed_tab_get_view (tab);
2624     gtk_widget_grab_focus (GTK_WIDGET (view));
2625 
2626     g_object_unref (tab->priv->print_job);
2627     tab->priv->print_job = NULL;
2628 }
2629 
2630 #if 0
2631 static void
2632 print_preview_destroyed (GtkWidget *preview,
2633              XedTab  *tab)
2634 {
2635     tab->priv->print_preview = NULL;
2636 
2637     if (tab->priv->state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW)
2638     {
2639         XedView *view;
2640 
2641         xed_tab_set_state (tab, XED_TAB_STATE_NORMAL);
2642 
2643         view = xed_tab_get_view (tab);
2644         gtk_widget_grab_focus (GTK_WIDGET (view));
2645     }
2646     else
2647     {
2648         /* This should happen only when printing while showing the print
2649          * preview. In this case let us continue whithout changing
2650          * the state and show the document. See bug #352658 */
2651         gtk_widget_show (tab->priv->view_scrolled_window);
2652 
2653         g_return_if_fail (tab->priv->state == XED_TAB_STATE_PRINTING);
2654     }
2655 }
2656 #endif
2657 
2658 static void
show_preview_cb(XedPrintJob * job,XedPrintPreview * preview,XedTab * tab)2659 show_preview_cb (XedPrintJob     *job,
2660                  XedPrintPreview *preview,
2661                  XedTab          *tab)
2662 {
2663 //  g_return_if_fail (tab->priv->state == XED_TAB_STATE_PRINT_PREVIEWING);
2664     g_return_if_fail (tab->priv->print_preview == NULL);
2665 
2666     set_info_bar (tab, NULL); /* destroy the message area */
2667 
2668     tab->priv->print_preview = GTK_WIDGET (preview);
2669     gtk_box_pack_end (GTK_BOX (tab), tab->priv->print_preview, TRUE, TRUE, 0);
2670     gtk_widget_show (tab->priv->print_preview);
2671     gtk_widget_grab_focus (tab->priv->print_preview);
2672 
2673 /* when the preview gets destroyed we get "done" signal
2674     g_signal_connect (tab->priv->print_preview,
2675               "destroy",
2676               G_CALLBACK (print_preview_destroyed),
2677               tab);
2678 */
2679     xed_tab_set_state (tab, XED_TAB_STATE_SHOWING_PRINT_PREVIEW);
2680 }
2681 
2682 #if 0
2683 
2684 static void
2685 set_print_preview (XedTab  *tab,
2686            GtkWidget *print_preview)
2687 {
2688     if (tab->priv->print_preview == print_preview)
2689         return;
2690 
2691     if (tab->priv->print_preview != NULL)
2692         gtk_widget_destroy (tab->priv->print_preview);
2693 
2694     tab->priv->print_preview = print_preview;
2695 
2696     gtk_box_pack_end (GTK_BOX (tab),
2697               tab->priv->print_preview,
2698               TRUE,
2699               TRUE,
2700               0);
2701 
2702     gtk_widget_grab_focus (tab->priv->print_preview);
2703 
2704     g_signal_connect (tab->priv->print_preview,
2705               "destroy",
2706               G_CALLBACK (print_preview_destroyed),
2707               tab);
2708 }
2709 
2710 static void
2711 preview_finished_cb (GtkSourcePrintJob *pjob, XedTab *tab)
2712 {
2713     MatePrintJob *gjob;
2714     GtkWidget *preview = NULL;
2715 
2716     g_return_if_fail (XED_IS_PROGRESS_INFO_BAR (tab->priv->info_bar));
2717     set_info_bar (tab, NULL); /* destroy the message area */
2718 
2719     gjob = gtk_source_print_job_get_print_job (pjob);
2720 
2721     preview = xed_print_job_preview_new (gjob);
2722     g_object_unref (gjob);
2723 
2724     set_print_preview (tab, preview);
2725 
2726     gtk_widget_show (preview);
2727     g_object_unref (pjob);
2728 
2729     xed_tab_set_state (tab, XED_TAB_STATE_SHOWING_PRINT_PREVIEW);
2730 }
2731 
2732 
2733 #endif
2734 
2735 static void
print_cancelled(GtkWidget * area,gint response_id,XedTab * tab)2736 print_cancelled (GtkWidget *area,
2737                  gint       response_id,
2738                  XedTab    *tab)
2739 {
2740     g_return_if_fail (XED_IS_PROGRESS_INFO_BAR (tab->priv->info_bar));
2741 
2742     xed_print_job_cancel (tab->priv->print_job);
2743 
2744     g_debug ("print_cancelled");
2745 }
2746 
2747 static void
show_printing_info_bar(XedTab * tab,gboolean preview)2748 show_printing_info_bar (XedTab   *tab,
2749                         gboolean  preview)
2750 {
2751     GtkWidget *area;
2752 
2753     if (preview)
2754     {
2755         area = xed_progress_info_bar_new ("document-print-preview-symbolic", "", TRUE);
2756     }
2757     else
2758     {
2759         area = xed_progress_info_bar_new ("document-print-symbolic", "", TRUE);
2760     }
2761 
2762     g_signal_connect (area, "response",
2763                       G_CALLBACK (print_cancelled), tab);
2764 
2765     set_info_bar (tab, area);
2766 }
2767 
2768 static void
xed_tab_print_or_print_preview(XedTab * tab,GtkPrintOperationAction print_action)2769 xed_tab_print_or_print_preview (XedTab                  *tab,
2770                                 GtkPrintOperationAction  print_action)
2771 {
2772     XedView *view;
2773     gboolean is_preview;
2774     GtkPageSetup *setup;
2775     GtkPrintSettings *settings;
2776     GtkPrintOperationResult res;
2777     GError *error = NULL;
2778 
2779     g_return_if_fail (tab->priv->print_job == NULL);
2780     g_return_if_fail (tab->priv->state == XED_TAB_STATE_NORMAL);
2781 
2782     view = xed_tab_get_view (tab);
2783 
2784     is_preview = (print_action == GTK_PRINT_OPERATION_ACTION_PREVIEW);
2785 
2786     tab->priv->print_job = xed_print_job_new (view);
2787     g_object_add_weak_pointer (G_OBJECT (tab->priv->print_job), (gpointer *) &tab->priv->print_job);
2788 
2789     show_printing_info_bar (tab, is_preview);
2790 
2791     g_signal_connect (tab->priv->print_job, "printing",
2792                       G_CALLBACK (printing_cb), tab);
2793     g_signal_connect (tab->priv->print_job, "show-preview",
2794                       G_CALLBACK (show_preview_cb), tab);
2795     g_signal_connect (tab->priv->print_job, "done",
2796                       G_CALLBACK (done_printing_cb), tab);
2797 
2798     if (is_preview)
2799     {
2800         xed_tab_set_state (tab, XED_TAB_STATE_PRINT_PREVIEWING);
2801     }
2802     else
2803     {
2804         xed_tab_set_state (tab, XED_TAB_STATE_PRINTING);
2805     }
2806 
2807     setup = get_page_setup (tab);
2808     settings = get_print_settings (tab);
2809 
2810     res = xed_print_job_print (tab->priv->print_job,
2811                                print_action,
2812                                setup,
2813                                settings,
2814                                GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tab))),
2815                                &error);
2816 
2817     // TODO: manage res in the correct way
2818     if (res == GTK_PRINT_OPERATION_RESULT_ERROR)
2819     {
2820         /* FIXME: go in error state */
2821         xed_tab_set_state (tab, XED_TAB_STATE_NORMAL);
2822         g_warning ("Async print preview failed (%s)", error->message);
2823         g_object_unref (tab->priv->print_job);
2824         g_error_free (error);
2825     }
2826 }
2827 
2828 void
_xed_tab_print(XedTab * tab,gboolean with_dialog)2829 _xed_tab_print (XedTab   *tab,
2830                 gboolean  with_dialog)
2831 {
2832     g_return_if_fail (XED_IS_TAB (tab));
2833 
2834     /* FIXME: currently we can have just one printoperation going on
2835      * at a given time, so before starting the print we close the preview.
2836      * Would be nice to handle it properly though */
2837     if (tab->priv->state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW)
2838     {
2839         gtk_widget_destroy (tab->priv->print_preview);
2840     }
2841 
2842     if (with_dialog)
2843     {
2844         xed_tab_print_or_print_preview (tab, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG);
2845     }
2846     else
2847     {
2848         xed_tab_print_or_print_preview (tab, GTK_PRINT_OPERATION_ACTION_PRINT);
2849     }
2850 }
2851 
2852 void
_xed_tab_print_preview(XedTab * tab)2853 _xed_tab_print_preview (XedTab *tab)
2854 {
2855     g_return_if_fail (XED_IS_TAB (tab));
2856 
2857     xed_tab_print_or_print_preview (tab, GTK_PRINT_OPERATION_ACTION_PREVIEW);
2858 }
2859 
2860 void
_xed_tab_mark_for_closing(XedTab * tab)2861 _xed_tab_mark_for_closing (XedTab *tab)
2862 {
2863     g_return_if_fail (XED_IS_TAB (tab));
2864     g_return_if_fail (tab->priv->state == XED_TAB_STATE_NORMAL);
2865 
2866     xed_tab_set_state (tab, XED_TAB_STATE_CLOSING);
2867 }
2868 
2869 gboolean
_xed_tab_get_can_close(XedTab * tab)2870 _xed_tab_get_can_close (XedTab *tab)
2871 {
2872     XedDocument *doc;
2873     XedTabState  ts;
2874 
2875     g_return_val_if_fail (XED_IS_TAB (tab), FALSE);
2876 
2877     ts = xed_tab_get_state (tab);
2878 
2879     /* if we are loading or reverting, the tab can be closed */
2880     if ((ts == XED_TAB_STATE_LOADING)       ||
2881         (ts == XED_TAB_STATE_LOADING_ERROR) ||
2882         (ts == XED_TAB_STATE_REVERTING)     ||
2883         (ts == XED_TAB_STATE_REVERTING_ERROR)) /* CHECK: I'm not sure this is the right behavior for REVERTING ERROR */
2884         {
2885             return TRUE;
2886         }
2887 
2888     /* Do not close tab with saving errors */
2889     if (ts == XED_TAB_STATE_SAVING_ERROR)
2890     {
2891         return FALSE;
2892     }
2893 
2894     doc = xed_tab_get_document (tab);
2895 
2896     if (_xed_document_needs_saving (doc))
2897     {
2898         return FALSE;
2899     }
2900 
2901     return TRUE;
2902 }
2903 
2904 /**
2905  * xed_tab_get_auto_save_enabled:
2906  * @tab: a #XedTab
2907  *
2908  * Gets the current state for the autosave feature
2909  *
2910  * Return value: %TRUE if the autosave is enabled, else %FALSE
2911  **/
2912 gboolean
xed_tab_get_auto_save_enabled(XedTab * tab)2913 xed_tab_get_auto_save_enabled (XedTab *tab)
2914 {
2915     xed_debug (DEBUG_TAB);
2916 
2917     g_return_val_if_fail (XED_IS_TAB (tab), FALSE);
2918 
2919     return tab->priv->auto_save;
2920 }
2921 
2922 /**
2923  * xed_tab_set_auto_save_enabled:
2924  * @tab: a #XedTab
2925  * @enable: enable (%TRUE) or disable (%FALSE) auto save
2926  *
2927  * Enables or disables the autosave feature. It does not install an
2928  * autosave timeout if the document is new or is read-only
2929  **/
2930 void
xed_tab_set_auto_save_enabled(XedTab * tab,gboolean enable)2931 xed_tab_set_auto_save_enabled (XedTab   *tab,
2932                                gboolean  enable)
2933 {
2934     xed_debug (DEBUG_TAB);
2935 
2936     g_return_if_fail (XED_IS_TAB (tab));
2937 
2938     enable = enable != FALSE;
2939 
2940     if (tab->priv->auto_save != enable)
2941     {
2942         tab->priv->auto_save = enable;
2943         update_auto_save_timeout (tab);
2944         return;
2945     }
2946 }
2947 
2948 /**
2949  * xed_tab_get_auto_save_interval:
2950  * @tab: a #XedTab
2951  *
2952  * Gets the current interval for the autosaves
2953  *
2954  * Return value: the value of the autosave
2955  **/
2956 gint
xed_tab_get_auto_save_interval(XedTab * tab)2957 xed_tab_get_auto_save_interval (XedTab *tab)
2958 {
2959     xed_debug (DEBUG_TAB);
2960 
2961     g_return_val_if_fail (XED_IS_TAB (tab), 0);
2962 
2963     return tab->priv->auto_save_interval;
2964 }
2965 
2966 /**
2967  * xed_tab_set_auto_save_interval:
2968  * @tab: a #XedTab
2969  * @interval: the new interval
2970  *
2971  * Sets the interval for the autosave feature.
2972  **/
2973 void
xed_tab_set_auto_save_interval(XedTab * tab,gint interval)2974 xed_tab_set_auto_save_interval (XedTab *tab,
2975                                 gint    interval)
2976 {
2977     g_return_if_fail (XED_IS_TAB (tab));
2978     g_return_if_fail (interval > 0);
2979 
2980     xed_debug (DEBUG_TAB);
2981 
2982     if (tab->priv->auto_save_interval != interval)
2983     {
2984         tab->priv->auto_save_interval = interval;
2985         remove_auto_save_timeout (tab);
2986         update_auto_save_timeout (tab);
2987     }
2988 }
2989 
2990 void
xed_tab_set_info_bar(XedTab * tab,GtkWidget * info_bar)2991 xed_tab_set_info_bar (XedTab    *tab,
2992                       GtkWidget *info_bar)
2993 {
2994     g_return_if_fail (XED_IS_TAB (tab));
2995     g_return_if_fail (info_bar == NULL || GTK_IS_WIDGET (info_bar));
2996 
2997     /* FIXME: this can cause problems with the tab state machine */
2998     set_info_bar (tab, info_bar);
2999 }
3000 
3001 GtkWidget *
_xed_tab_get_view_frame(XedTab * tab)3002 _xed_tab_get_view_frame (XedTab *tab)
3003 {
3004     g_return_val_if_fail (XED_IS_TAB (tab), NULL);
3005 
3006     return GTK_WIDGET (tab->priv->frame);
3007 }
3008