1 /* Copyright (c) 2006, 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-easysetup-country-combo-box.h"
37 #include <gtk/gtkliststore.h>
38 #include <gtk/gtkcelllayout.h>
39 #include <gtk/gtkcellrenderertext.h>
42 #include <string.h> /* For memcpy() */
44 #include <libintl.h> /* For dgettext(). */
46 /* Include config.h so that _() works: */
51 #define MAX_LINE_LEN 128 /* max length of a line in MCC file */
53 G_DEFINE_TYPE (EasysetupCountryComboBox, easysetup_country_combo_box, GTK_TYPE_COMBO_BOX);
55 #define COUNTRY_COMBO_BOX_GET_PRIVATE(o) \
56 (G_TYPE_INSTANCE_GET_PRIVATE ((o), EASYSETUP_TYPE_COUNTRY_COMBO_BOX, EasysetupCountryComboBoxPrivate))
58 typedef struct _EasysetupCountryComboBoxPrivate EasysetupCountryComboBoxPrivate;
60 struct _EasysetupCountryComboBoxPrivate
66 easysetup_country_combo_box_get_property (GObject *object, guint property_id,
67 GValue *value, GParamSpec *pspec)
69 switch (property_id) {
71 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
76 easysetup_country_combo_box_set_property (GObject *object, guint property_id,
77 const GValue *value, GParamSpec *pspec)
79 switch (property_id) {
81 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
86 easysetup_country_combo_box_dispose (GObject *object)
88 if (G_OBJECT_CLASS (easysetup_country_combo_box_parent_class)->dispose)
89 G_OBJECT_CLASS (easysetup_country_combo_box_parent_class)->dispose (object);
93 MODEL_COL_NAME = 0, /* string */
94 MODEL_COL_MCC = 1 /* the 'effective mcc' for this country */
99 easysetup_country_combo_box_finalize (GObject *object)
101 EasysetupCountryComboBoxPrivate *priv = COUNTRY_COMBO_BOX_GET_PRIVATE (object);
103 g_object_unref (G_OBJECT (priv->model));
104 G_OBJECT_CLASS (easysetup_country_combo_box_parent_class)->finalize (object);
108 easysetup_country_combo_box_class_init (EasysetupCountryComboBoxClass *klass)
110 GObjectClass *object_class = G_OBJECT_CLASS (klass);
112 g_type_class_add_private (klass, sizeof (EasysetupCountryComboBoxPrivate));
114 object_class->get_property = easysetup_country_combo_box_get_property;
115 object_class->set_property = easysetup_country_combo_box_set_property;
116 object_class->dispose = easysetup_country_combo_box_dispose;
117 object_class->finalize = easysetup_country_combo_box_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)
161 char mcc[4]; /* the mcc code, always 3 bytes*/
162 static char my_country[128];
164 /* Initialize output parameters: */
167 g_return_val_if_fail (line && strlen(line) > 20, 0);
169 for (i = 3, j = 0; i < 128; ++i) {
171 if (kar < '_' ) { /* optimization */
172 if (kar == '\n' || kar == '\r')
174 else if (kar == ' ' || kar == '\t')
180 my_country [j++] = kar;
183 my_country[j] = '\0';
190 *country = my_country;
191 return effective_mcc (atoi(mcc));
194 /** Note that the mcc_mapping file is installed
195 * by the operator-wizard-settings package.
198 load_from_file (EasysetupCountryComboBox *self)
200 EasysetupCountryComboBoxPrivate *priv = COUNTRY_COMBO_BOX_GET_PRIVATE (self);
201 GtkListStore *liststore = GTK_LIST_STORE (priv->model);
203 char line[MAX_LINE_LEN];
204 guint previous_mcc = 0;
206 /* Load the file one line at a time: */
207 #ifdef MODEST_HILDON_VERSION_0
208 const gchar* filepath = PROVIDER_DATA_DIR "/mcc_mapping";
210 /* This is the official version, in the 'operator-wizard-settings' package */
211 const gchar* filepath = "/usr/share/operator-wizard/mcc_mapping";
212 #endif /*MODEST_HILDON_VERSION_0*/
213 /* printf ("DEBUG: %s: filepath=%s\n", __FUNCTION__, filepath); */
214 FILE *file = fopen(filepath, "r");
216 const gchar* filepath_hack = HACK_TOP_SRCDIR "src/maemo/easysetup/mcc_mapping";
217 g_warning ("Could not locate the official mcc_mapping countries list file from %s, "
218 "so attempting to load it instead from %s", filepath, filepath_hack);
219 file = fopen(filepath_hack, "r");
222 g_warning("Could not open mcc_mapping file");
226 while (fgets (line, MAX_LINE_LEN, file) > 0) {
229 char *country = NULL;
230 mcc = parse_mcc_mapping_line (line, &country);
231 if (!country || mcc == 0) {
232 g_warning ("%s: error parsing line: '%s'", __FUNCTION__, line);
236 if (mcc == previous_mcc) {
237 /* g_warning ("already seen: %s", line); */
242 /* Get the translation for the country name:
243 * Note that the osso_countries_1.0 translation domain files are installed
244 * by the operator-wizard-settings package. */
245 /* For post-Bora, there is a separate (meta)package osso-countries-l10n-mr0 */
247 /* Note: Even when the untranslated names are different, there may still be
248 * duplicate translated names. They would be translation bugs.
250 const gchar *name_translated = dgettext ("osso-countries", country);
252 /* Add the row to the model: */
254 gtk_list_store_append (liststore, &iter);
255 gtk_list_store_set(liststore, &iter, MODEL_COL_MCC, mcc, MODEL_COL_NAME, name_translated, -1);
259 /* Sort the items: */
260 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (liststore),
261 MODEL_COL_NAME, GTK_SORT_ASCENDING);
265 easysetup_country_combo_box_init (EasysetupCountryComboBox *self)
267 EasysetupCountryComboBoxPrivate *priv = COUNTRY_COMBO_BOX_GET_PRIVATE (self);
269 /* Create a tree model for the combo box,
270 * with a string for the name, and an int for the MCC ID.
271 * This must match our MODEL_COLS enum constants.
273 priv->model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT));
275 /* Setup the combo box: */
276 GtkComboBox *combobox = GTK_COMBO_BOX (self);
277 gtk_combo_box_set_model (combobox, priv->model);
280 * The ID model column in not shown in the view. */
281 GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
282 g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
283 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combobox), renderer, TRUE);
284 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer,
285 "text", MODEL_COL_NAME, NULL);
288 g_assert (GTK_IS_LIST_STORE(priv->model));
291 /* Fill the model with rows: */
292 load_from_file (self);
295 EasysetupCountryComboBox*
296 easysetup_country_combo_box_new (void)
298 return g_object_new (EASYSETUP_TYPE_COUNTRY_COMBO_BOX, NULL);
302 * Returns the MCC number of the selected country, or 0 if no country was selected.
305 easysetup_country_combo_box_get_active_country_mcc (EasysetupCountryComboBox *self)
308 const gboolean found = gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self), &active);
310 EasysetupCountryComboBoxPrivate *priv = COUNTRY_COMBO_BOX_GET_PRIVATE (self);
312 gtk_tree_model_get (priv->model, &active, MODEL_COL_MCC, &mcc, -1);
315 return 0; /* Failed. */
320 * Selects the MCC number of the selected country.
321 * Specify 0 to select no country.
324 easysetup_country_combo_box_set_active_country_mcc (EasysetupCountryComboBox *self, guint mcc)
326 EasysetupCountryComboBoxPrivate *priv = COUNTRY_COMBO_BOX_GET_PRIVATE (self);
329 if (!gtk_tree_model_get_iter_first (priv->model, &iter))
332 gint current_mcc = 0;
333 gtk_tree_model_get (priv->model, &iter, MODEL_COL_MCC, ¤t_mcc, -1);
334 if (current_mcc == mcc) {
335 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self), &iter);
338 } while (gtk_tree_model_iter_next (priv->model, &iter));
340 return FALSE; /* not found */