1/*
2 * This file is part of GNOME LaTeX.
3 *
4 * Copyright © 2010-2012 Sébastien Wilmet
5 *
6 * GNOME LaTeX is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GNOME LaTeX is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNOME LaTeX.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20using Gtk;
21using Gee;
22
23public class PreferencesDialog : Dialog
24{
25    private static PreferencesDialog _instance = null;
26
27    delegate unowned string Plural (ulong n);
28
29    private PreferencesDialog ()
30    {
31        Object (use_header_bar : 1);
32
33        title = _("Preferences");
34        destroy_with_parent = true;
35        border_width = 5;
36
37        HeaderBar headerbar = get_header_bar () as HeaderBar;
38
39        headerbar.set_show_close_button (true);
40
41        // reset all button
42        Button reset_button = new Button.with_mnemonic (_("_Reset All"));
43        reset_button.set_tooltip_text (_("Reset all preferences"));
44        reset_button.show_all ();
45        reset_button.clicked.connect (() => reset_all ());
46        headerbar.pack_start (reset_button);
47
48        /* load the UI */
49
50        Builder builder = new Builder ();
51
52        try
53        {
54            string ui_path = Path.build_filename (Config.DATA_DIR, "ui",
55                "preferences_dialog.ui");
56            builder.add_from_file (ui_path);
57        }
58        catch (Error e)
59        {
60            string message = "Error: %s".printf (e.message);
61            warning ("%s", message);
62
63            Label label_error = new Label (message);
64            label_error.set_line_wrap (true);
65            Box content_area = (Box) get_content_area ();
66            content_area.pack_start (label_error);
67            content_area.show_all ();
68            return;
69        }
70
71        init_editor_tab (builder);
72        init_font_and_colors_tab (builder);
73        init_interactive_completion_setting (builder);
74        init_spell_checking_settings (builder);
75        init_other_tab (builder);
76
77        // pack notebook
78        Notebook notebook = builder.get_object ("notebook") as Notebook;
79        notebook.unparent ();
80        Box content_area = (Box) get_content_area ();
81        content_area.pack_start (notebook);
82    }
83
84    public static void show_me (Window parent)
85    {
86        if (_instance == null)
87        {
88            _instance = new PreferencesDialog ();
89
90            _instance.delete_event.connect (() =>
91            {
92                _instance.hide ();
93                return true;
94            });
95
96            _instance.destroy.connect (() =>
97            {
98                _instance = null;
99            });
100        }
101
102        if (parent != _instance.get_transient_for ())
103            _instance.set_transient_for (parent);
104
105        _instance.present ();
106    }
107
108    private void reset_all ()
109    {
110        Dialog dialog = new MessageDialog (this, DialogFlags.DESTROY_WITH_PARENT,
111            MessageType.QUESTION, ButtonsType.NONE,
112            "%s", _("Do you really want to reset all preferences?"));
113
114        dialog.add_button (_("_Cancel"), ResponseType.CANCEL);
115        dialog.add_button (_("_Reset All"), ResponseType.YES);
116
117        int resp = dialog.run ();
118        dialog.destroy ();
119        if (resp != ResponseType.YES)
120            return;
121
122        string[] settings_str =
123        {
124            "org.gnome.gnome-latex.preferences.editor",
125            "org.gnome.gnome-latex.preferences.latex"
126        };
127
128        foreach (string setting_str in settings_str)
129        {
130            GLib.Settings settings = new GLib.Settings (setting_str);
131            string[] keys = settings.list_keys ();
132            foreach (string key in keys)
133                settings.reset (key);
134        }
135    }
136
137    private void init_editor_tab (Builder builder)
138    {
139        GLib.Settings settings =
140            new GLib.Settings ("org.gnome.gnome-latex.preferences.editor");
141
142        var display_line_nb_checkbutton =
143            builder.get_object ("display_line_nb_checkbutton");
144        settings.bind ("display-line-numbers", display_line_nb_checkbutton, "active",
145            SettingsBindFlags.DEFAULT);
146
147        var tab_width_spinbutton =
148            builder.get_object ("tab_width_spinbutton") as SpinButton;
149        set_spin_button_range (tab_width_spinbutton, settings, "tabs-size");
150        settings.bind ("tabs-size", tab_width_spinbutton, "value",
151            SettingsBindFlags.DEFAULT);
152
153        var insert_spaces_checkbutton = builder.get_object ("insert_spaces_checkbutton");
154        settings.bind ("insert-spaces", insert_spaces_checkbutton, "active",
155            SettingsBindFlags.DEFAULT);
156
157        Widget forget_no_tabs = builder.get_object ("forget_no_tabs") as Widget;
158        settings.bind ("forget-no-tabs", forget_no_tabs, "active",
159            SettingsBindFlags.DEFAULT);
160        insert_spaces_checkbutton.bind_property ("active", forget_no_tabs, "sensitive",
161            BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
162
163        var hl_current_line_checkbutton =
164            builder.get_object ("hl_current_line_checkbutton");
165        settings.bind ("highlight-current-line", hl_current_line_checkbutton, "active",
166            SettingsBindFlags.DEFAULT);
167
168        var bracket_matching_checkbutton =
169            builder.get_object ("bracket_matching_checkbutton");
170        settings.bind ("bracket-matching", bracket_matching_checkbutton, "active",
171            SettingsBindFlags.DEFAULT);
172
173        var backup_checkbutton = builder.get_object ("backup_checkbutton");
174        settings.bind ("create-backup-copy", backup_checkbutton, "active",
175            SettingsBindFlags.DEFAULT);
176
177        var autosave_checkbutton = builder.get_object ("autosave_checkbutton");
178        settings.bind ("auto-save", autosave_checkbutton, "active",
179            SettingsBindFlags.DEFAULT);
180
181        var autosave_spinbutton =
182            builder.get_object ("autosave_spinbutton") as SpinButton;
183        set_spin_button_range (autosave_spinbutton, settings, "auto-save-interval");
184        settings.bind ("auto-save-interval", autosave_spinbutton, "value",
185            SettingsBindFlags.DEFAULT);
186        autosave_checkbutton.bind_property ("active", autosave_spinbutton, "sensitive",
187            BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
188
189        Label autosave_label = builder.get_object ("autosave_label") as Label;
190        set_plural (autosave_label, settings, "auto-save-interval",
191            (n) => ngettext ("minute", "minutes", n));
192
193        var reopen_checkbutton = builder.get_object ("reopen_checkbutton");
194        settings.bind ("reopen-files", reopen_checkbutton, "active",
195            SettingsBindFlags.DEFAULT);
196    }
197
198    private void init_font_and_colors_tab (Builder builder)
199    {
200        Latexila.Settings settings = Latexila.Settings.get_singleton ();
201        GLib.Settings editor_settings = settings.peek_editor_settings ();
202
203        var default_font_checkbutton =
204            builder.get_object ("default_font_checkbutton") as Button;
205        editor_settings.bind ("use-default-font", default_font_checkbutton, "active",
206            SettingsBindFlags.DEFAULT);
207        set_system_font_label (default_font_checkbutton);
208
209        AppSettings app_settings = AppSettings.get_default ();
210        app_settings.notify["system-font"].connect (() =>
211        {
212            set_system_font_label (default_font_checkbutton);
213        });
214
215        var font_button = builder.get_object ("font_button");
216        editor_settings.bind ("editor-font", font_button, "font-name",
217            SettingsBindFlags.DEFAULT);
218
219        var font_hbox = builder.get_object ("font_hbox") as Widget;
220        default_font_checkbutton.bind_property ("active", font_hbox, "sensitive",
221            BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE |
222            BindingFlags.INVERT_BOOLEAN);
223
224        Tepl.StyleSchemeChooserWidget style_scheme_chooser =
225            builder.get_object ("style_scheme_chooser") as Tepl.StyleSchemeChooserWidget;
226        editor_settings.bind ("scheme", style_scheme_chooser, "tepl-style-scheme-id",
227            SettingsBindFlags.DEFAULT);
228    }
229
230    private void init_interactive_completion_setting (Builder builder)
231    {
232        GLib.Settings settings =
233            new GLib.Settings ("org.gnome.gnome-latex.preferences.latex");
234
235        var interactive_comp_checkbutton =
236            builder.get_object ("interactive_comp_checkbutton");
237        settings.bind ("interactive-completion", interactive_comp_checkbutton, "active",
238            SettingsBindFlags.DEFAULT);
239
240        var interactive_comp_spinbutton =
241            builder.get_object ("interactive_comp_spinbutton") as SpinButton;
242        set_spin_button_range (interactive_comp_spinbutton, settings,
243            "interactive-completion-num");
244        settings.bind ("interactive-completion-num", interactive_comp_spinbutton, "value",
245            SettingsBindFlags.DEFAULT);
246        interactive_comp_checkbutton.bind_property ("active",
247            interactive_comp_spinbutton, "sensitive",
248            BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
249
250        Label interactive_comp_label =
251            builder.get_object ("interactive_comp_label") as Label;
252        set_plural (interactive_comp_label, settings, "interactive-completion-num",
253            (n) => ngettext ("character", "characters", n));
254    }
255
256    private void init_spell_checking_settings (Builder builder)
257    {
258        GLib.Settings editor_settings =
259            new GLib.Settings ("org.gnome.gnome-latex.preferences.editor");
260
261        Gspell.LanguageChooserButton spell_language_button =
262            builder.get_object ("spell_language_button") as Gspell.LanguageChooserButton;
263        editor_settings.bind ("spell-checking-language", spell_language_button,
264            "language-code", SettingsBindFlags.DEFAULT);
265
266        var inline_spell_checkbutton = builder.get_object ("inline_spell_checkbutton");
267        editor_settings.bind ("highlight-misspelled-words", inline_spell_checkbutton,
268            "active", SettingsBindFlags.DEFAULT);
269    }
270
271    private void init_other_tab (Builder builder)
272    {
273        GLib.Settings latex_settings =
274            new GLib.Settings ("org.gnome.gnome-latex.preferences.latex");
275
276        var confirm_clean_up_checkbutton =
277            builder.get_object ("confirm_clean_up_checkbutton");
278        latex_settings.bind ("no-confirm-clean", confirm_clean_up_checkbutton, "active",
279            SettingsBindFlags.DEFAULT);
280
281        Widget auto_clean_up_checkbutton =
282            builder.get_object ("auto_clean_up_checkbutton") as Widget;
283        latex_settings.bind ("automatic-clean", auto_clean_up_checkbutton, "active",
284            SettingsBindFlags.DEFAULT);
285        confirm_clean_up_checkbutton.bind_property ("active", auto_clean_up_checkbutton,
286            "sensitive", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
287
288        var clean_up_entry = builder.get_object ("clean_up_entry");
289        latex_settings.bind ("clean-extensions", clean_up_entry, "text",
290            SettingsBindFlags.DEFAULT);
291    }
292
293    private void set_system_font_label (Button button)
294    {
295        AppSettings app_settings = AppSettings.get_default ();
296        string label = _("Use the system fixed width font (%s)")
297            .printf (app_settings.system_font);
298        button.set_label (label);
299    }
300
301    private void set_plural (Label label, GLib.Settings settings, string key,
302        Plural plural)
303    {
304        uint val;
305        settings.get (key, "u", out val);
306        label.label = plural (val);
307
308        settings.changed[key].connect ((setting, k) =>
309        {
310            uint v;
311            setting.get (k, "u", out v);
312            label.label = plural (v);
313        });
314    }
315
316    private void set_spin_button_range (SpinButton spin_button, GLib.Settings settings,
317        string key)
318    {
319        GLib.SettingsSchema schema = settings.settings_schema;
320        Variant range = schema.get_key (key).get_range ();
321
322        string range_type;
323        Variant range_contents;
324        range.get ("(sv)", out range_type, out range_contents);
325
326        return_if_fail (range_type == "range");
327
328        uint min;
329        uint max;
330        range_contents.get ("(uu)", out min, out max);
331
332        uint cur_value;
333        settings.get (key, "u", out cur_value);
334
335        Adjustment adjustment = new Adjustment ((double) cur_value, (double) min,
336            (double) max, 1.0, 0, 0);
337        spin_button.set_adjustment (adjustment);
338    }
339}
340