Fix bug when searching through an empty dataset.
[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 <assert.h>
22 #include <stdlib.h>
23
24 #include "libpspp/cast.h"
25 #include "libpspp/compiler.h"
26 #include "libpspp/i18n.h"
27
28 #include "gl/c-strcase.h"
29 #include "gl/localcharset.h"
30 #include "gl/xalloc.h"
31 #include "gl/xvasprintf.h"
32
33 #include "gettext.h"
34 #define _(msgid) gettext (msgid)
35 #define N_(msgid) msgid
36
37 enum
38   {
39     COL_DESCRIPTION,
40     COL_ENCODING
41   };
42
43 static void
44 add_encodings (GtkTreeStore *store, struct encoding_category *cat)
45 {
46   if (cat->n_encodings == 1)
47     {
48       char *description;
49
50       if (strcmp (cat->encodings[0], "Auto"))
51         description = xasprintf ("%s (%s)", cat->category, cat->encodings[0]);
52       else
53         description = xstrdup (cat->category);
54
55       gtk_tree_store_insert_with_values (
56         store, NULL, NULL, G_MAXINT,
57         COL_DESCRIPTION, description,
58         COL_ENCODING, cat->encodings[0],
59         -1);
60
61       free (description);
62     }
63   else
64     {
65       GtkTreeIter head;
66       int i;
67
68       gtk_tree_store_insert_with_values (
69         store, &head, NULL, G_MAXINT,
70         COL_DESCRIPTION, cat->category,
71         -1);
72
73       for (i = 0; i < cat->n_encodings; i++)
74         gtk_tree_store_insert_with_values (
75           store, NULL, &head, G_MAXINT,
76           COL_DESCRIPTION, cat->encodings[i],
77           COL_ENCODING, cat->encodings[i],
78           -1);
79     }
80 }
81
82 static void
83 set_sensitive (GtkCellLayout   *cell_layout,
84                GtkCellRenderer *cell,
85                GtkTreeModel    *tree_model,
86                GtkTreeIter     *iter,
87                gpointer         data)
88 {
89   gboolean sensitive;
90
91   sensitive = !gtk_tree_model_iter_has_child (tree_model, iter);
92   g_object_set (cell, "sensitive", sensitive, NULL);
93 }
94
95 struct find_default_encoding_aux
96   {
97     const char *default_encoding;
98     GtkTreeIter iter;
99   };
100
101 static gboolean
102 find_default_encoding (GtkTreeModel *model,
103                        GtkTreePath *path,
104                        GtkTreeIter *iter,
105                        gpointer aux_)
106 {
107   struct find_default_encoding_aux *aux = aux_;
108   gchar *encoding;
109   gboolean found;
110
111   gtk_tree_model_get (model, iter, COL_ENCODING, &encoding, -1);
112   found = encoding != NULL && !c_strcasecmp (encoding, aux->default_encoding);
113   if (found)
114     aux->iter = *iter;
115   g_free (encoding);
116   return found;
117 }
118
119 GtkWidget *
120 psppire_encoding_selector_new (const char *default_encoding,
121                                gboolean allow_auto)
122 {
123   struct find_default_encoding_aux aux;
124   struct encoding_category *categories;
125   struct encoding_category locale_cat;
126   const char *locale_encoding;
127   GtkCellRenderer *renderer;
128   GtkWidget *hbox;
129   GtkWidget *combo_box;
130   GtkTreeStore *store;
131   size_t n_categories;
132   size_t i;
133
134   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
135
136   if (allow_auto)
137     {
138       struct encoding_category auto_cat;
139       const char *encoding = "Auto";
140
141       auto_cat.category = _("Automatically Detect");
142       auto_cat.encodings = &encoding;
143       auto_cat.n_encodings = 1;
144       add_encodings (store, &auto_cat);
145     }
146
147   locale_encoding = locale_charset ();
148   locale_cat.category = _("Locale Encoding");
149   locale_cat.encodings = &locale_encoding;
150   locale_cat.n_encodings = 1;
151   add_encodings (store, &locale_cat);
152
153   categories = get_encoding_categories ();
154   n_categories = get_n_encoding_categories ();
155   for (i = 0; i < n_categories; i++)
156     add_encodings (store, &categories[i]);
157
158   combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
159
160   aux.default_encoding = default_encoding ? default_encoding : "Auto";
161   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &aux.iter);
162   gtk_tree_model_foreach (GTK_TREE_MODEL (store), find_default_encoding, &aux);
163   gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &aux.iter);
164
165   g_object_unref (store);
166
167   renderer = gtk_cell_renderer_text_new ();
168   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
169   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
170                                   "text", COL_DESCRIPTION,
171                                   NULL);
172   gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box),
173                                       renderer, set_sensitive,
174                                       NULL, NULL);
175
176   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
177   gtk_box_pack_start (GTK_BOX (hbox),
178                       gtk_label_new (_("Character Encoding: ")),
179                       FALSE, FALSE, 0);
180   gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, TRUE, 0);
181   gtk_widget_show_all (hbox);
182
183   return hbox;
184 }
185
186 gchar *
187 psppire_encoding_selector_get_encoding (GtkWidget *selector)
188 {
189   gchar *encoding = NULL;
190   GList *list, *pos;
191
192   list = gtk_container_get_children (GTK_CONTAINER (selector));
193   for (pos = list; pos; pos = pos->next)
194     {
195       GtkWidget *widget = pos->data;
196       if (GTK_IS_COMBO_BOX (widget))
197         {
198           GtkTreeModel *model;
199           GtkTreeIter iter;
200
201           if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter))
202             break;
203
204           model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
205           gtk_tree_model_get (model, &iter, COL_ENCODING, &encoding, -1);
206           break;
207         }
208     }
209   g_list_free (list);
210
211   return encoding && !strcmp (encoding, "Auto") ? NULL : encoding;
212 }