1 /*
2  * pluma-close-confirmation-dialog.c
3  * This file is part of pluma
4  *
5  * Copyright (C) 2004-2005 GNOME Foundation
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, 2004-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  * $Id$
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 
36 #include <glib/gi18n.h>
37 
38 #include "pluma-close-confirmation-dialog.h"
39 #include <pluma/pluma-app.h>
40 #include <pluma/pluma-utils.h>
41 #include <pluma/pluma-window.h>
42 
43 
44 /* Properties */
45 enum
46 {
47 	PROP_0,
48 	PROP_UNSAVED_DOCUMENTS,
49 	PROP_LOGOUT_MODE
50 };
51 
52 /* Mode */
53 enum
54 {
55 	SINGLE_DOC_MODE,
56 	MULTIPLE_DOCS_MODE
57 };
58 
59 /* Columns */
60 enum
61 {
62 	SAVE_COLUMN,
63 	NAME_COLUMN,
64 	DOC_COLUMN, /* a handy pointer to the document */
65 	N_COLUMNS
66 };
67 
68 struct _PlumaCloseConfirmationDialogPrivate
69 {
70 	gboolean     logout_mode;
71 
72 	GList       *unsaved_documents;
73 
74 	GList       *selected_documents;
75 
76 	GtkTreeModel *list_store;
77 
78 	gboolean     disable_save_to_disk;
79 };
80 
81 #define GET_MODE(priv) (((priv->unsaved_documents != NULL) && \
82 			 (priv->unsaved_documents->next == NULL)) ? \
83 			  SINGLE_DOC_MODE : MULTIPLE_DOCS_MODE)
84 
85 G_DEFINE_TYPE_WITH_PRIVATE (PlumaCloseConfirmationDialog, pluma_close_confirmation_dialog, GTK_TYPE_DIALOG)
86 
87 static void 	 set_unsaved_document 		(PlumaCloseConfirmationDialog *dlg,
88 						 const GList                  *list);
89 
90 static GList 	*get_selected_docs 		(GtkTreeModel                 *store);
91 
92 /*  Since we connect in the costructor we are sure this handler will be called
93  *  before the user ones
94  */
95 static void
response_cb(PlumaCloseConfirmationDialog * dlg,gint response_id,gpointer data)96 response_cb (PlumaCloseConfirmationDialog *dlg,
97              gint                          response_id,
98              gpointer                      data)
99 {
100 	PlumaCloseConfirmationDialogPrivate *priv;
101 
102 	g_return_if_fail (PLUMA_IS_CLOSE_CONFIRMATION_DIALOG (dlg));
103 
104 	priv = dlg->priv;
105 
106 	if (priv->selected_documents != NULL)
107 		g_list_free (priv->selected_documents);
108 
109 	if (response_id == GTK_RESPONSE_YES)
110 	{
111 		if (GET_MODE (priv) == SINGLE_DOC_MODE)
112 		{
113 			priv->selected_documents =
114 				g_list_copy (priv->unsaved_documents);
115 		}
116 		else
117 		{
118 			g_return_if_fail (priv->list_store);
119 
120 			priv->selected_documents =
121 				get_selected_docs (priv->list_store);
122 		}
123 	}
124 	else
125 		priv->selected_documents = NULL;
126 }
127 
128 static void
set_logout_mode(PlumaCloseConfirmationDialog * dlg,gboolean logout_mode)129 set_logout_mode (PlumaCloseConfirmationDialog *dlg,
130 		 gboolean                      logout_mode)
131 {
132 	dlg->priv->logout_mode = logout_mode;
133 
134 	if (logout_mode)
135 	{
136 		gtk_dialog_add_button (GTK_DIALOG (dlg),
137 				       _("Log Out _without Saving"),
138 				       GTK_RESPONSE_NO);
139 
140 		pluma_dialog_add_button (GTK_DIALOG (dlg),
141 					 _("_Cancel Logout"),
142 					 "process-stop",
143 					 GTK_RESPONSE_CANCEL);
144 	}
145 	else
146 	{
147 		gtk_dialog_add_button (GTK_DIALOG (dlg),
148 				       _("Close _without Saving"),
149 				       GTK_RESPONSE_NO);
150 
151 		pluma_dialog_add_button (GTK_DIALOG (dlg),
152 					 _("_Cancel"),
153 					 "process-stop",
154 					 GTK_RESPONSE_CANCEL);
155 	}
156 
157 	if (dlg->priv->disable_save_to_disk)
158 	{
159 		gtk_dialog_set_default_response	(GTK_DIALOG (dlg),
160 						 GTK_RESPONSE_NO);
161 	}
162 	else
163 	{
164 		const gchar *icon_id = "document-save";
165 
166 		if (GET_MODE (dlg->priv) == SINGLE_DOC_MODE)
167 		{
168 			PlumaDocument *doc;
169 
170 			doc = PLUMA_DOCUMENT (dlg->priv->unsaved_documents->data);
171 
172 			if (pluma_document_get_readonly (doc) ||
173 			    pluma_document_is_untitled (doc))
174 				icon_id = "document-save-as";
175 		}
176 
177 		if (g_strcmp0 (icon_id, "document-save") == 0)
178 			pluma_dialog_add_button (GTK_DIALOG (dlg),
179 						 _("_Save"),
180 						 icon_id,
181 						 GTK_RESPONSE_YES);
182 		else
183 			pluma_dialog_add_button (GTK_DIALOG (dlg),
184 						 _("Save _As"),
185 						 icon_id,
186 						 GTK_RESPONSE_YES);
187 
188 		gtk_dialog_set_default_response	(GTK_DIALOG (dlg),
189 						 GTK_RESPONSE_YES);
190 	}
191 }
192 
193 static void
pluma_close_confirmation_dialog_init(PlumaCloseConfirmationDialog * dlg)194 pluma_close_confirmation_dialog_init (PlumaCloseConfirmationDialog *dlg)
195 {
196 	AtkObject *atk_obj;
197 
198 	dlg->priv = pluma_close_confirmation_dialog_get_instance_private (dlg);
199 
200 	dlg->priv->disable_save_to_disk =
201 			pluma_app_get_lockdown (pluma_app_get_default ())
202 			& PLUMA_LOCKDOWN_SAVE_TO_DISK;
203 
204 	gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
205 	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
206 			     14);
207 	gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
208 	gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dlg), TRUE);
209 
210 	gtk_window_set_title (GTK_WINDOW (dlg), "");
211 
212 	gtk_window_set_modal (GTK_WINDOW (dlg), TRUE);
213 	gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
214 
215 	atk_obj = gtk_widget_get_accessible (GTK_WIDGET (dlg));
216 	atk_object_set_role (atk_obj, ATK_ROLE_ALERT);
217 	atk_object_set_name (atk_obj, _("Question"));
218 
219 	g_signal_connect (dlg,
220 			  "response",
221 			  G_CALLBACK (response_cb),
222 			  NULL);
223 }
224 
225 static void
pluma_close_confirmation_dialog_finalize(GObject * object)226 pluma_close_confirmation_dialog_finalize (GObject *object)
227 {
228 	PlumaCloseConfirmationDialogPrivate *priv;
229 
230 	priv = PLUMA_CLOSE_CONFIRMATION_DIALOG (object)->priv;
231 
232 	if (priv->unsaved_documents != NULL)
233 		g_list_free (priv->unsaved_documents);
234 
235 	if (priv->selected_documents != NULL)
236 		g_list_free (priv->selected_documents);
237 
238 	/* Call the parent's destructor */
239 	G_OBJECT_CLASS (pluma_close_confirmation_dialog_parent_class)->finalize (object);
240 }
241 
242 static void
pluma_close_confirmation_dialog_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)243 pluma_close_confirmation_dialog_set_property (GObject      *object,
244 					      guint         prop_id,
245 					      const GValue *value,
246 					      GParamSpec   *pspec)
247 {
248 	PlumaCloseConfirmationDialog *dlg;
249 
250 	dlg = PLUMA_CLOSE_CONFIRMATION_DIALOG (object);
251 
252 	switch (prop_id)
253 	{
254 		case PROP_UNSAVED_DOCUMENTS:
255 			set_unsaved_document (dlg, g_value_get_pointer (value));
256 			break;
257 
258 		case PROP_LOGOUT_MODE:
259 			set_logout_mode (dlg, g_value_get_boolean (value));
260 			break;
261 
262 		default:
263 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
264 			break;
265 	}
266 }
267 
268 static void
pluma_close_confirmation_dialog_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)269 pluma_close_confirmation_dialog_get_property (GObject    *object,
270 					      guint       prop_id,
271 					      GValue     *value,
272 					      GParamSpec *pspec)
273 {
274 	PlumaCloseConfirmationDialogPrivate *priv;
275 
276 	priv = PLUMA_CLOSE_CONFIRMATION_DIALOG (object)->priv;
277 
278 	switch( prop_id )
279 	{
280 		case PROP_UNSAVED_DOCUMENTS:
281 			g_value_set_pointer (value, priv->unsaved_documents);
282 			break;
283 
284 		case PROP_LOGOUT_MODE:
285 			g_value_set_boolean (value, priv->logout_mode);
286 			break;
287 
288 		default:
289 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
290 			break;
291 	}
292 }
293 
294 static void
pluma_close_confirmation_dialog_class_init(PlumaCloseConfirmationDialogClass * klass)295 pluma_close_confirmation_dialog_class_init (PlumaCloseConfirmationDialogClass *klass)
296 {
297 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
298 
299 	gobject_class->set_property = pluma_close_confirmation_dialog_set_property;
300 	gobject_class->get_property = pluma_close_confirmation_dialog_get_property;
301 	gobject_class->finalize = pluma_close_confirmation_dialog_finalize;
302 
303 	g_object_class_install_property (gobject_class,
304 					 PROP_UNSAVED_DOCUMENTS,
305 					 g_param_spec_pointer ("unsaved_documents",
306 						 	       "Unsaved Documents",
307 							       "List of Unsaved Documents",
308 							       (G_PARAM_READWRITE |
309 							        G_PARAM_CONSTRUCT_ONLY)));
310 
311 	g_object_class_install_property (gobject_class,
312 					 PROP_LOGOUT_MODE,
313 					 g_param_spec_boolean ("logout_mode",
314 						 	       "Logout Mode",
315 							       "Whether the dialog is in logout mode",
316 							       FALSE,
317 							       (G_PARAM_READWRITE |
318 							        G_PARAM_CONSTRUCT_ONLY)));
319 }
320 
321 static GList *
get_selected_docs(GtkTreeModel * store)322 get_selected_docs (GtkTreeModel *store)
323 {
324 	GList      *list;
325 	gboolean     valid;
326 	GtkTreeIter  iter;
327 
328 	list = NULL;
329 	valid = gtk_tree_model_get_iter_first (store, &iter);
330 
331 	while (valid)
332 	{
333 		gboolean       to_save;
334 		PlumaDocument *doc;
335 
336 		gtk_tree_model_get (store, &iter,
337 				    SAVE_COLUMN, &to_save,
338 				    DOC_COLUMN, &doc,
339 				    -1);
340 		if (to_save)
341 			list = g_list_prepend (list, doc);
342 
343 		valid = gtk_tree_model_iter_next (store, &iter);
344 	}
345 
346 	list = g_list_reverse (list);
347 
348 	return list;
349 }
350 
351 GList *
pluma_close_confirmation_dialog_get_selected_documents(PlumaCloseConfirmationDialog * dlg)352 pluma_close_confirmation_dialog_get_selected_documents (PlumaCloseConfirmationDialog *dlg)
353 {
354 	g_return_val_if_fail (PLUMA_IS_CLOSE_CONFIRMATION_DIALOG (dlg), NULL);
355 
356 	return g_list_copy (dlg->priv->selected_documents);
357 }
358 
359 GtkWidget *
pluma_close_confirmation_dialog_new(GtkWindow * parent,GList * unsaved_documents,gboolean logout_mode)360 pluma_close_confirmation_dialog_new (GtkWindow *parent,
361 				     GList     *unsaved_documents,
362 				     gboolean   logout_mode)
363 {
364 	GtkWidget *dlg;
365 	g_return_val_if_fail (unsaved_documents != NULL, NULL);
366 
367 	dlg = GTK_WIDGET (g_object_new (PLUMA_TYPE_CLOSE_CONFIRMATION_DIALOG,
368 				        "unsaved_documents", unsaved_documents,
369 				        "logout_mode", logout_mode,
370 				        NULL));
371 	g_return_val_if_fail (dlg != NULL, NULL);
372 
373 	if (parent != NULL)
374 	{
375 		gtk_window_group_add_window (pluma_window_get_group (PLUMA_WINDOW (parent)),
376 					     GTK_WINDOW (dlg));
377 
378 		gtk_window_set_transient_for (GTK_WINDOW (dlg), parent);
379 	}
380 
381 	return dlg;
382 }
383 
384 GtkWidget *
pluma_close_confirmation_dialog_new_single(GtkWindow * parent,PlumaDocument * doc,gboolean logout_mode)385 pluma_close_confirmation_dialog_new_single (GtkWindow     *parent,
386 					    PlumaDocument *doc,
387 					    gboolean       logout_mode)
388 {
389 	GtkWidget *dlg;
390 	GList *unsaved_documents;
391 	g_return_val_if_fail (doc != NULL, NULL);
392 
393 	unsaved_documents = g_list_prepend (NULL, doc);
394 
395 	dlg = pluma_close_confirmation_dialog_new (parent,
396 						   unsaved_documents,
397 						   logout_mode);
398 
399 	g_list_free (unsaved_documents);
400 
401 	return dlg;
402 }
403 
404 static gchar *
get_text_secondary_label(PlumaDocument * doc)405 get_text_secondary_label (PlumaDocument *doc)
406 {
407 	glong  seconds;
408 	gchar *secondary_msg;
409 
410 	seconds = MAX (1, _pluma_document_get_seconds_since_last_save_or_load (doc));
411 
412 	if (seconds < 55)
413 	{
414 		secondary_msg = g_strdup_printf (
415 					ngettext ("If you don't save, changes from the last %ld second "
416 					    	  "will be permanently lost.",
417 						  "If you don't save, changes from the last %ld seconds "
418 					    	  "will be permanently lost.",
419 						  seconds),
420 					seconds);
421 	}
422 	else if (seconds < 75) /* 55 <= seconds < 75 */
423 	{
424 		secondary_msg = g_strdup (_("If you don't save, changes from the last minute "
425 					    "will be permanently lost."));
426 	}
427 	else if (seconds < 110) /* 75 <= seconds < 110 */
428 	{
429 		secondary_msg = g_strdup_printf (
430 					ngettext ("If you don't save, changes from the last minute and %ld "
431 						  "second will be permanently lost.",
432 						  "If you don't save, changes from the last minute and %ld "
433 						  "seconds will be permanently lost.",
434 						  seconds - 60 ),
435 					seconds - 60);
436 	}
437 	else if (seconds < 3600)
438 	{
439 		secondary_msg = g_strdup_printf (
440 					ngettext ("If you don't save, changes from the last %ld minute "
441 					    	  "will be permanently lost.",
442 						  "If you don't save, changes from the last %ld minutes "
443 					    	  "will be permanently lost.",
444 						  seconds / 60),
445 					seconds / 60);
446 	}
447 	else if (seconds < 7200)
448 	{
449 		gint minutes;
450 		seconds -= 3600;
451 
452 		minutes = seconds / 60;
453 		if (minutes < 5)
454 		{
455 			secondary_msg = g_strdup (_("If you don't save, changes from the last hour "
456 						    "will be permanently lost."));
457 		}
458 		else
459 		{
460 			secondary_msg = g_strdup_printf (
461 					ngettext ("If you don't save, changes from the last hour and %d "
462 						  "minute will be permanently lost.",
463 						  "If you don't save, changes from the last hour and %d "
464 						  "minutes will be permanently lost.",
465 						  minutes),
466 					minutes);
467 		}
468 	}
469 	else
470 	{
471 		gint hours;
472 
473 		hours = seconds / 3600;
474 
475 		secondary_msg = g_strdup_printf (
476 					ngettext ("If you don't save, changes from the last %d hour "
477 					    	  "will be permanently lost.",
478 						  "If you don't save, changes from the last %d hours "
479 					    	  "will be permanently lost.",
480 						  hours),
481 					hours);
482 	}
483 
484 	return secondary_msg;
485 }
486 
487 static void
build_single_doc_dialog(PlumaCloseConfirmationDialog * dlg)488 build_single_doc_dialog (PlumaCloseConfirmationDialog *dlg)
489 {
490 	GtkWidget     *hbox;
491 	GtkWidget     *vbox;
492 	GtkWidget     *primary_label;
493 	GtkWidget     *secondary_label;
494 	GtkWidget     *image;
495 	PlumaDocument *doc;
496 	gchar         *doc_name;
497 	gchar         *str;
498 	gchar         *markup_str;
499 
500 	g_return_if_fail (dlg->priv->unsaved_documents->data != NULL);
501 	doc = PLUMA_DOCUMENT (dlg->priv->unsaved_documents->data);
502 
503 	/* Image */
504 	image = gtk_image_new_from_icon_name ("dialog-warning",
505 					  GTK_ICON_SIZE_DIALOG);
506 	gtk_widget_set_halign (image, GTK_ALIGN_START);
507 	gtk_widget_set_valign (image, GTK_ALIGN_END);
508 
509 	/* Primary label */
510 	primary_label = gtk_label_new (NULL);
511 	gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
512 	gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
513 	gtk_label_set_xalign (GTK_LABEL (primary_label), 0.0);
514 	gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
515 	gtk_widget_set_can_focus (GTK_WIDGET (primary_label), FALSE);
516 	gtk_label_set_max_width_chars (GTK_LABEL (primary_label), 72);
517 
518 	doc_name = pluma_document_get_short_name_for_display (doc);
519 
520 	if (dlg->priv->disable_save_to_disk)
521 	{
522 		str = g_markup_printf_escaped (_("Changes to document \"%s\" will be permanently lost."),
523 					       doc_name);
524 	}
525 	else
526 	{
527 		str = g_markup_printf_escaped (_("Save changes to document \"%s\" before closing?"),
528 					       doc_name);
529 	}
530 
531 	g_free (doc_name);
532 
533 	markup_str = g_strconcat ("<span weight=\"bold\" size=\"larger\">", str, "</span>", NULL);
534 	g_free (str);
535 
536 	gtk_label_set_markup (GTK_LABEL (primary_label), markup_str);
537 	g_free (markup_str);
538 
539 	/* Secondary label */
540 	if (dlg->priv->disable_save_to_disk)
541 		str = g_strdup (_("Saving has been disabled by the system administrator."));
542 	else
543 		str = get_text_secondary_label (doc);
544 	secondary_label = gtk_label_new (str);
545 	g_free (str);
546 	gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
547 	gtk_label_set_xalign (GTK_LABEL (secondary_label), 0.0);
548 	gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
549 	gtk_widget_set_can_focus (GTK_WIDGET (secondary_label), FALSE);
550 	gtk_label_set_max_width_chars (GTK_LABEL (secondary_label), 72);
551 
552 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
553 	gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
554 
555 	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
556 
557 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
558 
559 	gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
560 
561 	gtk_box_pack_start (GTK_BOX (vbox), primary_label, FALSE, FALSE, 0);
562 
563 	gtk_box_pack_start (GTK_BOX (vbox), secondary_label, FALSE, FALSE, 0);
564 
565 	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
566 			    hbox,
567 	                    FALSE,
568 			    FALSE,
569 			    0);
570 
571 	gtk_widget_show_all (hbox);
572 }
573 
574 static void
populate_model(GtkTreeModel * store,GList * docs)575 populate_model (GtkTreeModel *store, GList *docs)
576 {
577 	GtkTreeIter iter;
578 
579 	while (docs != NULL)
580 	{
581 		PlumaDocument *doc;
582 		gchar *name;
583 
584 		doc = PLUMA_DOCUMENT (docs->data);
585 
586 		name = pluma_document_get_short_name_for_display (doc);
587 
588 		gtk_list_store_append (GTK_LIST_STORE (store), &iter);
589 		gtk_list_store_set (GTK_LIST_STORE (store), &iter,
590 				    SAVE_COLUMN, TRUE,
591 				    NAME_COLUMN, name,
592 				    DOC_COLUMN, doc,
593 			            -1);
594 
595 		g_free (name);
596 
597 		docs = g_list_next (docs);
598 	}
599 }
600 
601 static void
save_toggled(GtkCellRendererToggle * renderer,gchar * path_str,GtkTreeModel * store)602 save_toggled (GtkCellRendererToggle *renderer, gchar *path_str, GtkTreeModel *store)
603 {
604 	GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
605 	GtkTreeIter iter;
606 	gboolean active;
607 
608 	gtk_tree_model_get_iter (store, &iter, path);
609 	gtk_tree_model_get (store, &iter, SAVE_COLUMN, &active, -1);
610 
611 	active ^= 1;
612 
613 	gtk_list_store_set (GTK_LIST_STORE (store), &iter,
614 			    SAVE_COLUMN, active, -1);
615 
616 	gtk_tree_path_free (path);
617 }
618 
619 static GtkWidget *
create_treeview(PlumaCloseConfirmationDialogPrivate * priv)620 create_treeview (PlumaCloseConfirmationDialogPrivate *priv)
621 {
622 	GtkListStore *store;
623 	GtkWidget *treeview;
624 	GtkCellRenderer *renderer;
625 	GtkTreeViewColumn *column;
626 
627 	treeview = gtk_tree_view_new ();
628 	gtk_widget_set_size_request (treeview, 260, 120);
629 	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
630 	gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), FALSE);
631 
632 	/* Create and populate the model */
633 	store = gtk_list_store_new (N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER);
634 	populate_model (GTK_TREE_MODEL (store), priv->unsaved_documents);
635 
636 	/* Set model to the treeview */
637 	gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
638 	g_object_unref (store);
639 
640 	priv->list_store = GTK_TREE_MODEL (store);
641 
642 	/* Add columns */
643 	if (!priv->disable_save_to_disk)
644 	{
645 		renderer = gtk_cell_renderer_toggle_new ();
646 		g_signal_connect (renderer, "toggled",
647 				  G_CALLBACK (save_toggled), store);
648 
649 		column = gtk_tree_view_column_new_with_attributes ("Save?",
650 								   renderer,
651 								   "active",
652 								   SAVE_COLUMN,
653 								   NULL);
654 		gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
655 	}
656 
657 	renderer = gtk_cell_renderer_text_new ();
658 	column = gtk_tree_view_column_new_with_attributes ("Name",
659 							   renderer,
660 							   "text",
661 							   NAME_COLUMN,
662 							   NULL);
663 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
664 
665 	return treeview;
666 }
667 
668 static void
build_multiple_docs_dialog(PlumaCloseConfirmationDialog * dlg)669 build_multiple_docs_dialog (PlumaCloseConfirmationDialog *dlg)
670 {
671 	PlumaCloseConfirmationDialogPrivate *priv;
672 	GtkWidget   *hbox;
673 	GtkWidget   *image;
674 	GtkWidget   *vbox;
675 	GtkWidget   *primary_label;
676 	GtkWidget   *vbox2;
677 	GtkWidget   *select_label;
678 	GtkWidget   *scrolledwindow;
679 	GtkWidget   *treeview;
680 	GtkWidget   *secondary_label;
681 	GdkDisplay  *display;
682 	GdkRectangle mon_geo;
683 	gchar       *str;
684 	gchar       *markup_str;
685 	gint         new_width;
686 	gint         new_height;
687 	gint         max_height;
688 
689 	priv = dlg->priv;
690 
691 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
692 	gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
693 	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
694 			    hbox, TRUE, TRUE, 0);
695 
696 	/* Image */
697 	image = gtk_image_new_from_icon_name ("dialog-warning",
698 					  GTK_ICON_SIZE_DIALOG);
699 	gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
700 	gtk_widget_set_valign (image, GTK_ALIGN_START);
701 	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
702 
703 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
704 	gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
705 
706 	/* Primary label */
707 	primary_label = gtk_label_new (NULL);
708 	gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
709 	gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
710 	gtk_label_set_xalign (GTK_LABEL (primary_label), 0.0);
711 	gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
712 	gtk_widget_set_can_focus (GTK_WIDGET (primary_label), FALSE);
713 	gtk_label_set_max_width_chars (GTK_LABEL (primary_label), 72);
714 
715 	if (priv->disable_save_to_disk)
716 		str = g_strdup_printf (
717 				ngettext ("Changes to %d document will be permanently lost.",
718 					  "Changes to %d documents will be permanently lost.",
719 					  g_list_length (priv->unsaved_documents)),
720 				g_list_length (priv->unsaved_documents));
721 	else
722 		str = g_strdup_printf (
723 				ngettext ("There is %d document with unsaved changes. "
724 					  "Save changes before closing?",
725 					  "There are %d documents with unsaved changes. "
726 					  "Save changes before closing?",
727 					  g_list_length (priv->unsaved_documents)),
728 				g_list_length (priv->unsaved_documents));
729 
730 	markup_str = g_strconcat ("<span weight=\"bold\" size=\"larger\">", str, "</span>", NULL);
731 	g_free (str);
732 
733 	gtk_label_set_markup (GTK_LABEL (primary_label), markup_str);
734 	g_free (markup_str);
735 	gtk_box_pack_start (GTK_BOX (vbox), primary_label, FALSE, FALSE, 0);
736 
737 	vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
738 	gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
739 
740 	if (priv->disable_save_to_disk)
741 		select_label = gtk_label_new_with_mnemonic (_("Docum_ents with unsaved changes:"));
742 	else
743 		select_label = gtk_label_new_with_mnemonic (_("S_elect the documents you want to save:"));
744 
745 	gtk_box_pack_start (GTK_BOX (vbox2), select_label, FALSE, FALSE, 0);
746 	gtk_label_set_line_wrap (GTK_LABEL (select_label), TRUE);
747 	gtk_label_set_max_width_chars (GTK_LABEL (select_label), 72);
748 	gtk_label_set_xalign (GTK_LABEL (select_label), 0.0);
749 	gtk_label_set_selectable (GTK_LABEL (select_label), TRUE);
750 	gtk_widget_set_can_focus (GTK_WIDGET (select_label), FALSE);
751 
752 	scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
753 	gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (scrolledwindow), TRUE);
754 	gtk_box_pack_start (GTK_BOX (vbox2), scrolledwindow, TRUE, TRUE, 0);
755 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
756 					GTK_POLICY_AUTOMATIC,
757 					GTK_POLICY_AUTOMATIC);
758 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow),
759 					     GTK_SHADOW_IN);
760 
761 	treeview = create_treeview (priv);
762 	gtk_container_add (GTK_CONTAINER (scrolledwindow), treeview);
763 
764 	/* Secondary label */
765 	if (priv->disable_save_to_disk)
766 		secondary_label = gtk_label_new (_("Saving has been disabled by the system administrator."));
767 	else
768 		secondary_label = gtk_label_new (_("If you don't save, "
769 						   "all your changes will be permanently lost."));
770 
771 	gtk_box_pack_start (GTK_BOX (vbox2), secondary_label, FALSE, FALSE, 0);
772 	gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
773 	gtk_label_set_xalign (GTK_LABEL (secondary_label), 0.0);
774 	gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
775 	gtk_widget_set_can_focus (GTK_WIDGET (secondary_label), FALSE);
776 	gtk_label_set_max_width_chars (GTK_LABEL (secondary_label), 72);
777 
778 	gtk_label_set_mnemonic_widget (GTK_LABEL (select_label), treeview);
779 
780 	gtk_widget_show_all (hbox);
781 
782 	gtk_window_get_size (GTK_WINDOW (GTK_DIALOG (dlg)), &new_width, &new_height);
783 
784 	display = gtk_widget_get_display (scrolledwindow);
785 
786 	gdk_monitor_get_geometry (gdk_display_get_primary_monitor (display), &mon_geo);
787 
788 	max_height = mon_geo.height * 40 / 100;
789 
790 	if (new_height > max_height)
791 	{
792 		gtk_window_set_resizable (GTK_WINDOW (GTK_DIALOG (dlg)), TRUE);
793 		gtk_window_resize (GTK_WINDOW (GTK_DIALOG (dlg)), new_width, max_height);
794 	}
795 	else
796 		gtk_window_set_default_size (GTK_WINDOW (GTK_DIALOG (dlg)), new_width, new_height);
797 }
798 
799 static void
set_unsaved_document(PlumaCloseConfirmationDialog * dlg,const GList * list)800 set_unsaved_document (PlumaCloseConfirmationDialog *dlg,
801 		      const GList                  *list)
802 {
803 	PlumaCloseConfirmationDialogPrivate *priv;
804 
805 	g_return_if_fail (list != NULL);
806 
807 	priv = dlg->priv;
808 	g_return_if_fail (priv->unsaved_documents == NULL);
809 
810 	priv->unsaved_documents = g_list_copy ((GList *)list);
811 
812 	if (GET_MODE (priv) == SINGLE_DOC_MODE)
813 	{
814 		build_single_doc_dialog (dlg);
815 	}
816 	else
817 	{
818 		build_multiple_docs_dialog (dlg);
819 	}
820 }
821 
822 const GList *
pluma_close_confirmation_dialog_get_unsaved_documents(PlumaCloseConfirmationDialog * dlg)823 pluma_close_confirmation_dialog_get_unsaved_documents (PlumaCloseConfirmationDialog *dlg)
824 {
825 	g_return_val_if_fail (PLUMA_IS_CLOSE_CONFIRMATION_DIALOG (dlg), NULL);
826 
827 	return dlg->priv->unsaved_documents;
828 }
829