1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * gedit-preferences-dialog.c
4  * This file is part of gedit
5  *
6  * Copyright (C) 2001-2005 Paolo Maggi
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, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "config.h"
23 
24 #include "gedit-preferences-dialog.h"
25 
26 #include <glib/gi18n.h>
27 #include <glib/gstdio.h>
28 #include <tepl/tepl.h>
29 #include <libpeas-gtk/peas-gtk.h>
30 
31 #include "gedit-debug.h"
32 #include "gedit-dirs.h"
33 #include "gedit-settings.h"
34 
35 /*
36  * gedit-preferences dialog is a singleton since we don't
37  * want two dialogs showing an inconsistent state of the
38  * preferences.
39  * When gedit_show_preferences_dialog is called and there
40  * is already a prefs dialog dialog open, it is reparented
41  * and shown.
42  */
43 
44 static GtkWidget *preferences_dialog = NULL;
45 
46 #define GEDIT_SCHEME_ROW_ID_KEY "gedit-scheme-row-id"
47 
48 #define GEDIT_TYPE_PREFERENCES_DIALOG (gedit_preferences_dialog_get_type())
49 
50 G_DECLARE_FINAL_TYPE (GeditPreferencesDialog, gedit_preferences_dialog, GEDIT, PREFERENCES_DIALOG, GtkWindow)
51 
52 enum
53 {
54 	ID_COLUMN = 0,
55 	NAME_COLUMN,
56 	DESC_COLUMN,
57 	NUM_COLUMNS
58 };
59 
60 enum
61 {
62 	CLOSE,
63 	LAST_SIGNAL
64 };
65 
66 static guint signals[LAST_SIGNAL];
67 
68 struct _GeditPreferencesDialog
69 {
70 	GtkWindow	parent_instance;
71 
72 	GSettings	*editor;
73 	GSettings	*uisettings; /* unfortunately our settings are split for historical reasons */
74 
75 	GtkWidget	*notebook;
76 
77 	/* Font */
78 	GtkWidget	*default_font_checkbutton;
79 	GtkWidget	*font_button;
80 	GtkWidget	*font_grid;
81 
82 	/* Style Scheme */
83 	GtkWidget	*schemes_list;
84 	GtkWidget	*install_scheme_button;
85 	GtkWidget	*uninstall_scheme_button;
86 	GtkWidget	*schemes_toolbar;
87 	GtkFileChooserNative *
88 			 install_scheme_file_chooser;
89 
90 	/* Tabs */
91 	GtkWidget	*tabs_width_spinbutton;
92 	GtkWidget	*insert_spaces_checkbutton;
93 
94 	/* Auto indentation */
95 	GtkWidget	*auto_indent_checkbutton;
96 
97 	/* Text Wrapping */
98 	GtkWidget	*wrap_text_checkbutton;
99 	GtkWidget	*split_checkbutton;
100 
101 	/* File Saving */
102 	GtkWidget	*backup_copy_checkbutton;
103 	GtkWidget	*auto_save_checkbutton;
104 	GtkWidget	*auto_save_spinbutton;
105 
106 	GtkWidget	*display_line_numbers_checkbutton;
107 	GtkWidget	*display_statusbar_checkbutton;
108 	GtkWidget	*display_grid_checkbutton;
109 
110 	/* Right margin */
111 	GtkWidget	*right_margin_checkbutton;
112 	GtkWidget       *right_margin_position_grid;
113 	GtkWidget	*right_margin_position_spinbutton;
114 
115 	/* Highlighting */
116 	GtkWidget	*highlight_current_line_checkbutton;
117 	GtkWidget	*bracket_matching_checkbutton;
118 
119 	/* Plugin manager */
120 	GtkWidget	*plugin_manager;
121 };
122 
G_DEFINE_TYPE(GeditPreferencesDialog,gedit_preferences_dialog,GTK_TYPE_WINDOW)123 G_DEFINE_TYPE (GeditPreferencesDialog, gedit_preferences_dialog, GTK_TYPE_WINDOW)
124 
125 static void
126 gedit_preferences_dialog_dispose (GObject *object)
127 {
128 	GeditPreferencesDialog *dlg = GEDIT_PREFERENCES_DIALOG (object);
129 
130 	g_clear_object (&dlg->editor);
131 	g_clear_object (&dlg->uisettings);
132 
133 	G_OBJECT_CLASS (gedit_preferences_dialog_parent_class)->dispose (object);
134 }
135 
136 static void
gedit_preferences_dialog_close(GeditPreferencesDialog * dialog)137 gedit_preferences_dialog_close (GeditPreferencesDialog *dialog)
138 {
139 	gtk_window_close (GTK_WINDOW (dialog));
140 }
141 
142 static void
gedit_preferences_dialog_class_init(GeditPreferencesDialogClass * klass)143 gedit_preferences_dialog_class_init (GeditPreferencesDialogClass *klass)
144 {
145 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
146 	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
147 	GtkBindingSet *binding_set;
148 
149 	/* Otherwise libpeas-gtk might not be linked */
150 	g_type_ensure (PEAS_GTK_TYPE_PLUGIN_MANAGER);
151 
152 	object_class->dispose = gedit_preferences_dialog_dispose;
153 
154 	signals[CLOSE] =
155 		g_signal_new_class_handler ("close",
156 		                            G_TYPE_FROM_CLASS (klass),
157 		                            G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
158 		                            G_CALLBACK (gedit_preferences_dialog_close),
159 		                            NULL, NULL, NULL,
160 		                            G_TYPE_NONE,
161 		                            0);
162 
163 	binding_set = gtk_binding_set_by_class (klass);
164 	gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "close", 0);
165 
166 	/* Bind class to template */
167 	gtk_widget_class_set_template_from_resource (widget_class,
168 	                                             "/org/gnome/gedit/ui/gedit-preferences-dialog.ui");
169 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, notebook);
170 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, display_line_numbers_checkbutton);
171 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, display_statusbar_checkbutton);
172 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, display_grid_checkbutton);
173 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, right_margin_checkbutton);
174 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, right_margin_position_grid);
175 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, right_margin_position_spinbutton);
176 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, highlight_current_line_checkbutton);
177 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, bracket_matching_checkbutton);
178 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, wrap_text_checkbutton);
179 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, split_checkbutton);
180 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, tabs_width_spinbutton);
181 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, insert_spaces_checkbutton);
182 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, auto_indent_checkbutton);
183 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, backup_copy_checkbutton);
184 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, auto_save_checkbutton);
185 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, auto_save_spinbutton);
186 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, default_font_checkbutton);
187 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, font_button);
188 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, font_grid);
189 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, schemes_list);
190 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, install_scheme_button);
191 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, uninstall_scheme_button);
192 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, schemes_toolbar);
193 	gtk_widget_class_bind_template_child (widget_class, GeditPreferencesDialog, plugin_manager);
194 }
195 
196 static void
setup_editor_page(GeditPreferencesDialog * dlg)197 setup_editor_page (GeditPreferencesDialog *dlg)
198 {
199 	gedit_debug (DEBUG_PREFS);
200 
201 	/* Connect signal */
202 	g_settings_bind (dlg->editor,
203 			 GEDIT_SETTINGS_TABS_SIZE,
204 			 dlg->tabs_width_spinbutton,
205 			 "value",
206 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
207 	g_settings_bind (dlg->editor,
208 			 GEDIT_SETTINGS_INSERT_SPACES,
209 			 dlg->insert_spaces_checkbutton,
210 			 "active",
211 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
212 	g_settings_bind (dlg->editor,
213 			 GEDIT_SETTINGS_AUTO_INDENT,
214 			 dlg->auto_indent_checkbutton,
215 			 "active",
216 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
217 	g_settings_bind (dlg->editor,
218 			 GEDIT_SETTINGS_CREATE_BACKUP_COPY,
219 			 dlg->backup_copy_checkbutton,
220 			 "active",
221 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
222 	g_settings_bind (dlg->editor,
223 			 GEDIT_SETTINGS_BRACKET_MATCHING,
224 			 dlg->bracket_matching_checkbutton,
225 			 "active",
226 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
227 	g_settings_bind (dlg->editor,
228 			 GEDIT_SETTINGS_AUTO_SAVE_INTERVAL,
229 			 dlg->auto_save_spinbutton,
230 			 "value",
231 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
232 	g_settings_bind (dlg->editor,
233 			 GEDIT_SETTINGS_AUTO_SAVE,
234 			 dlg->auto_save_spinbutton,
235 			 "sensitive",
236 			 G_SETTINGS_BIND_GET);
237 	g_settings_bind (dlg->editor,
238 			 GEDIT_SETTINGS_AUTO_SAVE,
239 			 dlg->auto_save_checkbutton,
240 			 "active",
241 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
242 }
243 
244 static void
wrap_mode_checkbutton_toggled(GtkToggleButton * button,GeditPreferencesDialog * dlg)245 wrap_mode_checkbutton_toggled (GtkToggleButton        *button,
246 			       GeditPreferencesDialog *dlg)
247 {
248 	GtkWrapMode mode;
249 
250 	if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dlg->wrap_text_checkbutton)))
251 	{
252 		mode = GTK_WRAP_NONE;
253 
254 		gtk_widget_set_sensitive (dlg->split_checkbutton,
255 					  FALSE);
256 		gtk_toggle_button_set_inconsistent (
257 			GTK_TOGGLE_BUTTON (dlg->split_checkbutton), TRUE);
258 	}
259 	else
260 	{
261 		gtk_widget_set_sensitive (dlg->split_checkbutton,
262 					  TRUE);
263 
264 		gtk_toggle_button_set_inconsistent (
265 			GTK_TOGGLE_BUTTON (dlg->split_checkbutton), FALSE);
266 
267 
268 		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dlg->split_checkbutton)))
269 		{
270 			g_settings_set_enum (dlg->editor,
271 			                     GEDIT_SETTINGS_WRAP_LAST_SPLIT_MODE,
272 			                     GTK_WRAP_WORD);
273 
274 			mode = GTK_WRAP_WORD;
275 		}
276 		else
277 		{
278 			g_settings_set_enum (dlg->editor,
279 			                     GEDIT_SETTINGS_WRAP_LAST_SPLIT_MODE,
280 			                     GTK_WRAP_CHAR);
281 
282 			mode = GTK_WRAP_CHAR;
283 		}
284 	}
285 
286 	g_settings_set_enum (dlg->editor,
287 			     GEDIT_SETTINGS_WRAP_MODE,
288 			     mode);
289 }
290 
291 static void
grid_checkbutton_toggled(GtkToggleButton * button,GeditPreferencesDialog * dlg)292 grid_checkbutton_toggled (GtkToggleButton        *button,
293                           GeditPreferencesDialog *dlg)
294 {
295 	GtkSourceBackgroundPatternType background_type;
296 
297 	background_type = gtk_toggle_button_get_active (button) ?
298 	                  GTK_SOURCE_BACKGROUND_PATTERN_TYPE_GRID :
299 		          GTK_SOURCE_BACKGROUND_PATTERN_TYPE_NONE;
300 	g_settings_set_enum (dlg->editor,
301 	                     GEDIT_SETTINGS_BACKGROUND_PATTERN,
302 	                     background_type);
303 }
304 
305 static void
setup_view_page(GeditPreferencesDialog * dlg)306 setup_view_page (GeditPreferencesDialog *dlg)
307 {
308 	GtkWrapMode wrap_mode;
309 	GtkWrapMode last_split_mode;
310 	GtkSourceBackgroundPatternType background_pattern;
311 	gboolean display_right_margin;
312 	guint right_margin_position;
313 
314 	gedit_debug (DEBUG_PREFS);
315 
316 	/* Get values */
317 	display_right_margin = g_settings_get_boolean (dlg->editor,
318 						       GEDIT_SETTINGS_DISPLAY_RIGHT_MARGIN);
319 	g_settings_get (dlg->editor, GEDIT_SETTINGS_RIGHT_MARGIN_POSITION,
320 			"u", &right_margin_position);
321 	background_pattern = g_settings_get_enum (dlg->editor,
322 	                                          GEDIT_SETTINGS_BACKGROUND_PATTERN);
323 
324 	wrap_mode = g_settings_get_enum (dlg->editor,
325 					 GEDIT_SETTINGS_WRAP_MODE);
326 
327 	/* Set initial state */
328 	switch (wrap_mode)
329 	{
330 		case GTK_WRAP_WORD:
331 			gtk_toggle_button_set_active (
332 				GTK_TOGGLE_BUTTON (dlg->wrap_text_checkbutton), TRUE);
333 			gtk_toggle_button_set_active (
334 				GTK_TOGGLE_BUTTON (dlg->split_checkbutton), TRUE);
335 
336 			g_settings_set_enum (dlg->editor,
337 			                     GEDIT_SETTINGS_WRAP_LAST_SPLIT_MODE,
338 			                     GTK_WRAP_WORD);
339 			break;
340 		case GTK_WRAP_CHAR:
341 			gtk_toggle_button_set_active (
342 				GTK_TOGGLE_BUTTON (dlg->wrap_text_checkbutton), TRUE);
343 			gtk_toggle_button_set_active (
344 				GTK_TOGGLE_BUTTON (dlg->split_checkbutton), FALSE);
345 
346 			g_settings_set_enum (dlg->editor,
347 			                     GEDIT_SETTINGS_WRAP_LAST_SPLIT_MODE,
348 			                     GTK_WRAP_CHAR);
349 			break;
350 		default:
351 			gtk_toggle_button_set_active (
352 				GTK_TOGGLE_BUTTON (dlg->wrap_text_checkbutton), FALSE);
353 
354 			last_split_mode = g_settings_get_enum (dlg->editor,
355 			                                       GEDIT_SETTINGS_WRAP_LAST_SPLIT_MODE);
356 			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dlg->split_checkbutton),
357 			                              last_split_mode == GTK_WRAP_WORD);
358 
359 			gtk_toggle_button_set_inconsistent (
360 				GTK_TOGGLE_BUTTON (dlg->split_checkbutton), TRUE);
361 	}
362 
363 	gtk_toggle_button_set_active (
364 		GTK_TOGGLE_BUTTON (dlg->right_margin_checkbutton),
365 		display_right_margin);
366 	gtk_toggle_button_set_active (
367 		GTK_TOGGLE_BUTTON (dlg->display_grid_checkbutton),
368 		background_pattern == GTK_SOURCE_BACKGROUND_PATTERN_TYPE_GRID);
369 
370 	/* Set widgets sensitivity */
371 	gtk_widget_set_sensitive (dlg->split_checkbutton,
372 				  (wrap_mode != GTK_WRAP_NONE));
373 
374 	g_settings_bind (dlg->editor,
375 			 GEDIT_SETTINGS_DISPLAY_LINE_NUMBERS,
376 			 dlg->display_line_numbers_checkbutton,
377 			 "active",
378 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
379 	g_settings_bind (dlg->editor,
380 			 GEDIT_SETTINGS_HIGHLIGHT_CURRENT_LINE,
381 			 dlg->highlight_current_line_checkbutton,
382 			 "active",
383 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
384 	g_settings_bind (dlg->uisettings,
385 	                 GEDIT_SETTINGS_STATUSBAR_VISIBLE,
386 	                 dlg->display_statusbar_checkbutton,
387 	                 "active",
388 	                 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
389 	g_settings_bind (dlg->editor,
390 	                 GEDIT_SETTINGS_DISPLAY_RIGHT_MARGIN,
391 	                 dlg->right_margin_checkbutton,
392 	                 "active",
393 	                 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
394 	g_settings_bind (dlg->editor,
395 	                 GEDIT_SETTINGS_DISPLAY_RIGHT_MARGIN,
396 	                 dlg->right_margin_position_grid,
397 	                 "sensitive",
398 	                 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
399 	g_settings_bind (dlg->editor,
400 			 GEDIT_SETTINGS_RIGHT_MARGIN_POSITION,
401 			 dlg->right_margin_position_spinbutton,
402 			 "value",
403 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
404 	g_settings_bind (dlg->editor,
405 			 GEDIT_SETTINGS_AUTO_SAVE_INTERVAL,
406 			 dlg->auto_save_spinbutton,
407 			 "value",
408 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
409 	g_signal_connect (dlg->wrap_text_checkbutton,
410 			  "toggled",
411 			  G_CALLBACK (wrap_mode_checkbutton_toggled),
412 			  dlg);
413 	g_signal_connect (dlg->split_checkbutton,
414 			  "toggled",
415 			  G_CALLBACK (wrap_mode_checkbutton_toggled),
416 			  dlg);
417 	g_signal_connect (dlg->display_grid_checkbutton,
418 			  "toggled",
419 			  G_CALLBACK (grid_checkbutton_toggled),
420 			  dlg);
421 }
422 
423 static void
setup_font_colors_page_font_section(GeditPreferencesDialog * dlg)424 setup_font_colors_page_font_section (GeditPreferencesDialog *dlg)
425 {
426 	GeditSettings *settings;
427 	gchar *system_font = NULL;
428 	gchar *label;
429 
430 	gedit_debug (DEBUG_PREFS);
431 
432 	gtk_widget_set_tooltip_text (dlg->font_button,
433 			 _("Click on this button to select the font to be used by the editor"));
434 
435 	/* Get values */
436 	settings = _gedit_settings_get_singleton ();
437 	system_font = _gedit_settings_get_system_font (settings);
438 
439 	label = g_strdup_printf(_("_Use the system fixed width font (%s)"),
440 				system_font);
441 	gtk_button_set_label (GTK_BUTTON (dlg->default_font_checkbutton),
442 			      label);
443 	g_free (system_font);
444 	g_free (label);
445 
446 	/* Bind settings */
447 	g_settings_bind (dlg->editor,
448 			 GEDIT_SETTINGS_USE_DEFAULT_FONT,
449 			 dlg->default_font_checkbutton,
450 			 "active",
451 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
452 	g_settings_bind (dlg->editor,
453 			 GEDIT_SETTINGS_USE_DEFAULT_FONT,
454 			 dlg->font_grid,
455 			 "sensitive",
456 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET | G_SETTINGS_BIND_INVERT_BOOLEAN);
457 	g_settings_bind (dlg->editor,
458 			 GEDIT_SETTINGS_EDITOR_FONT,
459 			 dlg->font_button,
460 			 "font-name",
461 			 G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
462 }
463 
464 static void
update_style_scheme_buttons_sensisitivity(GeditPreferencesDialog * dlg)465 update_style_scheme_buttons_sensisitivity (GeditPreferencesDialog *dlg)
466 {
467 	GtkSourceStyleScheme *selected_style_scheme;
468 	gboolean editable = FALSE;
469 
470 	selected_style_scheme = gtk_source_style_scheme_chooser_get_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (dlg->schemes_list));
471 
472 	if (selected_style_scheme != NULL)
473 	{
474 		const gchar *filename;
475 
476 		filename = gtk_source_style_scheme_get_filename (selected_style_scheme);
477 		if (filename != NULL)
478 		{
479 			editable = g_str_has_prefix (filename, gedit_dirs_get_user_styles_dir ());
480 		}
481 	}
482 
483 	gtk_widget_set_sensitive (dlg->uninstall_scheme_button, editable);
484 }
485 
486 static void
style_scheme_notify_cb(GtkSourceStyleSchemeChooser * chooser,GParamSpec * pspec,GeditPreferencesDialog * dlg)487 style_scheme_notify_cb (GtkSourceStyleSchemeChooser *chooser,
488 			GParamSpec                  *pspec,
489 			GeditPreferencesDialog      *dlg)
490 {
491 	update_style_scheme_buttons_sensisitivity (dlg);
492 }
493 
494 static GFile *
get_user_style_scheme_destination_file(GFile * src_file)495 get_user_style_scheme_destination_file (GFile *src_file)
496 {
497 	gchar *basename;
498 	const gchar *styles_dir;
499 	GFile *dest_file;
500 
501 	basename = g_file_get_basename (src_file);
502 	g_return_val_if_fail (basename != NULL, NULL);
503 
504 	styles_dir = gedit_dirs_get_user_styles_dir ();
505 	dest_file = g_file_new_build_filename (styles_dir, basename, NULL);
506 
507 	g_free (basename);
508 	return dest_file;
509 }
510 
511 /* Returns: whether @src_file has been correctly copied to @dest_file. */
512 static gboolean
copy_file(GFile * src_file,GFile * dest_file,GError ** error)513 copy_file (GFile   *src_file,
514 	   GFile   *dest_file,
515 	   GError **error)
516 {
517 	if (g_file_equal (src_file, dest_file))
518 	{
519 		return FALSE;
520 	}
521 
522 	if (!tepl_utils_create_parent_directories (dest_file, NULL, error))
523 	{
524 		return FALSE;
525 	}
526 
527 	return g_file_copy (src_file,
528 			    dest_file,
529 			    G_FILE_COPY_OVERWRITE | G_FILE_COPY_TARGET_DEFAULT_PERMS,
530 			    NULL, /* cancellable */
531 			    NULL, NULL, /* progress callback */
532 			    error);
533 }
534 
535 /* Get the style scheme ID of @user_style_scheme_file if it has been correctly
536  * installed and @user_style_scheme_file is a valid style scheme file.
537  */
538 static const gchar *
get_style_scheme_id_after_installing_user_style_scheme(GFile * user_style_scheme_file)539 get_style_scheme_id_after_installing_user_style_scheme (GFile *user_style_scheme_file)
540 {
541 	GtkSourceStyleSchemeManager *manager;
542 	const gchar * const *scheme_ids;
543 	gint i;
544 
545 	manager = gtk_source_style_scheme_manager_get_default ();
546 	gtk_source_style_scheme_manager_force_rescan (manager);
547 
548 	scheme_ids = gtk_source_style_scheme_manager_get_scheme_ids (manager);
549 
550 	for (i = 0; scheme_ids != NULL && scheme_ids[i] != NULL; i++)
551 	{
552 		const gchar *cur_scheme_id = scheme_ids[i];
553 		GtkSourceStyleScheme *scheme;
554 		const gchar *filename;
555 		GFile *scheme_file;
556 
557 		scheme = gtk_source_style_scheme_manager_get_scheme (manager, cur_scheme_id);
558 		filename = gtk_source_style_scheme_get_filename (scheme);
559 		if (filename == NULL)
560 		{
561 			continue;
562 		}
563 
564 		scheme_file = g_file_new_for_path (filename);
565 		if (g_file_equal (scheme_file, user_style_scheme_file))
566 		{
567 			g_object_unref (scheme_file);
568 			return cur_scheme_id;
569 		}
570 
571 		g_object_unref (scheme_file);
572 	}
573 
574 	return NULL;
575 }
576 
577 /* Returns: (nullable): the installed style scheme ID, or %NULL on failure. */
578 static const gchar *
install_style_scheme(GFile * src_file,GError ** error)579 install_style_scheme (GFile   *src_file,
580 		      GError **error)
581 {
582 	GFile *dest_file;
583 	gboolean copied;
584 	const gchar *installed_style_scheme_id = NULL;
585 	GError *my_error = NULL;
586 
587 	g_return_val_if_fail (G_IS_FILE (src_file), NULL);
588 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
589 
590 	dest_file = get_user_style_scheme_destination_file (src_file);
591 	g_return_val_if_fail (dest_file != NULL, NULL);
592 
593 	copied = copy_file (src_file, dest_file, &my_error);
594 	if (my_error != NULL)
595 	{
596 		g_propagate_error (error, my_error);
597 		g_object_unref (dest_file);
598 		return NULL;
599 	}
600 
601 	installed_style_scheme_id = get_style_scheme_id_after_installing_user_style_scheme (dest_file);
602 
603 	if (installed_style_scheme_id == NULL && copied)
604 	{
605 		/* The style scheme has not been correctly installed. */
606 		g_file_delete (dest_file, NULL, &my_error);
607 		if (my_error != NULL)
608 		{
609 			gchar *dest_file_parse_name = g_file_get_parse_name (dest_file);
610 
611 			g_warning ("Failed to delete the file “%s”: %s",
612 				   dest_file_parse_name,
613 				   my_error->message);
614 
615 			g_free (dest_file_parse_name);
616 			g_clear_error (&my_error);
617 		}
618 	}
619 
620 	g_object_unref (dest_file);
621 	return installed_style_scheme_id;
622 }
623 
624 /*
625  * uninstall_style_scheme:
626  * @scheme: a #GtkSourceStyleScheme
627  *
628  * Uninstall a user scheme.
629  *
630  * Returns: %TRUE on success, %FALSE otherwise.
631  */
632 static gboolean
uninstall_style_scheme(GtkSourceStyleScheme * scheme)633 uninstall_style_scheme (GtkSourceStyleScheme *scheme)
634 {
635 	GtkSourceStyleSchemeManager *manager;
636 	const gchar *filename;
637 
638 	g_return_val_if_fail (GTK_SOURCE_IS_STYLE_SCHEME (scheme), FALSE);
639 
640 	manager = gtk_source_style_scheme_manager_get_default ();
641 
642 	filename = gtk_source_style_scheme_get_filename (scheme);
643 	if (filename == NULL)
644 		return FALSE;
645 
646 	if (g_unlink (filename) == -1)
647 		return FALSE;
648 
649 	/* Reload the available style schemes */
650 	gtk_source_style_scheme_manager_force_rescan (manager);
651 
652 	return TRUE;
653 }
654 
655 static void
add_scheme_chooser_response_cb(GtkFileChooserNative * chooser,gint response_id,GeditPreferencesDialog * dialog)656 add_scheme_chooser_response_cb (GtkFileChooserNative   *chooser,
657 				gint                    response_id,
658 				GeditPreferencesDialog *dialog)
659 {
660 	GFile *file;
661 	const gchar *scheme_id;
662 	GeditSettings *settings;
663 	GSettings *editor_settings;
664 	GError *error = NULL;
665 
666 	if (response_id != GTK_RESPONSE_ACCEPT)
667 	{
668 		return;
669 	}
670 
671 	file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (chooser));
672 	if (file == NULL)
673 	{
674 		return;
675 	}
676 
677 	scheme_id = install_style_scheme (file, &error);
678 	g_object_unref (file);
679 
680 	if (scheme_id == NULL)
681 	{
682 		if (error != NULL)
683 		{
684 			tepl_utils_show_warning_dialog (GTK_WINDOW (dialog),
685 							_("The selected color scheme cannot be installed: %s"),
686 							error->message);
687 		}
688 		else
689 		{
690 			tepl_utils_show_warning_dialog (GTK_WINDOW (dialog),
691 							_("The selected color scheme cannot be installed."));
692 		}
693 
694 		g_clear_error (&error);
695 		return;
696 	}
697 
698 	settings = _gedit_settings_get_singleton ();
699 	editor_settings = _gedit_settings_peek_editor_settings (settings);
700 	g_settings_set_string (editor_settings, GEDIT_SETTINGS_SCHEME, scheme_id);
701 }
702 
703 static void
install_scheme_clicked(GtkButton * button,GeditPreferencesDialog * dialog)704 install_scheme_clicked (GtkButton              *button,
705 			GeditPreferencesDialog *dialog)
706 {
707 	GtkFileChooserNative *chooser;
708 	GtkFileFilter *scheme_filter;
709 	GtkFileFilter *all_filter;
710 
711 	if (dialog->install_scheme_file_chooser != NULL)
712 	{
713 		gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog->install_scheme_file_chooser));
714 		return;
715 	}
716 
717 	chooser = gtk_file_chooser_native_new (_("Add Color Scheme"),
718 					       GTK_WINDOW (dialog),
719 					       GTK_FILE_CHOOSER_ACTION_OPEN,
720 					       _("_Add Scheme"),
721 					       _("_Cancel"));
722 
723 	/* Filters */
724 	scheme_filter = gtk_file_filter_new ();
725 	gtk_file_filter_set_name (scheme_filter, _("Color Scheme Files"));
726 	gtk_file_filter_add_pattern (scheme_filter, "*.xml");
727 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), scheme_filter);
728 
729 	all_filter = gtk_file_filter_new ();
730 	gtk_file_filter_set_name (all_filter, _("All Files"));
731 	gtk_file_filter_add_pattern (all_filter, "*");
732 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), all_filter);
733 
734 	gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser), scheme_filter);
735 
736 	g_signal_connect (chooser,
737 			  "response",
738 			  G_CALLBACK (add_scheme_chooser_response_cb),
739 			  dialog);
740 
741 	g_set_weak_pointer (&dialog->install_scheme_file_chooser, chooser);
742 
743 	gtk_native_dialog_show (GTK_NATIVE_DIALOG (chooser));
744 }
745 
746 static void
uninstall_scheme_clicked(GtkButton * button,GeditPreferencesDialog * dlg)747 uninstall_scheme_clicked (GtkButton              *button,
748 			  GeditPreferencesDialog *dlg)
749 {
750 	GtkSourceStyleScheme *scheme;
751 	GtkSourceStyleScheme *new_selected_scheme;
752 
753 	scheme = gtk_source_style_scheme_chooser_get_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (dlg->schemes_list));
754 
755 	if (scheme == NULL)
756 	{
757 		return;
758 	}
759 
760 	if (!uninstall_style_scheme (scheme))
761 	{
762 		tepl_utils_show_warning_dialog (GTK_WINDOW (dlg),
763 						_("Could not remove color scheme “%s”."),
764 						gtk_source_style_scheme_get_name (scheme));
765 		return;
766 	}
767 
768 	new_selected_scheme = gtk_source_style_scheme_chooser_get_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (dlg->schemes_list));
769 	if (new_selected_scheme == NULL)
770 	{
771 		GeditSettings *settings;
772 		GSettings *editor_settings;
773 
774 		settings = _gedit_settings_get_singleton ();
775 		editor_settings = _gedit_settings_peek_editor_settings (settings);
776 
777 		g_settings_reset (editor_settings, GEDIT_SETTINGS_SCHEME);
778 	}
779 }
780 
781 static void
setup_font_colors_page_style_scheme_section(GeditPreferencesDialog * dlg)782 setup_font_colors_page_style_scheme_section (GeditPreferencesDialog *dlg)
783 {
784 	GtkStyleContext *context;
785 	GeditSettings *settings;
786 	GSettings *editor_settings;
787 
788 	gedit_debug (DEBUG_PREFS);
789 
790 	/* junction between the schemes list and the toolbar */
791 	context = gtk_widget_get_style_context (dlg->schemes_list);
792 	gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
793 	context = gtk_widget_get_style_context (dlg->schemes_toolbar);
794 	gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
795 
796 	/* Connect signals */
797 	g_signal_connect (dlg->schemes_list,
798 	                  "notify::style-scheme",
799 	                  G_CALLBACK (style_scheme_notify_cb),
800 	                  dlg);
801 	g_signal_connect (dlg->install_scheme_button,
802 			  "clicked",
803 			  G_CALLBACK (install_scheme_clicked),
804 			  dlg);
805 	g_signal_connect (dlg->uninstall_scheme_button,
806 			  "clicked",
807 			  G_CALLBACK (uninstall_scheme_clicked),
808 			  dlg);
809 
810 	settings = _gedit_settings_get_singleton ();
811 	editor_settings = _gedit_settings_peek_editor_settings (settings);
812 	g_settings_bind (editor_settings, GEDIT_SETTINGS_SCHEME,
813 			 dlg->schemes_list, "tepl-style-scheme-id",
814 			 G_SETTINGS_BIND_DEFAULT);
815 
816 	update_style_scheme_buttons_sensisitivity (dlg);
817 }
818 
819 static void
setup_font_colors_page(GeditPreferencesDialog * dlg)820 setup_font_colors_page (GeditPreferencesDialog *dlg)
821 {
822 	setup_font_colors_page_font_section (dlg);
823 	setup_font_colors_page_style_scheme_section (dlg);
824 }
825 
826 static void
setup_plugins_page(GeditPreferencesDialog * dlg)827 setup_plugins_page (GeditPreferencesDialog *dlg)
828 {
829 	gtk_widget_show_all (dlg->plugin_manager);
830 }
831 
832 static void
gedit_preferences_dialog_init(GeditPreferencesDialog * dlg)833 gedit_preferences_dialog_init (GeditPreferencesDialog *dlg)
834 {
835 	gedit_debug (DEBUG_PREFS);
836 
837 	dlg->editor = g_settings_new ("org.gnome.gedit.preferences.editor");
838 	dlg->uisettings = g_settings_new ("org.gnome.gedit.preferences.ui");
839 
840 	gtk_widget_init_template (GTK_WIDGET (dlg));
841 
842 	setup_editor_page (dlg);
843 	setup_view_page (dlg);
844 	setup_font_colors_page (dlg);
845 	setup_plugins_page (dlg);
846 }
847 
848 void
gedit_show_preferences_dialog(GeditWindow * parent)849 gedit_show_preferences_dialog (GeditWindow *parent)
850 {
851 	gedit_debug (DEBUG_PREFS);
852 
853 	if (preferences_dialog == NULL)
854 	{
855 		preferences_dialog = GTK_WIDGET (g_object_new (GEDIT_TYPE_PREFERENCES_DIALOG,
856 							       "application", g_application_get_default (),
857 							       NULL));
858 		g_signal_connect (preferences_dialog,
859 				  "destroy",
860 				  G_CALLBACK (gtk_widget_destroyed),
861 				  &preferences_dialog);
862 	}
863 
864 	if (GTK_WINDOW (parent) != gtk_window_get_transient_for (GTK_WINDOW (preferences_dialog)))
865 	{
866 		gtk_window_set_transient_for (GTK_WINDOW (preferences_dialog),
867 					      GTK_WINDOW (parent));
868 	}
869 
870 	gtk_window_present (GTK_WINDOW (preferences_dialog));
871 }
872 
873 /* ex:set ts=8 noet: */
874