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