/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright © 200-2003 Marco Pesenti Gritti
* Copyright © 2003, 2004, 2005 Christian Persch
* Copyright © 2010 Igalia S.L.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "config.h"
#include "prefs-dialog.h"
#include "ephy-bookmarks.h"
#include "ephy-debug.h"
#include "ephy-embed-container.h"
#include "ephy-embed-prefs.h"
#include "ephy-embed-shell.h"
#include "ephy-embed-utils.h"
#include "ephy-encodings.h"
#include "ephy-file-chooser.h"
#include "ephy-file-helpers.h"
#include "ephy-gui.h"
#include "ephy-langs.h"
#include "ephy-prefs.h"
#include "ephy-session.h"
#include "ephy-settings.h"
#include "ephy-shell.h"
#include "clear-data-dialog.h"
#include "cookies-dialog.h"
#include "passwords-dialog.h"
#include
#include
#include
#define DOWNLOAD_BUTTON_WIDTH 8
static void prefs_dialog_class_init (PrefsDialogClass *klass);
static void prefs_dialog_init (PrefsDialog *pd);
#include "languages.h"
enum
{
COL_LANG_NAME,
COL_LANG_CODE
};
struct PrefsDialogPrivate
{
/* general */
GtkWidget *download_button_hbox;
GtkWidget *download_button_label;
GtkWidget *automatic_downloads_checkbutton;
GtkWidget *search_engine_combo;
GtkWidget *popups_allow_checkbutton;
GtkWidget *adblock_allow_checkbutton;
GtkWidget *enable_plugins_checkbutton;
/* fonts */
GtkWidget *use_gnome_fonts_checkbutton;
GtkWidget *custom_fonts_table;
GtkWidget *sans_fontbutton;
GtkWidget *serif_fontbutton;
GtkWidget *mono_fontbutton;
GtkWidget *css_checkbox;
GtkWidget *css_edit_button;
/* privacy */
GtkWidget *always;
GtkWidget *no_third_party;
GtkWidget *never;
GtkWidget *remember_passwords_checkbutton;
GtkWidget *do_not_track_checkbutton;
GtkWidget *clear_personal_data_button;
/* language */
GtkWidget *default_encoding_combo;
GtkTreeView *lang_treeview;
GtkWidget *lang_add_button;
GtkWidget *lang_remove_button;
GtkWidget *lang_up_button;
GtkWidget *lang_down_button;
GtkWidget *enable_spell_checking_checkbutton;
GtkDialog *add_lang_dialog;
GtkTreeView *add_lang_treeview;
GtkTreeModel *lang_model;
GHashTable *iso_639_table;
GHashTable *iso_3166_table;
};
enum {
COL_TITLE_ELIDED,
COL_ENCODING,
NUM_COLS
};
enum
{
SEARCH_ENGINE_COL_NAME,
SEARCH_ENGINE_COL_STOCK_URL,
SEARCH_ENGINE_COL_URL,
SEARCH_ENGINE_NUM_COLS
};
G_DEFINE_TYPE_WITH_PRIVATE (PrefsDialog, prefs_dialog, GTK_TYPE_DIALOG)
static void
prefs_dialog_finalize (GObject *object)
{
PrefsDialog *dialog = EPHY_PREFS_DIALOG (object);
PrefsDialogPrivate *priv = dialog->priv;
if (priv->add_lang_dialog != NULL)
{
GtkDialog **add_lang_dialog = &priv->add_lang_dialog;
g_object_remove_weak_pointer (G_OBJECT (priv->add_lang_dialog),
(gpointer *) add_lang_dialog);
g_object_unref (priv->add_lang_dialog);
}
g_hash_table_destroy (priv->iso_639_table);
g_hash_table_destroy (priv->iso_3166_table);
G_OBJECT_CLASS (prefs_dialog_parent_class)->finalize (object);
}
static void
on_manage_cookies_button_clicked (GtkWidget *button,
PrefsDialog *dialog)
{
EphyCookiesDialog *cookies_dialog;
cookies_dialog = ephy_cookies_dialog_new ();
gtk_window_set_transient_for (GTK_WINDOW (cookies_dialog), GTK_WINDOW (dialog));
gtk_window_set_modal (GTK_WINDOW (cookies_dialog), TRUE);
gtk_window_present (GTK_WINDOW (cookies_dialog));
}
static void
on_manage_passwords_button_clicked (GtkWidget *button,
PrefsDialog *dialog)
{
EphyPasswordsDialog *passwords_dialog;
passwords_dialog = ephy_passwords_dialog_new ();
gtk_window_set_transient_for (GTK_WINDOW (passwords_dialog), GTK_WINDOW (dialog));
gtk_window_set_modal (GTK_WINDOW (passwords_dialog), TRUE);
gtk_window_present (GTK_WINDOW (passwords_dialog));
}
static void
prefs_dialog_class_init (PrefsDialogClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = prefs_dialog_finalize;
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/epiphany/prefs-dialog.ui");
/* general */
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, automatic_downloads_checkbutton);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, search_engine_combo);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, popups_allow_checkbutton);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, adblock_allow_checkbutton);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, enable_plugins_checkbutton);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, download_button_hbox);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, download_button_label);
/* fonts */
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, use_gnome_fonts_checkbutton);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, custom_fonts_table);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, sans_fontbutton);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, serif_fontbutton);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, mono_fontbutton);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, css_checkbox);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, css_edit_button);
/* privacy */
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, always);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, no_third_party);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, never);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, remember_passwords_checkbutton);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, do_not_track_checkbutton);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, clear_personal_data_button);
/* language */
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, default_encoding_combo);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, lang_treeview);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, lang_add_button);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, lang_remove_button);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, lang_up_button);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, lang_down_button);
gtk_widget_class_bind_template_child_private (widget_class, PrefsDialog, enable_spell_checking_checkbutton);
gtk_widget_class_bind_template_callback (widget_class, on_manage_cookies_button_clicked);
gtk_widget_class_bind_template_callback (widget_class, on_manage_passwords_button_clicked);
}
static void
css_edit_button_clicked_cb (GtkWidget *button,
PrefsDialog *pd)
{
GFile *css_file;
css_file = g_file_new_for_path (g_build_filename (ephy_dot_dir (),
USER_STYLESHEET_FILENAME,
NULL));
ephy_file_launch_handler ("text/plain", css_file,
gtk_get_current_event_time ());
g_object_unref (css_file);
}
static gboolean
combo_get_mapping (GValue *value,
GVariant *variant,
gpointer user_data)
{
GtkTreeModel *model;
GtkTreeIter iter;
gboolean valid = FALSE;
const char *settings_name;
int i;
model = gtk_combo_box_get_model (GTK_COMBO_BOX (user_data));
valid = gtk_tree_model_get_iter_first (model, &iter);
settings_name = g_variant_get_string (variant, NULL);
i = 0;
while (valid)
{
char *item_name;
gtk_tree_model_get (model, &iter, 1, &item_name, -1);
if (g_strcmp0 (item_name, settings_name) == 0)
{
g_value_set_int (value, i);
g_free (item_name);
break;
}
i++;
valid = gtk_tree_model_iter_next (model, &iter);
g_free (item_name);
}
return TRUE;
}
static GVariant *
combo_set_mapping (const GValue *value,
const GVariantType *expected_type,
gpointer user_data)
{
GVariant *variant = NULL;
GtkTreeModel *model;
GtkTreeIter iter;
gboolean valid = FALSE;
int n;
n = g_value_get_int (value);
model = gtk_combo_box_get_model (GTK_COMBO_BOX (user_data));
valid = gtk_tree_model_iter_nth_child (model, &iter, NULL, n);
if (valid)
{
char *item_name;
gtk_tree_model_get (model, &iter, 1, &item_name, -1);
variant = g_variant_new_string (item_name);
g_free (item_name);
}
return variant;
}
static void
create_node_combo (PrefsDialog *dialog,
EphyEncodings *encodings,
const char *default_value)
{
GtkComboBox *combo;
GtkCellRenderer *renderer;
GtkListStore *store;
GList *all_encodings, *p;
char *code;
code = g_settings_get_string (EPHY_SETTINGS_WEB,
EPHY_PREFS_WEB_DEFAULT_ENCODING);
if (code == NULL || ephy_encodings_get_encoding (encodings, code, FALSE) == NULL)
{
/* safe default */
g_settings_set_string (EPHY_SETTINGS_WEB,
EPHY_PREFS_WEB_DEFAULT_ENCODING,
default_value);
}
g_free (code);
combo = GTK_COMBO_BOX (dialog->priv->default_encoding_combo);
store = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_STRING);
all_encodings = ephy_encodings_get_all (encodings);
for (p = all_encodings; p; p = p->next)
{
GtkTreeIter iter;
EphyEncoding *encoding = EPHY_ENCODING (p->data);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COL_TITLE_ELIDED,
ephy_encoding_get_title_elided (encoding),
-1);
gtk_list_store_set (store, &iter,
COL_ENCODING,
ephy_encoding_get_encoding (encoding),
-1);
}
g_list_free (all_encodings);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), COL_TITLE_ELIDED,
GTK_SORT_ASCENDING);
gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
"text", COL_TITLE_ELIDED,
NULL);
g_settings_bind_with_mapping (EPHY_SETTINGS_WEB,
EPHY_PREFS_WEB_DEFAULT_ENCODING,
combo, "active",
G_SETTINGS_BIND_DEFAULT,
combo_get_mapping,
combo_set_mapping,
combo,
NULL);
}
static void
language_editor_add (PrefsDialog *pd,
const char *code,
const char *desc)
{
GtkTreeIter iter;
g_return_if_fail (code != NULL && desc != NULL);
if (gtk_tree_model_get_iter_first (pd->priv->lang_model, &iter))
{
do
{
char *c;
gtk_tree_model_get (pd->priv->lang_model, &iter,
COL_LANG_CODE, &c,
-1);
if (strcmp (code, c) == 0)
{
g_free (c);
/* already in list, don't allow a duplicate */
return;
}
g_free (c);
}
while (gtk_tree_model_iter_next (pd->priv->lang_model, &iter));
}
gtk_list_store_append (GTK_LIST_STORE (pd->priv->lang_model), &iter);
gtk_list_store_set (GTK_LIST_STORE (pd->priv->lang_model), &iter,
COL_LANG_NAME, desc,
COL_LANG_CODE, code,
-1);
}
static void
language_editor_update_pref (PrefsDialog *pd)
{
GtkTreeIter iter;
GVariantBuilder builder;
if (gtk_tree_model_get_iter_first (pd->priv->lang_model, &iter))
{
g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY);
do
{
char *code;
gtk_tree_model_get (pd->priv->lang_model, &iter,
COL_LANG_CODE, &code,
-1);
g_variant_builder_add (&builder, "s", code);
g_free (code);
}
while (gtk_tree_model_iter_next (pd->priv->lang_model, &iter));
g_settings_set (EPHY_SETTINGS_WEB,
EPHY_PREFS_WEB_LANGUAGE,
"as", &builder);
} else {
g_settings_set (EPHY_SETTINGS_WEB,
EPHY_PREFS_WEB_LANGUAGE,
"as", NULL);
}
}
static void
language_editor_update_buttons (PrefsDialog *dialog)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreePath *path;
GtkTreeIter iter;
gboolean can_remove = FALSE, can_move_up = FALSE, can_move_down = FALSE;
int selected;
selection = gtk_tree_view_get_selection (dialog->priv->lang_treeview);
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
path = gtk_tree_model_get_path (model, &iter);
selected = gtk_tree_path_get_indices (path)[0];
can_remove = TRUE;
can_move_up = selected > 0;
can_move_down =
selected < gtk_tree_model_iter_n_children (model, NULL) - 1;
gtk_tree_path_free (path);
}
gtk_widget_set_sensitive (dialog->priv->lang_remove_button, can_remove);
gtk_widget_set_sensitive (dialog->priv->lang_up_button, can_move_up);
gtk_widget_set_sensitive (dialog->priv->lang_down_button, can_move_down);
}
static void
add_lang_dialog_selection_changed (GtkTreeSelection *selection,
GtkWidget *button)
{
int n_selected;
n_selected = gtk_tree_selection_count_selected_rows (selection);
gtk_widget_set_sensitive (button, n_selected > 0);
}
static void
add_lang_dialog_response_cb (GtkWidget *widget,
int response,
PrefsDialog *pd)
{
GtkDialog *dialog = pd->priv->add_lang_dialog;
GtkTreeModel *model;
GtkTreeSelection *selection;
GtkTreeIter iter;
GList *rows, *r;
g_return_if_fail (dialog != NULL);
if (response == GTK_RESPONSE_ACCEPT)
{
selection = gtk_tree_view_get_selection (pd->priv->add_lang_treeview);
rows = gtk_tree_selection_get_selected_rows (selection, &model);
for (r = rows; r != NULL; r = r->next)
{
GtkTreePath *path = (GtkTreePath *) r->data;
if (gtk_tree_model_get_iter (model, &iter, path))
{
char *code, *desc;
gtk_tree_model_get (model, &iter,
COL_LANG_NAME, &desc,
COL_LANG_CODE, &code,
-1);
language_editor_add (pd, code, desc);
g_free (desc);
g_free (code);
}
}
g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
g_list_free (rows);
language_editor_update_pref (pd);
language_editor_update_buttons (pd);
}
gtk_widget_destroy (GTK_WIDGET (dialog));
}
static char *
get_name_for_lang_code (PrefsDialog *pd,
const char *code)
{
char **str;
char *name;
const char *langname, *localename;
int len;
str = g_strsplit (code, "-", -1);
len = g_strv_length (str);
g_return_val_if_fail (len != 0, NULL);
langname = (const char *) g_hash_table_lookup (pd->priv->iso_639_table, str[0]);
if (len == 1 && langname != NULL)
{
name = g_strdup (dgettext (ISO_639_DOMAIN, langname));
}
else if (len == 2 && langname != NULL)
{
localename = (const char *) g_hash_table_lookup (pd->priv->iso_3166_table, str[1]);
if (localename != NULL)
{
/* Translators: the first %s is the language name, and the
* second %s is the locale name. Example:
* "French (France)"
*/
name = g_strdup_printf (C_("language", "%s (%s)"),
dgettext (ISO_639_DOMAIN, langname),
dgettext (ISO_3166_DOMAIN, localename));
}
else
{
name = g_strdup_printf (C_("language", "%s (%s)"),
dgettext (ISO_639_DOMAIN, langname), str[1]);
}
}
else
{
/* Translators: this refers to a user-define language code
* (one which isn't in our built-in list).
*/
name = g_strdup_printf (C_("language", "User defined (%s)"), code);
}
g_strfreev (str);
return name;
}
static void
add_system_language_entry (GtkListStore *store)
{
GtkTreeIter iter;
char **sys_langs;
char *system, *text;
int n_sys_langs;
sys_langs = ephy_langs_get_languages ();
n_sys_langs = g_strv_length (sys_langs);
system = g_strjoinv (", ", sys_langs);
text = g_strdup_printf
(ngettext ("System language (%s)",
"System languages (%s)", n_sys_langs), system);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COL_LANG_NAME, text,
COL_LANG_CODE, "system",
-1);
g_strfreev (sys_langs);
g_free (system);
g_free (text);
}
static GtkDialog *
setup_add_language_dialog (PrefsDialog *dialog)
{
GtkWidget *ad;
GtkWidget *add_button;
GtkListStore *store;
GtkTreeModel *sortmodel;
GtkTreeView *treeview;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkTreeSelection *selection;
GtkTreeIter iter;
int i;
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/org/gnome/epiphany/prefs-lang-dialog.ui");
ad = GTK_WIDGET (gtk_builder_get_object (builder, "add_language_dialog"));
add_button = GTK_WIDGET (gtk_builder_get_object (builder, "add_button"));
treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "languages_treeview"));
dialog->priv->add_lang_treeview = treeview;
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
for (i = 0; i < G_N_ELEMENTS (languages); i++)
{
const char *code = languages[i];
char *name;
name = get_name_for_lang_code (dialog, code);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COL_LANG_NAME, name,
COL_LANG_CODE, code,
-1);
g_free (name);
}
add_system_language_entry (store);
sortmodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
gtk_tree_sortable_set_sort_column_id
(GTK_TREE_SORTABLE (sortmodel), COL_LANG_NAME, GTK_SORT_ASCENDING);
gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (dialog)),
GTK_WINDOW (ad));
gtk_window_set_modal (GTK_WINDOW (ad), TRUE);
gtk_tree_view_set_reorderable (GTK_TREE_VIEW (treeview), FALSE);
gtk_tree_view_set_model (treeview, sortmodel);
gtk_tree_view_set_headers_visible (treeview, FALSE);
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (treeview,
0, "Language",
renderer,
"text", 0,
NULL);
column = gtk_tree_view_get_column (treeview, 0);
gtk_tree_view_column_set_resizable (column, TRUE);
gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME);
selection = gtk_tree_view_get_selection (treeview);
gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
add_lang_dialog_selection_changed (GTK_TREE_SELECTION (selection), add_button);
g_signal_connect (selection, "changed",
G_CALLBACK (add_lang_dialog_selection_changed), add_button);
g_signal_connect (ad, "response",
G_CALLBACK (add_lang_dialog_response_cb), dialog);
g_object_unref (store);
g_object_unref (sortmodel);
return GTK_DIALOG (ad);
}
static void
language_editor_add_button_clicked_cb (GtkWidget *button,
PrefsDialog *pd)
{
if (pd->priv->add_lang_dialog == NULL)
{
GtkDialog **add_lang_dialog;
pd->priv->add_lang_dialog = setup_add_language_dialog (pd);
gtk_window_set_transient_for (GTK_WINDOW (pd->priv->add_lang_dialog), GTK_WINDOW (pd));
add_lang_dialog = &pd->priv->add_lang_dialog;
g_object_add_weak_pointer
(G_OBJECT (pd->priv->add_lang_dialog),
(gpointer *) add_lang_dialog);
}
gtk_window_present (GTK_WINDOW (pd->priv->add_lang_dialog));
}
static void
language_editor_remove_button_clicked_cb (GtkWidget *button,
PrefsDialog *pd)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
selection = gtk_tree_view_get_selection (pd->priv->lang_treeview);
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
}
language_editor_update_pref (pd);
language_editor_update_buttons (pd);
}
static void
language_editor_up_button_clicked_cb (GtkWidget *button,
PrefsDialog *pd)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter, iter_prev;
GtkTreePath *path;
selection = gtk_tree_view_get_selection (pd->priv->lang_treeview);
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
path = gtk_tree_model_get_path (model, &iter);
if (!gtk_tree_path_prev (path))
{
gtk_tree_path_free (path);
return;
}
gtk_tree_model_get_iter (model, &iter_prev, path);
gtk_list_store_swap (GTK_LIST_STORE (model), &iter_prev, &iter);
gtk_tree_path_free (path);
}
language_editor_update_pref (pd);
language_editor_update_buttons (pd);
}
static void
language_editor_down_button_clicked_cb (GtkWidget *button,
PrefsDialog *pd)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter, iter_next;
GtkTreePath *path;
selection = gtk_tree_view_get_selection (pd->priv->lang_treeview);
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
path = gtk_tree_model_get_path (model, &iter);
gtk_tree_path_next (path);
gtk_tree_model_get_iter (model, &iter_next, path);
gtk_list_store_swap (GTK_LIST_STORE (model), &iter, &iter_next);
gtk_tree_path_free (path);
}
language_editor_update_pref (pd);
language_editor_update_buttons (pd);
}
static void
language_editor_treeview_drag_end_cb (GtkWidget *widget,
GdkDragContext *context,
PrefsDialog *dialog)
{
language_editor_update_pref (dialog);
language_editor_update_buttons (dialog);
}
static void
language_editor_selection_changed_cb (GtkTreeSelection *selection,
PrefsDialog *dialog)
{
language_editor_update_buttons (dialog);
}
static void
create_language_section (PrefsDialog *dialog)
{
PrefsDialogPrivate *priv = dialog->priv;
GtkListStore *store;
GtkTreeView *treeview;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkTreeSelection *selection;
char **list = NULL;
int i;
priv->iso_639_table = ephy_langs_iso_639_table ();
priv->iso_3166_table = ephy_langs_iso_3166_table ();
g_signal_connect (priv->lang_add_button, "clicked",
G_CALLBACK (language_editor_add_button_clicked_cb), dialog);
g_signal_connect (priv->lang_remove_button, "clicked",
G_CALLBACK (language_editor_remove_button_clicked_cb), dialog);
g_signal_connect (priv->lang_up_button, "clicked",
G_CALLBACK (language_editor_up_button_clicked_cb), dialog);
g_signal_connect (priv->lang_down_button, "clicked",
G_CALLBACK (language_editor_down_button_clicked_cb), dialog);
/* setup the languages treeview */
treeview = priv->lang_treeview;
gtk_tree_view_set_reorderable (treeview, TRUE);
gtk_tree_view_set_headers_visible (treeview, FALSE);
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
priv->lang_model = GTK_TREE_MODEL (store);
gtk_tree_view_set_model (treeview, priv->lang_model);
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (treeview,
0, _("Language"),
renderer,
"text", 0,
NULL);
column = gtk_tree_view_get_column (treeview, 0);
gtk_tree_view_column_set_resizable (column, TRUE);
gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME);
selection = gtk_tree_view_get_selection (treeview);
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
/* Connect treeview signals */
g_signal_connect (G_OBJECT (treeview), "drag_end",
G_CALLBACK (language_editor_treeview_drag_end_cb), dialog);
g_signal_connect (G_OBJECT (selection), "changed",
G_CALLBACK (language_editor_selection_changed_cb), dialog);
list = g_settings_get_strv (EPHY_SETTINGS_WEB,
EPHY_PREFS_WEB_LANGUAGE);
/* Fill languages editor */
for (i = 0; list[i]; i++)
{
const char *code = (const char *) list[i];
if (strcmp (code, "system") == 0)
{
add_system_language_entry (store);
}
else if (code[0] != '\0')
{
char *text;
text = get_name_for_lang_code (dialog, code);
language_editor_add (dialog, code, text);
g_free (text);
}
}
g_object_unref (store);
language_editor_update_buttons (dialog);
g_strfreev (list);
/* Lockdown if key is not writable */
g_settings_bind_writable (EPHY_SETTINGS_WEB,
EPHY_PREFS_WEB_LANGUAGE,
priv->lang_add_button, "sensitive", FALSE);
g_settings_bind_writable (EPHY_SETTINGS_WEB,
EPHY_PREFS_WEB_LANGUAGE,
priv->lang_remove_button, "sensitive", FALSE);
g_settings_bind_writable (EPHY_SETTINGS_WEB,
EPHY_PREFS_WEB_LANGUAGE,
priv->lang_up_button, "sensitive", FALSE);
g_settings_bind_writable (EPHY_SETTINGS_WEB,
EPHY_PREFS_WEB_LANGUAGE,
priv->lang_down_button, "sensitive", FALSE);
g_settings_bind_writable (EPHY_SETTINGS_WEB,
EPHY_PREFS_WEB_LANGUAGE,
priv->lang_treeview, "sensitive", FALSE);
}
static void
download_path_changed_cb (GtkFileChooser *button)
{
char *dir;
dir = gtk_file_chooser_get_filename (button);
if (dir == NULL) return;
g_settings_set_string (EPHY_SETTINGS_STATE,
EPHY_PREFS_STATE_DOWNLOAD_DIR, dir);
g_free (dir);
}
static void
create_download_path_button (PrefsDialog *dialog)
{
GtkWidget *button;
EphyFileChooser *fc;
char *dir;
dir = ephy_file_get_downloads_dir ();
fc = ephy_file_chooser_new (_("Select a Directory"),
GTK_WIDGET (dialog),
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
EPHY_FILE_FILTER_NONE);
/* Unset the destroy-with-parent, since gtkfilechooserbutton doesn't
* expect this */
gtk_window_set_destroy_with_parent (GTK_WINDOW (fc), FALSE);
button = gtk_file_chooser_button_new_with_dialog (GTK_WIDGET (fc));
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (button), dir);
gtk_file_chooser_button_set_width_chars (GTK_FILE_CHOOSER_BUTTON (button),
DOWNLOAD_BUTTON_WIDTH);
g_signal_connect (button, "selection-changed",
G_CALLBACK (download_path_changed_cb), dialog);
gtk_label_set_mnemonic_widget (GTK_LABEL (dialog->priv->download_button_label), button);
gtk_box_pack_start (GTK_BOX (dialog->priv->download_button_hbox), button, TRUE, TRUE, 0);
gtk_widget_show (button);
g_settings_bind_writable (EPHY_SETTINGS_STATE,
EPHY_PREFS_STATE_DOWNLOAD_DIR,
button, "sensitive", FALSE);
g_free (dir);
}
static void
prefs_dialog_response_cb (GtkDialog *widget,
int response,
GtkDialog *dialog)
{
gtk_widget_destroy (GTK_WIDGET (dialog));
}
static void
clear_personal_data_button_clicked_cb (GtkWidget *button,
PrefsDialog *dialog)
{
ClearDataDialog *clear_dialog;
clear_dialog = g_object_new (EPHY_TYPE_CLEAR_DATA_DIALOG,
"use-header-bar", TRUE,
NULL);
gtk_window_set_transient_for (GTK_WINDOW (clear_dialog), GTK_WINDOW (dialog));
gtk_window_set_modal (GTK_WINDOW (clear_dialog), TRUE);
gtk_window_present (GTK_WINDOW (clear_dialog));
}
static gboolean
cookies_get_mapping (GValue *value,
GVariant *variant,
gpointer user_data)
{
const char *setting;
const char *name;
setting = g_variant_get_string (variant, NULL);
name = gtk_buildable_get_name (GTK_BUILDABLE (user_data));
if (g_strcmp0 (name, "no_third_party") == 0)
name = "no-third-party";
/* If the button name matches the setting, it should be active. */
if (g_strcmp0 (name, setting) == 0)
g_value_set_boolean (value, TRUE);
return TRUE;
}
static GVariant *
cookies_set_mapping (const GValue *value,
const GVariantType *expected_type,
gpointer user_data)
{
GVariant *variant = NULL;
const char *name;
/* Don't act unless the button has been activated (turned ON). */
if (!g_value_get_boolean (value))
return NULL;
name = gtk_buildable_get_name (GTK_BUILDABLE (user_data));
if (g_strcmp0 (name, "no_third_party") == 0)
variant = g_variant_new_string ("no-third-party");
else
variant = g_variant_new_string (name);
return variant;
}
static void
search_engine_combo_add_default_engines (GtkListStore *store)
{
int i;
const char *default_engines[][3] = { /* Search engine option in the preferences dialog */
{ N_("DuckDuckGo"),
"https://duckduckgo.com/?q=%s&t=epiphany",
/* For the preferences dialog. Must exactly match the URL
* you chose in the gschema, but with & instead of &
* If the match is not exact, there will be a spurious, ugly
* entry in the preferences combo, so please test this. */
N_("https://duckduckgo.com/?q=%s&t=epiphany")},
/* Search engine option in the preferences dialog */
{ N_("Google"),
"https://google.com/search?q=%s",
/* For the preferences dialog. Consider a regional variant, like google.co.uk */
N_("https://google.com/search?q=%s")},
/* Search engine option in the preferences dialog */
{ N_("Bing"),
"https://www.bing.com/search?q=%s",
/* For the preferences dialog. Consider a regional variant, like uk.bing.com */
N_("https://www.bing.com/search?q=%s")} };
for (i = 0; i < G_N_ELEMENTS (default_engines); ++i)
{
gtk_list_store_insert_with_values (store, NULL, -1,
SEARCH_ENGINE_COL_NAME,
_(default_engines[i][0]),
SEARCH_ENGINE_COL_STOCK_URL,
default_engines[i][1],
SEARCH_ENGINE_COL_URL,
_(default_engines[i][2]),
-1);
}
}
static void
search_engine_combo_add_smart_bookmarks (GtkListStore *store)
{
int i;
EphyBookmarks *bookmarks;
EphyNode *smart_bookmarks_parent_node;
GPtrArray *smart_bookmarks;
bookmarks = ephy_shell_get_bookmarks (ephy_shell_get_default ());
smart_bookmarks_parent_node = ephy_bookmarks_get_smart_bookmarks (bookmarks);
smart_bookmarks = ephy_node_get_children (smart_bookmarks_parent_node);
if (!smart_bookmarks)
return;
for (i = 0; i < smart_bookmarks->len; ++i)
{
EphyNode *bookmark;
const char *bookmark_name;
const char *bookmark_url;
bookmark = g_ptr_array_index (smart_bookmarks, i);
bookmark_name = ephy_node_get_property_string (bookmark, EPHY_NODE_BMK_PROP_TITLE);
bookmark_url = ephy_node_get_property_string (bookmark, EPHY_NODE_BMK_PROP_LOCATION);
if (!bookmark_name || !bookmark_url)
continue;
if (strcmp (bookmark_name, DEFAULT_SMART_BOOKMARK_TEXT) == 0)
continue;
gtk_list_store_insert_with_values (store, NULL, -1,
SEARCH_ENGINE_COL_NAME, bookmark_name,
SEARCH_ENGINE_COL_STOCK_URL, bookmark_url,
SEARCH_ENGINE_COL_URL, bookmark_url,
-1);
}
}
/* Has the user manually set the engine to something not in the combo?
* If so, add that URL as an extra item in the combo. */
static void
search_engine_combo_add_current_engine (GtkListStore *store)
{
GtkTreeIter iter;
char *original_url;
gboolean in_combo = FALSE;
gboolean has_next = FALSE;
original_url = g_settings_get_string (EPHY_SETTINGS_MAIN,
EPHY_PREFS_KEYWORD_SEARCH_URL);
if (!original_url)
return;
has_next = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
while (!in_combo && has_next)
{
char *stock_url, *url;
gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
SEARCH_ENGINE_COL_STOCK_URL, &stock_url,
SEARCH_ENGINE_COL_URL, &url, -1);
if (strcmp (original_url, stock_url) == 0 ||
strcmp (original_url, url) == 0)
in_combo = TRUE;
g_free (stock_url);
g_free (url);
has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
}
if (!in_combo)
gtk_list_store_insert_with_values (store, NULL, -1,
SEARCH_ENGINE_COL_NAME, original_url,
SEARCH_ENGINE_COL_STOCK_URL, original_url,
SEARCH_ENGINE_COL_URL, original_url,
-1);
g_free (original_url);
}
static void
create_search_engine_combo (GtkComboBox *combo)
{
GtkCellRenderer *renderer;
GtkListStore *store;
store = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
search_engine_combo_add_default_engines (store);
search_engine_combo_add_smart_bookmarks (store);
search_engine_combo_add_current_engine (store);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), SEARCH_ENGINE_COL_NAME,
GTK_SORT_ASCENDING);
gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
"text", SEARCH_ENGINE_COL_NAME,
NULL);
g_settings_bind_with_mapping (EPHY_SETTINGS_MAIN,
EPHY_PREFS_KEYWORD_SEARCH_URL,
combo, "active",
G_SETTINGS_BIND_DEFAULT,
combo_get_mapping,
combo_set_mapping,
combo,
NULL);
}
static void
setup_general_page (PrefsDialog *dialog)
{
PrefsDialogPrivate *priv = dialog->priv;
GSettings *settings;
GSettings *web_settings;
settings = ephy_settings_get (EPHY_PREFS_SCHEMA);
web_settings = ephy_settings_get (EPHY_PREFS_WEB_SCHEMA);
g_settings_bind (settings,
EPHY_PREFS_AUTO_DOWNLOADS,
priv->automatic_downloads_checkbutton,
"active",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (web_settings,
EPHY_PREFS_WEB_ENABLE_POPUPS,
priv->popups_allow_checkbutton,
"active",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (web_settings,
EPHY_PREFS_WEB_ENABLE_ADBLOCK,
priv->adblock_allow_checkbutton,
"active",
G_SETTINGS_BIND_INVERT_BOOLEAN);
g_settings_bind (web_settings,
EPHY_PREFS_WEB_ENABLE_PLUGINS,
priv->enable_plugins_checkbutton,
"active",
G_SETTINGS_BIND_DEFAULT);
create_download_path_button (dialog);
create_search_engine_combo (GTK_COMBO_BOX (dialog->priv->search_engine_combo));
}
static void
setup_fonts_page (PrefsDialog *dialog)
{
PrefsDialogPrivate *priv = dialog->priv;
GSettings *web_settings;
web_settings = ephy_settings_get (EPHY_PREFS_WEB_SCHEMA);
g_settings_bind (web_settings,
EPHY_PREFS_WEB_USE_GNOME_FONTS,
priv->use_gnome_fonts_checkbutton,
"active",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (web_settings,
EPHY_PREFS_WEB_USE_GNOME_FONTS,
priv->custom_fonts_table,
"sensitive",
G_SETTINGS_BIND_GET | G_SETTINGS_BIND_INVERT_BOOLEAN);
g_settings_bind (web_settings,
EPHY_PREFS_WEB_SANS_SERIF_FONT,
priv->sans_fontbutton,
"font-name",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (web_settings,
EPHY_PREFS_WEB_SERIF_FONT,
priv->serif_fontbutton,
"font-name",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (web_settings,
EPHY_PREFS_WEB_MONOSPACE_FONT,
priv->mono_fontbutton,
"font-name",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (web_settings,
EPHY_PREFS_WEB_ENABLE_USER_CSS,
priv->css_checkbox,
"active",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (web_settings,
EPHY_PREFS_WEB_ENABLE_USER_CSS,
priv->css_edit_button,
"sensitive",
G_SETTINGS_BIND_GET);
g_signal_connect (priv->css_edit_button,
"clicked",
G_CALLBACK (css_edit_button_clicked_cb),
dialog);
}
static void
setup_privacy_page (PrefsDialog *dialog)
{
PrefsDialogPrivate *priv = dialog->priv;
GSettings *settings;
GSettings *web_settings;
settings = ephy_settings_get (EPHY_PREFS_SCHEMA);
web_settings = ephy_settings_get (EPHY_PREFS_WEB_SCHEMA);
g_settings_bind_with_mapping (web_settings,
EPHY_PREFS_WEB_COOKIES_POLICY,
priv->always,
"active",
G_SETTINGS_BIND_DEFAULT,
cookies_get_mapping,
cookies_set_mapping,
priv->always,
NULL);
g_settings_bind_with_mapping (web_settings,
EPHY_PREFS_WEB_COOKIES_POLICY,
priv->no_third_party,
"active",
G_SETTINGS_BIND_DEFAULT,
cookies_get_mapping,
cookies_set_mapping,
priv->no_third_party,
NULL);
g_settings_bind_with_mapping (web_settings,
EPHY_PREFS_WEB_COOKIES_POLICY,
priv->never,
"active",
G_SETTINGS_BIND_DEFAULT,
cookies_get_mapping,
cookies_set_mapping,
priv->never,
NULL);
g_settings_bind (settings,
EPHY_PREFS_REMEMBER_PASSWORDS,
priv->remember_passwords_checkbutton,
"active",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (web_settings,
EPHY_PREFS_WEB_DO_NOT_TRACK,
priv->do_not_track_checkbutton,
"active",
G_SETTINGS_BIND_DEFAULT);
g_signal_connect (priv->clear_personal_data_button,
"clicked",
G_CALLBACK (clear_personal_data_button_clicked_cb),
dialog);
}
static void
setup_language_page (PrefsDialog *dialog)
{
PrefsDialogPrivate *priv = dialog->priv;
GSettings *web_settings;
EphyEncodings *encodings;
web_settings = ephy_settings_get (EPHY_PREFS_WEB_SCHEMA);
g_settings_bind (web_settings,
EPHY_PREFS_WEB_ENABLE_SPELL_CHECKING,
priv->enable_spell_checking_checkbutton,
"active",
G_SETTINGS_BIND_DEFAULT);
encodings = EPHY_ENCODINGS (ephy_embed_shell_get_encodings (EPHY_EMBED_SHELL (ephy_shell_get_default ())));
create_node_combo (dialog, encodings, "ISO-8859-1");
create_language_section (dialog);
}
static void
prefs_dialog_init (PrefsDialog *dialog)
{
dialog->priv = prefs_dialog_get_instance_private (dialog);
gtk_widget_init_template (GTK_WIDGET (dialog));
setup_general_page (dialog);
setup_fonts_page (dialog);
setup_privacy_page (dialog);
setup_language_page (dialog);
ephy_gui_ensure_window_group (GTK_WINDOW (dialog));
g_signal_connect (dialog, "response",
G_CALLBACK (prefs_dialog_response_cb), dialog);
}