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