1 /*
2  * xed-encodings-dialog.c
3  * This file is part of xed
4  *
5  * Copyright (C) 2002-2005 Paolo Maggi
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 /*
24  * Modified by the xed Team, 2002-2005. See the AUTHORS file for a
25  * list of people on the xed Team.
26  * See the ChangeLog files for a list of changes.
27  *
28  * $Id$
29  */
30 
31 #include <config.h>
32 #include <string.h>
33 #include <glib/gi18n.h>
34 #include <gtksourceview/gtksource.h>
35 
36 #include "xed-encodings-dialog.h"
37 #include "xed-utils.h"
38 #include "xed-debug.h"
39 #include "xed-dirs.h"
40 #include "xed-settings.h"
41 
42 struct _XedEncodingsDialogPrivate
43 {
44     GSettings *enc_settings;
45 
46     GtkListStore *available_liststore;
47     GtkListStore *displayed_liststore;
48 
49     GtkWidget *available_treeview;
50     GtkWidget *displayed_treeview;
51     GtkWidget *add_button;
52     GtkWidget *remove_button;
53 
54     GSList       *show_in_menu_list;
55 };
56 
G_DEFINE_TYPE_WITH_PRIVATE(XedEncodingsDialog,xed_encodings_dialog,GTK_TYPE_DIALOG)57 G_DEFINE_TYPE_WITH_PRIVATE (XedEncodingsDialog, xed_encodings_dialog, GTK_TYPE_DIALOG)
58 
59 static void
60 xed_encodings_dialog_finalize (GObject *object)
61 {
62     XedEncodingsDialogPrivate *priv = XED_ENCODINGS_DIALOG (object)->priv;
63 
64     g_slist_free (priv->show_in_menu_list);
65 
66     G_OBJECT_CLASS (xed_encodings_dialog_parent_class)->finalize (object);
67 }
68 
69 static void
xed_encodings_dialog_dispose(GObject * object)70 xed_encodings_dialog_dispose (GObject *object)
71 {
72     XedEncodingsDialogPrivate *priv = XED_ENCODINGS_DIALOG (object)->priv;
73 
74     g_clear_object (&priv->enc_settings);
75 
76     G_OBJECT_CLASS (xed_encodings_dialog_parent_class)->dispose (object);
77 }
78 
79 static void
xed_encodings_dialog_class_init(XedEncodingsDialogClass * klass)80 xed_encodings_dialog_class_init (XedEncodingsDialogClass *klass)
81 {
82     GObjectClass *object_class = G_OBJECT_CLASS (klass);
83 
84     object_class->finalize = xed_encodings_dialog_finalize;
85     object_class->dispose = xed_encodings_dialog_dispose;
86 }
87 
88 enum
89 {
90     COLUMN_NAME,
91     COLUMN_CHARSET,
92     N_COLUMNS
93 };
94 
95 static void
count_selected_items_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)96 count_selected_items_func (GtkTreeModel *model,
97                            GtkTreePath  *path,
98                            GtkTreeIter  *iter,
99                            gpointer      data)
100 {
101     int *count = data;
102 
103     *count += 1;
104 }
105 
106 static void
available_selection_changed_callback(GtkTreeSelection * selection,XedEncodingsDialog * dialogs)107 available_selection_changed_callback (GtkTreeSelection   *selection,
108                                       XedEncodingsDialog *dialogs)
109 {
110     int count;
111 
112     count = 0;
113     gtk_tree_selection_selected_foreach (selection, count_selected_items_func, &count);
114 
115     gtk_widget_set_sensitive (dialogs->priv->add_button, count > 0);
116 }
117 
118 static void
displayed_selection_changed_callback(GtkTreeSelection * selection,XedEncodingsDialog * dialogs)119 displayed_selection_changed_callback (GtkTreeSelection   *selection,
120                                       XedEncodingsDialog *dialogs)
121 {
122     int count;
123 
124     count = 0;
125     gtk_tree_selection_selected_foreach (selection, count_selected_items_func, &count);
126 
127     gtk_widget_set_sensitive (dialogs->priv->remove_button, count > 0);
128 }
129 
130 static void
get_selected_encodings_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)131 get_selected_encodings_func (GtkTreeModel *model,
132                              GtkTreePath  *path,
133                              GtkTreeIter  *iter,
134                              gpointer      data)
135 {
136     GSList **list = data;
137     gchar *charset;
138     const GtkSourceEncoding *enc;
139 
140     charset = NULL;
141     gtk_tree_model_get (model, iter, COLUMN_CHARSET, &charset, -1);
142 
143     enc = gtk_source_encoding_get_from_charset (charset);
144     g_free (charset);
145 
146     *list = g_slist_prepend (*list, (gpointer)enc);
147 }
148 
149 static void
update_shown_in_menu_tree_model(GtkListStore * store,GSList * list)150 update_shown_in_menu_tree_model (GtkListStore *store,
151                                  GSList       *list)
152 {
153     GtkTreeIter iter;
154 
155     gtk_list_store_clear (store);
156 
157     while (list != NULL)
158     {
159         const GtkSourceEncoding *enc;
160 
161         enc = list->data;
162 
163         gtk_list_store_append (store, &iter);
164         gtk_list_store_set (store, &iter,
165                             COLUMN_CHARSET, gtk_source_encoding_get_charset (enc),
166                             COLUMN_NAME, gtk_source_encoding_get_name (enc),
167                             -1);
168 
169         list = g_slist_next (list);
170     }
171 }
172 
173 static void
add_button_clicked_callback(GtkWidget * button,XedEncodingsDialog * dialog)174 add_button_clicked_callback (GtkWidget          *button,
175                              XedEncodingsDialog *dialog)
176 {
177     GtkTreeSelection *selection;
178     GSList *encodings;
179     GSList *tmp;
180 
181     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->available_treeview));
182 
183     encodings = NULL;
184     gtk_tree_selection_selected_foreach (selection, get_selected_encodings_func, &encodings);
185 
186     tmp = encodings;
187     while (tmp != NULL)
188     {
189         if (g_slist_find (dialog->priv->show_in_menu_list, tmp->data) == NULL)
190             dialog->priv->show_in_menu_list = g_slist_prepend (dialog->priv->show_in_menu_list, tmp->data);
191 
192         tmp = g_slist_next (tmp);
193     }
194 
195     g_slist_free (encodings);
196 
197     update_shown_in_menu_tree_model (GTK_LIST_STORE (dialog->priv->displayed_liststore),
198                                      dialog->priv->show_in_menu_list);
199 }
200 
201 static void
remove_button_clicked_callback(GtkWidget * button,XedEncodingsDialog * dialog)202 remove_button_clicked_callback (GtkWidget          *button,
203                                 XedEncodingsDialog *dialog)
204 {
205     GtkTreeSelection *selection;
206     GSList *encodings;
207     GSList *tmp;
208 
209     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->displayed_treeview));
210 
211     encodings = NULL;
212     gtk_tree_selection_selected_foreach (selection, get_selected_encodings_func, &encodings);
213 
214     tmp = encodings;
215     while (tmp != NULL)
216     {
217         dialog->priv->show_in_menu_list = g_slist_remove (dialog->priv->show_in_menu_list, tmp->data);
218 
219         tmp = g_slist_next (tmp);
220     }
221 
222     g_slist_free (encodings);
223 
224     update_shown_in_menu_tree_model (GTK_LIST_STORE (dialog->priv->displayed_liststore),
225                                      dialog->priv->show_in_menu_list);
226 }
227 
228 static void
init_shown_in_menu_tree_model(XedEncodingsDialog * dialog)229 init_shown_in_menu_tree_model (XedEncodingsDialog *dialog)
230 {
231     GtkTreeIter iter;
232     gchar **enc_strv;
233     GSList *list, *tmp;
234 
235     /* add data to the list store */
236     enc_strv = g_settings_get_strv (dialog->priv->enc_settings, XED_SETTINGS_ENCODING_SHOWN_IN_MENU);
237 
238     list = _xed_utils_encoding_strv_to_list ((const gchar * const *)enc_strv);
239 
240     for (tmp = list; tmp != NULL; tmp = g_slist_next (tmp))
241     {
242         const GtkSourceEncoding *enc = tmp->data;
243 
244         dialog->priv->show_in_menu_list = g_slist_prepend (dialog->priv->show_in_menu_list, tmp->data);
245 
246         gtk_list_store_append (dialog->priv->displayed_liststore, &iter);
247         gtk_list_store_set (dialog->priv->displayed_liststore, &iter,
248                             COLUMN_CHARSET, gtk_source_encoding_get_charset (enc),
249                             COLUMN_NAME, gtk_source_encoding_get_name (enc),
250                             -1);
251     }
252 
253     g_slist_free (list);
254 }
255 
256 static void
response_handler(GtkDialog * dialog,gint response_id,XedEncodingsDialog * dlg)257 response_handler (GtkDialog          *dialog,
258                   gint                response_id,
259                   XedEncodingsDialog *dlg)
260 {
261     if (response_id == GTK_RESPONSE_HELP)
262     {
263         xed_app_show_help (XED_APP (g_application_get_default ()), GTK_WINDOW (dialog), "xed", NULL);
264         g_signal_stop_emission_by_name (dialog, "response");
265         return;
266     }
267 
268     if (response_id == GTK_RESPONSE_OK)
269     {
270         gchar **encs;
271 
272         encs = _xed_utils_encoding_list_to_strv (dlg->priv->show_in_menu_list);
273         g_settings_set_strv (dlg->priv->enc_settings,
274                              XED_SETTINGS_ENCODING_SHOWN_IN_MENU,
275                              (const gchar * const *)encs);
276 
277         g_strfreev (encs);
278     }
279 }
280 
281 static void
init_liststore_available(XedEncodingsDialog * dialog)282 init_liststore_available (XedEncodingsDialog *dialog)
283 {
284     GSList *all_encodings;
285     GSList *l;
286 
287     all_encodings = gtk_source_encoding_get_all ();
288 
289     for (l = all_encodings; l != NULL; l = l->next)
290     {
291         const GtkSourceEncoding *encoding = l->data;
292         GtkTreeIter iter;
293 
294         if (encoding == gtk_source_encoding_get_utf8 ())
295         {
296             /* The UTF-8 encoding is always added to the combobox. */
297             continue;
298         }
299 
300         gtk_list_store_append (dialog->priv->available_liststore, &iter);
301 
302         gtk_list_store_set (dialog->priv->available_liststore,
303                             &iter,
304                             COLUMN_CHARSET, gtk_source_encoding_get_charset (encoding),
305                             COLUMN_NAME, gtk_source_encoding_get_name (encoding),
306                             -1);
307     }
308 
309     g_slist_free (all_encodings);
310 }
311 
312 static void
xed_encodings_dialog_init(XedEncodingsDialog * dlg)313 xed_encodings_dialog_init (XedEncodingsDialog *dlg)
314 {
315     GtkBuilder *builder;
316     GtkWidget *content;
317     GtkCellRenderer *cell_renderer;
318     GtkTreeModel *sort_model;
319     GtkTreeViewColumn *column;
320     GtkTreeSelection *selection;
321     gchar *root_objects[] = {
322         "encodings-dialog-contents",
323         NULL
324     };
325 
326     dlg->priv = xed_encodings_dialog_get_instance_private (dlg);
327     dlg->priv->enc_settings = g_settings_new ("org.x.editor.preferences.encodings");
328 
329     gtk_dialog_add_buttons (GTK_DIALOG (dlg),
330                             _("_Cancel"), GTK_RESPONSE_CANCEL,
331                             _("_OK"), GTK_RESPONSE_OK,
332                             _("_Help"), GTK_RESPONSE_HELP,
333                             NULL);
334 
335     gtk_window_set_title (GTK_WINDOW (dlg), _("Character Encodings"));
336     gtk_window_set_default_size (GTK_WINDOW (dlg), 650, 400);
337 
338     /* HIG defaults */
339     gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
340     gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), 2); /* 2 * 5 + 2 = 12 */
341 
342     gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
343 
344     g_signal_connect (dlg, "response", G_CALLBACK (response_handler), dlg);
345 
346     builder = gtk_builder_new ();
347     gtk_builder_add_objects_from_resource (builder, "/org/x/editor/ui/xed-encodings-dialog.ui",
348                                            root_objects, NULL);
349     content = GTK_WIDGET (gtk_builder_get_object (builder, "encodings-dialog-contents"));
350     g_object_ref (content);
351     dlg->priv->add_button = GTK_WIDGET (gtk_builder_get_object (builder, "add-button"));
352     dlg->priv->remove_button = GTK_WIDGET (gtk_builder_get_object (builder, "remove-button"));
353     dlg->priv->available_treeview = GTK_WIDGET (gtk_builder_get_object (builder, "available-treeview"));
354     dlg->priv->displayed_treeview = GTK_WIDGET (gtk_builder_get_object (builder, "displayed-treeview"));
355     g_object_unref (builder);
356 
357     gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), content, TRUE, TRUE, 0);
358     g_object_unref (content);
359     gtk_container_set_border_width (GTK_CONTAINER (content), 5);
360 
361     g_signal_connect (dlg->priv->add_button, "clicked", G_CALLBACK (add_button_clicked_callback), dlg);
362     g_signal_connect (dlg->priv->remove_button, "clicked", G_CALLBACK (remove_button_clicked_callback), dlg);
363 
364     /* Tree view of available encodings */
365     dlg->priv->available_liststore = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
366 
367     cell_renderer = gtk_cell_renderer_text_new ();
368     column = gtk_tree_view_column_new_with_attributes (_("_Description"),
369                                                        cell_renderer,
370                                                        "text", COLUMN_NAME,
371                                                        NULL);
372     gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->priv->available_treeview), column);
373     gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
374 
375     cell_renderer = gtk_cell_renderer_text_new ();
376     column = gtk_tree_view_column_new_with_attributes (_("_Encoding"),
377                                                        cell_renderer,
378                                                        "text",
379                                                        COLUMN_CHARSET,
380                                                        NULL);
381     gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->priv->available_treeview), column);
382     gtk_tree_view_column_set_sort_column_id (column, COLUMN_CHARSET);
383 
384     /* Add the data */
385     init_liststore_available (dlg);
386 
387     /* Sort model */
388     sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (dlg->priv->available_liststore));
389     gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model), COLUMN_NAME, GTK_SORT_ASCENDING);
390 
391     gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->priv->available_treeview), sort_model);
392     g_object_unref (G_OBJECT (dlg->priv->available_liststore));
393     g_object_unref (G_OBJECT (sort_model));
394 
395     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->priv->available_treeview));
396     gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection), GTK_SELECTION_MULTIPLE);
397 
398     available_selection_changed_callback (selection, dlg);
399     g_signal_connect (selection, "changed", G_CALLBACK (available_selection_changed_callback), dlg);
400 
401     /* Tree view of selected encodings */
402     dlg->priv->displayed_liststore = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
403 
404     cell_renderer = gtk_cell_renderer_text_new ();
405     column = gtk_tree_view_column_new_with_attributes (_("_Description"),
406                                                        cell_renderer,
407                                                        "text", COLUMN_NAME,
408                                                        NULL);
409     gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->priv->displayed_treeview), column);
410     gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
411 
412     cell_renderer = gtk_cell_renderer_text_new ();
413     column = gtk_tree_view_column_new_with_attributes (_("_Encoding"),
414                                                        cell_renderer,
415                                                        "text",
416                                                        COLUMN_CHARSET,
417                                                        NULL);
418     gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->priv->displayed_treeview), column);
419     gtk_tree_view_column_set_sort_column_id (column, COLUMN_CHARSET);
420 
421     /* Add the data */
422     init_shown_in_menu_tree_model (dlg);
423 
424     /* Sort model */
425     sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (dlg->priv->displayed_liststore));
426 
427     gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model), COLUMN_NAME, GTK_SORT_ASCENDING);
428 
429     gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->priv->displayed_treeview), sort_model);
430     g_object_unref (G_OBJECT (sort_model));
431     g_object_unref (G_OBJECT (dlg->priv->displayed_liststore));
432 
433     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->priv->displayed_treeview));
434     gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection), GTK_SELECTION_MULTIPLE);
435 
436     displayed_selection_changed_callback (selection, dlg);
437     g_signal_connect (selection, "changed", G_CALLBACK (displayed_selection_changed_callback), dlg);
438 }
439 
440 GtkWidget *
xed_encodings_dialog_new(void)441 xed_encodings_dialog_new (void)
442 {
443     GtkWidget *dlg;
444 
445     dlg = GTK_WIDGET (g_object_new (XED_TYPE_ENCODINGS_DIALOG, NULL));
446 
447     return dlg;
448 }
449 
450