1 /* Copyright (c) 2008, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #define _GNU_SOURCE /* So we can use the getline() function, which is a convenient GNU extension. */
36 #include "modest-maemo-utils.h"
37 #include "modest-country-picker.h"
38 #include <hildon/hildon-touch-selector-entry.h>
39 #include <gtk/gtkliststore.h>
40 #include <gtk/gtkcelllayout.h>
41 #include <gtk/gtkcellrenderertext.h>
44 #include <string.h> /* For memcpy() */
47 #include <libintl.h> /* For dgettext(). */
49 /* Include config.h so that _() works: */
54 #define MAX_LINE_LEN 128 /* max length of a line in MCC file */
56 G_DEFINE_TYPE (ModestCountryPicker, modest_country_picker, HILDON_TYPE_PICKER_BUTTON);
61 /* GtkTreeModel *model; */
62 } ModestCountryPickerPrivate;
64 #define MODEST_COUNTRY_PICKER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
65 MODEST_TYPE_COUNTRY_PICKER, \
66 ModestCountryPickerPrivate))
69 modest_country_picker_get_property (GObject *object, guint property_id,
70 GValue *value, GParamSpec *pspec)
72 switch (property_id) {
74 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
79 modest_country_picker_set_property (GObject *object, guint property_id,
80 const GValue *value, GParamSpec *pspec)
82 switch (property_id) {
84 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
89 modest_country_picker_dispose (GObject *object)
91 if (G_OBJECT_CLASS (modest_country_picker_parent_class)->dispose)
92 G_OBJECT_CLASS (modest_country_picker_parent_class)->dispose (object);
96 MODEL_COL_NAME = 0, /* string */
97 MODEL_COL_MCC = 1 /* the 'effective mcc' for this country */
102 modest_country_picker_finalize (GObject *object)
104 G_OBJECT_CLASS (modest_country_picker_parent_class)->finalize (object);
108 modest_country_picker_class_init (ModestCountryPickerClass *klass)
110 GObjectClass *object_class = G_OBJECT_CLASS (klass);
112 g_type_class_add_private (klass, sizeof (ModestCountryPickerPrivate));
114 object_class->get_property = modest_country_picker_get_property;
115 object_class->set_property = modest_country_picker_set_property;
116 object_class->dispose = modest_country_picker_dispose;
117 object_class->finalize = modest_country_picker_finalize;
123 /* cluster mcc's, based on the list
124 * http://en.wikipedia.org/wiki/Mobile_country_code
127 effective_mcc (gint mcc)
130 case 405: return 404; /* india */
131 case 441: return 440; /* japan */
132 case 235: return 234; /* united kingdom */
138 case 316: return 310; /* united states */
144 /* each line is of the form:
147 NOTE: this function is NOT re-entrant, the out-param country
148 are static strings that should NOT be freed. and will change when
149 calling this function again
151 also note, this function will return the "effective mcc", which
152 is the normalized mcc for a country - ie. even if the there
153 are multiple entries for the United States with various mccs,
154 this function will always return 310, even if the real mcc parsed
155 would be 314. see the 'effective_mcc' function above.
158 parse_mcc_mapping_line (const char* line, char** country)
160 char mcc[4]; /* the mcc code, always 3 bytes*/
161 gchar *iter, *tab, *final;
168 /* Go to the first tab (Country separator) */
169 tab = g_utf8_strrchr (line, -1, '\t');
173 *country = g_utf8_find_next_char (tab, NULL);
175 /* Replace by end of string. We need to use strlen, because
176 g_utf8_strrchr expects bytes and not UTF8 characters */
177 final = g_utf8_strrchr (tab, strlen (tab) + 1, '\n');
178 if (G_LIKELY (final))
181 tab[strlen(tab) - 1] = '\0';
184 mcc[0] = g_utf8_get_char (line);
185 iter = g_utf8_find_next_char (line, NULL);
186 mcc[1] = g_utf8_get_char (iter);
187 iter = g_utf8_find_next_char (iter, NULL);
188 mcc[2] = g_utf8_get_char (iter);
191 return effective_mcc ((int) strtol ((const char*)mcc, NULL, 10));
194 /** Note that the mcc_mapping file is installed
195 * by the operator-wizard-settings package.
198 load_from_file (ModestCountryPicker *self, GtkListStore *liststore)
200 ModestCountryPickerPrivate *priv = MODEST_COUNTRY_PICKER_GET_PRIVATE (self);
202 char line[MAX_LINE_LEN];
203 guint previous_mcc = 0;
206 FILE *file = modest_maemo_open_mcc_mapping_file (&translated);
208 g_warning("Could not open mcc_mapping file");
212 /* Get the territory specified for the current locale */
213 territory = nl_langinfo (_NL_ADDRESS_COUNTRY_NAME);
215 while (fgets (line, MAX_LINE_LEN, file) != NULL) {
218 char *country = NULL;
219 const gchar *name_translated;
221 mcc = parse_mcc_mapping_line (line, &country);
222 if (!country || mcc == 0) {
223 g_warning ("%s: error parsing line: '%s'", __FUNCTION__, line);
227 if (mcc == previous_mcc) {
228 /* g_warning ("already seen: %s", line); */
233 if (!priv->locale_mcc) {
235 if (!g_utf8_collate (country, territory))
236 priv->locale_mcc = mcc;
238 gchar *translation = dgettext ("osso-countries", country);
239 if (!g_utf8_collate (translation, territory))
240 priv->locale_mcc = mcc;
243 name_translated = dgettext ("osso-countries", country);
245 /* Add the row to the model: */
247 gtk_list_store_append (liststore, &iter);
248 gtk_list_store_set(liststore, &iter, MODEL_COL_MCC, mcc, MODEL_COL_NAME, name_translated, -1);
252 /* Fallback to Finland */
253 if (!priv->locale_mcc)
254 priv->locale_mcc = 244;
256 /* Sort the items: */
257 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (liststore),
258 MODEL_COL_NAME, GTK_SORT_ASCENDING);
262 modest_country_picker_init (ModestCountryPicker *self)
264 ModestCountryPickerPrivate *priv = MODEST_COUNTRY_PICKER_GET_PRIVATE (self);
265 priv->locale_mcc = 0;
269 country_picker_print_func (HildonTouchSelector *selector, gpointer userdata)
275 /* Always pick the selected country from the tree view and
276 never from the entry */
277 model = hildon_touch_selector_get_model (selector, 0);
278 if (hildon_touch_selector_get_selected (selector, 0, &iter)) {
281 const gchar *entry_text;
283 column = hildon_touch_selector_entry_get_text_column (HILDON_TOUCH_SELECTOR_ENTRY (selector));
284 gtk_tree_model_get (model, &iter, column, &text, -1);
286 entry = GTK_WIDGET (hildon_touch_selector_entry_get_entry (HILDON_TOUCH_SELECTOR_ENTRY (selector)));
287 entry_text = hildon_entry_get_text (HILDON_ENTRY (entry));
288 if (entry_text != NULL && text != NULL && strcmp (entry_text, text)) {
289 hildon_entry_set_text (HILDON_ENTRY (entry), text);
296 modest_country_picker_load_data(ModestCountryPicker *self)
298 GtkCellRenderer *renderer;
301 HildonTouchSelectorColumn *column;
303 /* Create a tree model for the combo box,
304 * with a string for the name, and an int for the MCC ID.
305 * This must match our MODEL_COLS enum constants.
307 model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
310 * The ID model column in not shown in the view. */
311 renderer = gtk_cell_renderer_text_new ();
312 g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
314 selector = hildon_touch_selector_entry_new ();
315 hildon_touch_selector_set_print_func (HILDON_TOUCH_SELECTOR (selector), (HildonTouchSelectorPrintFunc) country_picker_print_func);
316 column = hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector), GTK_TREE_MODEL (model),
317 renderer, "text", MODEL_COL_NAME, NULL);
318 g_object_set (G_OBJECT (column), "text-column", MODEL_COL_NAME, NULL);
320 /* Fill the model with rows: */
321 load_from_file (self, model);
323 /* Set this _after_ loading from file, it makes loading faster */
324 hildon_touch_selector_set_model (HILDON_TOUCH_SELECTOR (selector),
325 0, GTK_TREE_MODEL (model));
326 hildon_touch_selector_entry_set_text_column (HILDON_TOUCH_SELECTOR_ENTRY (selector),
328 hildon_touch_selector_entry_set_input_mode (HILDON_TOUCH_SELECTOR_ENTRY (selector),
329 HILDON_GTK_INPUT_MODE_ALPHA |
330 HILDON_GTK_INPUT_MODE_AUTOCAP);
332 hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (self), HILDON_TOUCH_SELECTOR (selector));
334 g_object_unref (model);
338 modest_country_picker_new (HildonSizeType size,
339 HildonButtonArrangement arrangement)
341 return g_object_new (MODEST_TYPE_COUNTRY_PICKER,
342 "arrangement", arrangement,
348 * Returns the MCC number of the selected country, or 0 if no country was selected.
351 modest_country_picker_get_active_country_mcc (ModestCountryPicker *self)
356 found = hildon_touch_selector_get_selected (hildon_picker_button_get_selector
357 (HILDON_PICKER_BUTTON (self)), 0, &active);
360 gtk_tree_model_get (hildon_touch_selector_get_model (hildon_picker_button_get_selector
361 (HILDON_PICKER_BUTTON (self)),
363 &active, MODEL_COL_MCC, &mcc, -1);
366 return 0; /* Failed. */
371 * Selects the MCC number of the selected country.
372 * Specify 0 to select no country.
375 modest_country_picker_set_active_country_locale (ModestCountryPicker *self)
377 ModestCountryPickerPrivate *priv = MODEST_COUNTRY_PICKER_GET_PRIVATE (self);
383 selector = GTK_WIDGET (hildon_picker_button_get_selector (HILDON_PICKER_BUTTON (self)));
384 model = hildon_touch_selector_get_model (HILDON_TOUCH_SELECTOR (selector), 0);
385 if (!gtk_tree_model_get_iter_first (model, &iter))
388 gtk_tree_model_get (model, &iter, MODEL_COL_MCC, ¤t_mcc, -1);
389 if (priv->locale_mcc == current_mcc) {
390 hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector), 0,
392 hildon_button_set_value (HILDON_BUTTON (self),
393 hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector)));
396 } while (gtk_tree_model_iter_next (model, &iter));
398 return FALSE; /* not found */