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