find-dialog.c: Replace exp10 with our own integer version
[pspp] / src / ui / gui / psppire-encoding-selector.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2011, 2012, 2014 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "ui/gui/psppire-encoding-selector.h"
20
21 #include <stdlib.h>
22
23 #include "libpspp/cast.h"
24 #include "libpspp/compiler.h"
25 #include "libpspp/i18n.h"
26
27 #include "gl/c-strcase.h"
28 #include "gl/localcharset.h"
29 #include "gl/xalloc.h"
30 #include "gl/xvasprintf.h"
31
32 #include "gettext.h"
33 #define _(msgid) gettext (msgid)
34 #define N_(msgid) msgid
35
36 enum
37   {
38     COL_DESCRIPTION,
39     COL_ENCODING
40   };
41
42 static void
43 add_encodings (GtkTreeStore *store, struct encoding_category *cat)
44 {
45   if (cat->n_encodings == 1)
46     {
47       char *description;
48
49       if (strcmp (cat->encodings[0], "Auto"))
50         description = xasprintf ("%s (%s)", cat->category, cat->encodings[0]);
51       else
52         description = xstrdup (cat->category);
53
54       gtk_tree_store_insert_with_values (
55         store, NULL, NULL, G_MAXINT,
56         COL_DESCRIPTION, description,
57         COL_ENCODING, cat->encodings[0],
58         -1);
59
60       free (description);
61     }
62   else
63     {
64       GtkTreeIter head;
65       int i;
66
67       gtk_tree_store_insert_with_values (
68         store, &head, NULL, G_MAXINT,
69         COL_DESCRIPTION, cat->category,
70         -1);
71
72       for (i = 0; i < cat->n_encodings; i++)
73         gtk_tree_store_insert_with_values (
74           store, NULL, &head, G_MAXINT,
75           COL_DESCRIPTION, cat->encodings[i],
76           COL_ENCODING, cat->encodings[i],
77           -1);
78     }
79 }
80
81 static void
82 set_sensitive (GtkCellLayout   *cell_layout,
83                GtkCellRenderer *cell,
84                GtkTreeModel    *tree_model,
85                GtkTreeIter     *iter,
86                gpointer         data)
87 {
88   gboolean sensitive;
89
90   sensitive = !gtk_tree_model_iter_has_child (tree_model, iter);
91   g_object_set (cell, "sensitive", sensitive, NULL);
92 }
93
94 struct find_default_encoding_aux
95   {
96     const char *default_encoding;
97     GtkTreeIter iter;
98   };
99
100 static gboolean
101 find_default_encoding (GtkTreeModel *model,
102                        GtkTreePath *path,
103                        GtkTreeIter *iter,
104                        gpointer aux_)
105 {
106   struct find_default_encoding_aux *aux = aux_;
107   gchar *encoding;
108   gboolean found;
109
110   gtk_tree_model_get (model, iter, COL_ENCODING, &encoding, -1);
111   found = encoding != NULL && !c_strcasecmp (encoding, aux->default_encoding);
112   if (found)
113     aux->iter = *iter;
114   g_free (encoding);
115   return found;
116 }
117
118 GtkWidget *
119 psppire_encoding_selector_new (const char *default_encoding,
120                                gboolean allow_auto)
121 {
122   struct find_default_encoding_aux aux;
123   struct encoding_category *categories;
124   struct encoding_category locale_cat;
125   const char *locale_encoding;
126   GtkCellRenderer *renderer;
127   GtkWidget *hbox;
128   GtkWidget *combo_box;
129   GtkTreeStore *store;
130   size_t n_categories;
131   size_t i;
132
133   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
134
135   if (allow_auto)
136     {
137       struct encoding_category auto_cat;
138       const char *encoding = "Auto";
139
140       auto_cat.category = _("Automatically Detect");
141       auto_cat.encodings = &encoding;
142       auto_cat.n_encodings = 1;
143       add_encodings (store, &auto_cat);
144     }
145
146   locale_encoding = locale_charset ();
147   locale_cat.category = _("Locale Encoding");
148   locale_cat.encodings = &locale_encoding;
149   locale_cat.n_encodings = 1;
150   add_encodings (store, &locale_cat);
151
152   categories = get_encoding_categories ();
153   n_categories = get_n_encoding_categories ();
154   for (i = 0; i < n_categories; i++)
155     add_encodings (store, &categories[i]);
156
157   combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
158
159   aux.default_encoding = default_encoding ? default_encoding : "Auto";
160   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &aux.iter);
161   gtk_tree_model_foreach (GTK_TREE_MODEL (store), find_default_encoding, &aux);
162   gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &aux.iter);
163
164   g_object_unref (store);
165
166   renderer = gtk_cell_renderer_text_new ();
167   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
168   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
169                                   "text", COL_DESCRIPTION,
170                                   NULL);
171   gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box),
172                                       renderer, set_sensitive,
173                                       NULL, NULL);
174
175   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
176   gtk_box_pack_start (GTK_BOX (hbox),
177                       gtk_label_new (_("Character Encoding: ")),
178                       FALSE, FALSE, 0);
179   gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, TRUE, 0);
180   gtk_widget_show_all (hbox);
181
182   return hbox;
183 }
184
185 /*
186    Return a string describing the currently selected encoding.
187    The caller should free this string when no longer required.
188 */
189 gchar *
190 psppire_encoding_selector_get_encoding (GtkWidget *selector)
191 {
192   gchar *encoding = NULL;
193   GList *pos;
194   GList *list = gtk_container_get_children (GTK_CONTAINER (selector));
195
196   for (pos = list; pos; pos = pos->next)
197     {
198       GtkWidget *widget = pos->data;
199       if (GTK_IS_COMBO_BOX (widget))
200         {
201           GtkTreeModel *model;
202           GtkTreeIter iter;
203
204           if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter))
205             break;
206
207           model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
208           gtk_tree_model_get (model, &iter, COL_ENCODING, &encoding, -1);
209           break;
210         }
211     }
212
213   g_list_free (list);
214
215   if (0 == strcmp (encoding, "Auto"))
216     {
217       g_free (encoding);
218       return NULL;
219     }
220
221   return encoding;
222 }