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