~ubuntu-branches/ubuntu/saucy/network-manager-applet/saucy-updates

« back to all changes in this revision

Viewing changes to .pc/git_fix_some_leaks_80ef61b.patch/src/libnm-gtk/nm-mobile-wizard.c

  • Committer: Package Import Robot
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2012-08-10 15:44:44 UTC
  • mfrom: (1.2.30)
  • Revision ID: package-import@ubuntu.com-20120810154444-nmjepmyshkpbxt60
Tags: 0.9.6.2-0ubuntu1
* New upstream release.
  - Fix GNOME Bluetooth plugin DUN modem detection and setup
  - Various crash and stability fixes
  - Allow appending DNS servers and domains in automatic addressing mode
  - Fix defaults for PPP echo values
  - Show IPv6 addressing page for VPN plugins that support it
  - Port to GSettings and split out 0.8 -> 0.9 migration code
  - Recognize PKCS#12 certificates imported from Firefox
  - Pre-fill CDMA username/password in the mobile broadband wizard
  - Only handle VPN secrets for GNOME Shell 3.3 and lower
* debian/control: Bump Depends and Build-Depends to (>= 0.9.6) for
  network-manager and the libnm-{glib,util,glib-vpn}-dev packages.
* debian/patches/git_fix_some_leaks_80ef61b.patch: cherry-picked patch to
  fix a few leaks: g_object_get() and gtk_tree_model_get() copy/ref the
  values they return, so make sure to deal with that everywhere.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 
2
/* NetworkManager Connection editor -- Connection editor for NetworkManager
 
3
 *
 
4
 * Dan Williams <dcbw@redhat.com>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License along
 
17
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
19
 *
 
20
 * (C) Copyright 2008 - 2012 Red Hat, Inc.
 
21
 */
 
22
 
 
23
#include "config.h"
 
24
 
 
25
#include <stdlib.h>
 
26
#include <ctype.h>
 
27
 
 
28
#include <glib.h>
 
29
#include <glib/gi18n.h>
 
30
 
 
31
#include <gtk/gtk.h>
 
32
 
 
33
#include <NetworkManager.h>
 
34
#include <nm-setting-gsm.h>
 
35
#include <nm-setting-cdma.h>
 
36
#include <nm-client.h>
 
37
#include <nm-device-modem.h>
 
38
 
 
39
#include "nm-mobile-wizard.h"
 
40
#include "nmn-mobile-providers.h"
 
41
#include "utils.h"
 
42
 
 
43
#define DEVICE_TAG "device"
 
44
#define TYPE_TAG "setting-type"
 
45
 
 
46
static char *get_selected_country (NMAMobileWizard *self, gboolean *unlisted);
 
47
static NmnMobileProvider *get_selected_provider (NMAMobileWizard *self);
 
48
static NmnMobileAccessMethodType get_provider_unlisted_type (NMAMobileWizard *self);
 
49
static NmnMobileAccessMethod *get_selected_method (NMAMobileWizard *self, gboolean *manual);
 
50
 
 
51
struct NMAMobileWizard {
 
52
        GtkWidget *assistant;
 
53
        NMAMobileWizardCallback callback;
 
54
        gpointer user_data;
 
55
        GHashTable *providers;
 
56
        GHashTable *country_codes;
 
57
        NmnMobileAccessMethodType method_type;
 
58
        gboolean initial_method_type;
 
59
        gboolean will_connect_after;
 
60
 
 
61
        /* Intro page */
 
62
        GtkWidget *dev_combo;
 
63
        GtkTreeStore *dev_store;
 
64
        char *dev_desc;
 
65
        NMClient *client;
 
66
 
 
67
        /* Country page */
 
68
        guint32 country_idx;
 
69
        const char *country;
 
70
        GtkWidget *country_page;
 
71
        GtkWidget *country_view;
 
72
        GtkTreeStore *country_store;
 
73
        GtkTreeModelSort *country_sort;
 
74
        guint32 country_focus_id;
 
75
 
 
76
        /* Providers page */
 
77
        guint32 providers_idx;
 
78
        GtkWidget *providers_page;
 
79
        GtkWidget *providers_view;
 
80
        GtkTreeStore *providers_store;
 
81
        GtkTreeModelSort *providers_sort;
 
82
        guint32 providers_focus_id;
 
83
        GtkWidget *providers_view_radio;
 
84
 
 
85
        GtkWidget *provider_unlisted_radio;
 
86
        GtkWidget *provider_unlisted_entry;
 
87
        GtkWidget *provider_unlisted_type_combo;
 
88
 
 
89
        gboolean provider_only_cdma;
 
90
 
 
91
        /* Plan page */
 
92
        guint32 plan_idx;
 
93
        GtkWidget *plan_page;
 
94
        GtkWidget *plan_combo;
 
95
        GtkTreeStore *plan_store;
 
96
        guint32 plan_focus_id;
 
97
 
 
98
        GtkWidget *plan_unlisted_entry;
 
99
 
 
100
        /* Confirm page */
 
101
        GtkWidget *confirm_page;
 
102
        GtkWidget *confirm_provider;
 
103
        GtkWidget *confirm_plan;
 
104
        GtkWidget *confirm_apn;
 
105
        GtkWidget *confirm_plan_label;
 
106
        GtkWidget *confirm_device;
 
107
        GtkWidget *confirm_device_label;
 
108
        guint32 confirm_idx;
 
109
};
 
110
 
 
111
static void
 
112
assistant_closed (GtkButton *button, gpointer user_data)
 
113
{
 
114
        NMAMobileWizard *self = user_data;
 
115
        NmnMobileProvider *provider;
 
116
        NmnMobileAccessMethod *method;
 
117
        NMAMobileWizardAccessMethod *wiz_method;
 
118
        NmnMobileAccessMethodType method_type = self->method_type;
 
119
 
 
120
        wiz_method = g_malloc0 (sizeof (NMAMobileWizardAccessMethod));
 
121
 
 
122
        provider = get_selected_provider (self);
 
123
        if (!provider) {
 
124
                if (method_type == NMN_MOBILE_ACCESS_METHOD_TYPE_UNKNOWN)
 
125
                        method_type = get_provider_unlisted_type (self);
 
126
 
 
127
                wiz_method->provider_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->provider_unlisted_entry)));
 
128
                if (method_type == NMN_MOBILE_ACCESS_METHOD_TYPE_GSM)
 
129
                        wiz_method->gsm_apn = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->plan_unlisted_entry)));
 
130
        } else {
 
131
                gboolean manual = FALSE;
 
132
 
 
133
                wiz_method->provider_name = g_strdup (provider->name);
 
134
                method = get_selected_method (self, &manual);
 
135
                if (method) {
 
136
                        if (method->name)
 
137
                                wiz_method->plan_name = g_strdup (method->name);
 
138
                        method_type = method->type;
 
139
                        if (method_type == NMN_MOBILE_ACCESS_METHOD_TYPE_GSM)
 
140
                                wiz_method->gsm_apn = g_strdup (method->gsm_apn);
 
141
                        wiz_method->username = method->username ? g_strdup (method->username) : NULL;
 
142
                        wiz_method->password = method->password ? g_strdup (method->password) : NULL;
 
143
                } else {
 
144
                        if (self->provider_only_cdma) {
 
145
                                method_type = NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA;
 
146
                                /* Take username and password from the first (only) method for CDMA only provider */
 
147
                                if (provider->methods) {
 
148
                                        method = provider->methods->data;
 
149
                                        wiz_method->username = method->username ? g_strdup (method->username) : NULL;
 
150
                                        wiz_method->password = method->password ? g_strdup (method->password) : NULL;
 
151
                                }
 
152
                        }
 
153
                        else {
 
154
                                method_type = NMN_MOBILE_ACCESS_METHOD_TYPE_GSM;
 
155
                                wiz_method->gsm_apn = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->plan_unlisted_entry)));
 
156
                        }
 
157
                }
 
158
        }
 
159
 
 
160
        switch (method_type) {
 
161
        case NMN_MOBILE_ACCESS_METHOD_TYPE_GSM:
 
162
                wiz_method->devtype = NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS;
 
163
                break;
 
164
        case NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA:
 
165
                wiz_method->devtype = NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO;
 
166
                break;
 
167
        default:
 
168
                g_assert_not_reached ();
 
169
                break;
 
170
        }
 
171
 
 
172
        (*(self->callback)) (self, FALSE, wiz_method, self->user_data);
 
173
 
 
174
        g_free (wiz_method->provider_name);
 
175
        g_free (wiz_method->plan_name);
 
176
        g_free (wiz_method->username);
 
177
        g_free (wiz_method->password);
 
178
        g_free (wiz_method->gsm_apn);
 
179
        g_free (wiz_method);
 
180
}
 
181
 
 
182
static void
 
183
assistant_cancel (GtkButton *button, gpointer user_data)
 
184
{
 
185
        NMAMobileWizard *self = user_data;
 
186
 
 
187
        (*(self->callback)) (self, TRUE, NULL, self->user_data);
 
188
}
 
189
 
 
190
/**********************************************************/
 
191
/* Confirm page */
 
192
/**********************************************************/
 
193
 
 
194
static void
 
195
confirm_setup (NMAMobileWizard *self)
 
196
{
 
197
        GtkWidget *vbox, *label, *alignment, *pbox;
 
198
 
 
199
#if GTK_CHECK_VERSION(3,1,6)
 
200
        vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
 
201
#else
 
202
        vbox = gtk_vbox_new (FALSE, 6);
 
203
#endif
 
204
        gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
 
205
        label = gtk_label_new (_("Your mobile broadband connection is configured with the following settings:"));
 
206
        gtk_widget_set_size_request (label, 500, -1);
 
207
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
208
        gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 
209
        gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 6);
 
210
 
 
211
        /* Device */
 
212
        self->confirm_device_label = gtk_label_new (_("Your Device:"));
 
213
        gtk_misc_set_alignment (GTK_MISC (self->confirm_device_label), 0, 0.5);
 
214
        gtk_box_pack_start (GTK_BOX (vbox), self->confirm_device_label, FALSE, FALSE, 0);
 
215
 
 
216
        alignment = gtk_alignment_new (0, 0.5, 0, 0);
 
217
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 12, 25, 0);
 
218
        self->confirm_device = gtk_label_new (NULL);
 
219
        gtk_container_add (GTK_CONTAINER (alignment), self->confirm_device);
 
220
        gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
 
221
 
 
222
        /* Provider */
 
223
        label = gtk_label_new (_("Your Provider:"));
 
224
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
225
        gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
 
226
 
 
227
        alignment = gtk_alignment_new (0, 0.5, 0, 0);
 
228
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 12, 25, 0);
 
229
        self->confirm_provider = gtk_label_new (NULL);
 
230
        gtk_container_add (GTK_CONTAINER (alignment), self->confirm_provider);
 
231
        gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
 
232
 
 
233
        /* Plan and APN */
 
234
        self->confirm_plan_label = gtk_label_new (_("Your Plan:"));
 
235
        gtk_misc_set_alignment (GTK_MISC (self->confirm_plan_label), 0, 0.5);
 
236
        gtk_box_pack_start (GTK_BOX (vbox), self->confirm_plan_label, FALSE, FALSE, 0);
 
237
 
 
238
        alignment = gtk_alignment_new (0, 0.5, 0, 0);
 
239
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 25, 0);
 
240
#if GTK_CHECK_VERSION(3,1,6)
 
241
        pbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
 
242
#else
 
243
        pbox = gtk_vbox_new (FALSE, 0);
 
244
#endif
 
245
        gtk_container_add (GTK_CONTAINER (alignment), pbox);
 
246
        gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
 
247
 
 
248
        self->confirm_plan = gtk_label_new (NULL);
 
249
        gtk_misc_set_alignment (GTK_MISC (self->confirm_plan), 0, 0.5);
 
250
        gtk_box_pack_start (GTK_BOX (pbox), self->confirm_plan, FALSE, FALSE, 0);
 
251
 
 
252
        self->confirm_apn = gtk_label_new (NULL);
 
253
        gtk_misc_set_alignment (GTK_MISC (self->confirm_apn), 0, 0.5);
 
254
        gtk_misc_set_padding (GTK_MISC (self->confirm_apn), 0, 6);
 
255
        gtk_box_pack_start (GTK_BOX (pbox), self->confirm_apn, FALSE, FALSE, 0);
 
256
 
 
257
        if (self->will_connect_after) {
 
258
                alignment = gtk_alignment_new (0, 0.5, 1, 0);
 
259
                label = gtk_label_new (_("A connection will now be made to your mobile broadband provider using the settings you selected.  If the connection fails or you cannot access network resources, double-check your settings.  To modify your mobile broadband connection settings, choose \"Network Connections\" from the System >> Preferences menu."));
 
260
                gtk_widget_set_size_request (label, 500, -1);
 
261
                gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
262
                gtk_misc_set_padding (GTK_MISC (label), 0, 6);
 
263
                gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 
264
                gtk_container_add (GTK_CONTAINER (alignment), label);
 
265
                gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 6);
 
266
        }
 
267
 
 
268
        gtk_widget_show_all (vbox);
 
269
        self->confirm_idx = gtk_assistant_append_page (GTK_ASSISTANT (self->assistant), vbox);
 
270
        gtk_assistant_set_page_title (GTK_ASSISTANT (self->assistant),
 
271
                                      vbox, _("Confirm Mobile Broadband Settings"));
 
272
 
 
273
        gtk_assistant_set_page_complete (GTK_ASSISTANT (self->assistant), vbox, TRUE);
 
274
        gtk_assistant_set_page_type (GTK_ASSISTANT (self->assistant), vbox, GTK_ASSISTANT_PAGE_CONFIRM);
 
275
 
 
276
        self->confirm_page = vbox;
 
277
}
 
278
 
 
279
static void
 
280
confirm_prepare (NMAMobileWizard *self)
 
281
{
 
282
        NmnMobileProvider *provider = NULL;
 
283
        NmnMobileAccessMethod *method = NULL;
 
284
        char *country = NULL;
 
285
        gboolean manual = FALSE;
 
286
        GString *str;
 
287
 
 
288
        country = get_selected_country (self, NULL);
 
289
        provider = get_selected_provider (self);
 
290
        if (provider)
 
291
                method = get_selected_method (self, &manual);
 
292
 
 
293
        /* Provider */
 
294
        str = g_string_new (NULL);
 
295
        if (provider)
 
296
                g_string_append (str, provider->name);
 
297
        else {
 
298
                const char *unlisted_provider;
 
299
 
 
300
                unlisted_provider = gtk_entry_get_text (GTK_ENTRY (self->provider_unlisted_entry));
 
301
                g_string_append (str, unlisted_provider);
 
302
        }
 
303
 
 
304
        if (country)
 
305
                g_string_append_printf (str, ", %s", country);
 
306
        gtk_label_set_text (GTK_LABEL (self->confirm_provider), str->str);
 
307
        g_string_free (str, TRUE);
 
308
 
 
309
        if (self->dev_desc)
 
310
                gtk_label_set_text (GTK_LABEL (self->confirm_device), self->dev_desc);
 
311
        else {
 
312
                gtk_widget_hide (self->confirm_device_label);
 
313
                gtk_widget_hide (self->confirm_device);
 
314
        }
 
315
 
 
316
        if (self->provider_only_cdma) {
 
317
                gtk_widget_hide (self->confirm_plan_label);
 
318
                gtk_widget_hide (self->confirm_plan);
 
319
                gtk_widget_hide (self->confirm_apn);
 
320
        } else {
 
321
                const char *apn = NULL;
 
322
 
 
323
                /* Plan */
 
324
                gtk_widget_show (self->confirm_plan_label);
 
325
                gtk_widget_show (self->confirm_plan);
 
326
                gtk_widget_show (self->confirm_apn);
 
327
 
 
328
                if (method) {
 
329
                        gtk_label_set_text (GTK_LABEL (self->confirm_plan), method->name);
 
330
                        apn = method->gsm_apn;
 
331
                } else {
 
332
                        gtk_label_set_text (GTK_LABEL (self->confirm_plan), _("Unlisted"));
 
333
                        apn = gtk_entry_get_text (GTK_ENTRY (self->plan_unlisted_entry));
 
334
                }
 
335
 
 
336
                str = g_string_new (NULL);
 
337
                g_string_append_printf (str, "<span color=\"#999999\">APN: %s</span>", apn);
 
338
                gtk_label_set_markup (GTK_LABEL (self->confirm_apn), str->str);
 
339
                g_string_free (str, TRUE);
 
340
        }
 
341
}
 
342
 
 
343
/**********************************************************/
 
344
/* Plan page */
 
345
/**********************************************************/
 
346
 
 
347
#define PLAN_COL_NAME 0
 
348
#define PLAN_COL_METHOD 1
 
349
#define PLAN_COL_MANUAL 2
 
350
 
 
351
static NmnMobileAccessMethod *
 
352
get_selected_method (NMAMobileWizard *self, gboolean *manual)
 
353
{
 
354
        GtkTreeModel *model;
 
355
        NmnMobileAccessMethod *method = NULL;
 
356
        GtkTreeIter iter;
 
357
        gboolean is_manual = FALSE;
 
358
 
 
359
        if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self->plan_combo), &iter))
 
360
                return NULL;
 
361
 
 
362
        model = gtk_combo_box_get_model (GTK_COMBO_BOX (self->plan_combo));
 
363
        if (!model)
 
364
                return NULL;
 
365
 
 
366
        gtk_tree_model_get (model, &iter,
 
367
                            PLAN_COL_METHOD, &method,
 
368
                            PLAN_COL_MANUAL, &is_manual,
 
369
                            -1);
 
370
        if (is_manual) {
 
371
                if (manual)
 
372
                        *manual = is_manual;
 
373
                if (method)
 
374
                        nmn_mobile_access_method_unref (method);
 
375
                method = NULL;
 
376
        }
 
377
 
 
378
        return method;
 
379
}
 
380
 
 
381
static void
 
382
plan_update_complete (NMAMobileWizard *self)
 
383
{
 
384
        GtkAssistant *assistant = GTK_ASSISTANT (self->assistant);
 
385
        gboolean is_manual = FALSE;
 
386
        NmnMobileAccessMethod *method;
 
387
 
 
388
        method = get_selected_method (self, &is_manual);
 
389
        if (method) {
 
390
                gtk_assistant_set_page_complete (assistant, self->plan_page, TRUE);
 
391
                nmn_mobile_access_method_unref (method);
 
392
        } else {
 
393
                const char *manual_apn;
 
394
 
 
395
                manual_apn = gtk_entry_get_text (GTK_ENTRY (self->plan_unlisted_entry));
 
396
                gtk_assistant_set_page_complete (assistant, self->plan_page,
 
397
                                                 (manual_apn && strlen (manual_apn)));
 
398
        }
 
399
}
 
400
 
 
401
static void
 
402
plan_combo_changed (NMAMobileWizard *self)
 
403
{
 
404
        NmnMobileAccessMethod *method = NULL;
 
405
        gboolean is_manual = FALSE;
 
406
 
 
407
        method = get_selected_method (self, &is_manual);
 
408
        if (method) {
 
409
                gtk_entry_set_text (GTK_ENTRY (self->plan_unlisted_entry), method->gsm_apn);
 
410
                gtk_widget_set_sensitive (self->plan_unlisted_entry, FALSE);
 
411
        } else {
 
412
                gtk_entry_set_text (GTK_ENTRY (self->plan_unlisted_entry), "");
 
413
                gtk_widget_set_sensitive (self->plan_unlisted_entry, TRUE);
 
414
                gtk_widget_grab_focus (self->plan_unlisted_entry);
 
415
        }
 
416
 
 
417
        if (method)
 
418
                nmn_mobile_access_method_unref (method);
 
419
 
 
420
        plan_update_complete (self);
 
421
}
 
422
 
 
423
static gboolean
 
424
plan_row_separator_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
 
425
{
 
426
        NmnMobileAccessMethod *method = NULL;
 
427
        gboolean is_manual = FALSE;
 
428
        gboolean draw_separator = FALSE;
 
429
 
 
430
        gtk_tree_model_get (model, iter,
 
431
                            PLAN_COL_METHOD, &method,
 
432
                            PLAN_COL_MANUAL, &is_manual,
 
433
                            -1);
 
434
        if (!method && !is_manual)
 
435
                draw_separator = TRUE;
 
436
        if (method)
 
437
                nmn_mobile_access_method_unref (method);
 
438
        return draw_separator;
 
439
}
 
440
 
 
441
static void
 
442
apn_filter_cb (GtkEntry *   entry,
 
443
               const gchar *text,
 
444
               gint         length,
 
445
               gint *       position,
 
446
               gpointer     user_data)
 
447
{
 
448
        GtkEditable *editable = GTK_EDITABLE (entry);
 
449
        int i, count = 0;
 
450
        gchar *result = g_new0 (gchar, length);
 
451
 
 
452
        for (i = 0; i < length; i++) {
 
453
                if (   isalnum (text[i])
 
454
                    || (text[i] == '.')
 
455
                    || (text[i] == '_')
 
456
                    || (text[i] == '-'))
 
457
                        result[count++] = text[i];
 
458
        }
 
459
 
 
460
        if (count > 0) {
 
461
                g_signal_handlers_block_by_func (G_OBJECT (editable),
 
462
                                                 G_CALLBACK (apn_filter_cb),
 
463
                                                 user_data);
 
464
                gtk_editable_insert_text (editable, result, count, position);
 
465
                g_signal_handlers_unblock_by_func (G_OBJECT (editable),
 
466
                                                   G_CALLBACK (apn_filter_cb),
 
467
                                                   user_data);
 
468
        }
 
469
 
 
470
        g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
 
471
        g_free (result);
 
472
}
 
473
 
 
474
static void
 
475
plan_setup (NMAMobileWizard *self)
 
476
{
 
477
        GtkWidget *vbox, *label, *alignment, *hbox, *image;
 
478
        GtkCellRenderer *renderer;
 
479
 
 
480
#if GTK_CHECK_VERSION(3,1,6)
 
481
        vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
 
482
#else
 
483
        vbox = gtk_vbox_new (FALSE, 6);
 
484
#endif
 
485
        gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
 
486
 
 
487
        label = gtk_label_new_with_mnemonic (_("_Select your plan:"));
 
488
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
489
        gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
 
490
 
 
491
        self->plan_store = gtk_tree_store_new (3, G_TYPE_STRING, NMN_TYPE_MOBILE_ACCESS_METHOD, G_TYPE_BOOLEAN);
 
492
 
 
493
        self->plan_combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (self->plan_store));
 
494
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->plan_combo);
 
495
        gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (self->plan_combo),
 
496
                                              plan_row_separator_func,
 
497
                                              NULL,
 
498
                                              NULL);
 
499
 
 
500
        renderer = gtk_cell_renderer_text_new ();
 
501
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self->plan_combo), renderer, TRUE);
 
502
        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self->plan_combo), renderer, "text", PLAN_COL_NAME);
 
503
 
 
504
        g_signal_connect_swapped (self->plan_combo, "changed", G_CALLBACK (plan_combo_changed), self);
 
505
 
 
506
        alignment = gtk_alignment_new (0, 0.5, 0.5, 0);
 
507
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 12, 0, 0);
 
508
        gtk_container_add (GTK_CONTAINER (alignment), self->plan_combo);
 
509
        gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
 
510
 
 
511
        label = gtk_label_new_with_mnemonic (_("Selected plan _APN (Access Point Name):"));
 
512
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
513
        gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
 
514
 
 
515
        self->plan_unlisted_entry = gtk_entry_new ();
 
516
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->plan_unlisted_entry);
 
517
        gtk_entry_set_max_length (GTK_ENTRY (self->plan_unlisted_entry), 64);
 
518
        g_signal_connect (self->plan_unlisted_entry, "insert-text", G_CALLBACK (apn_filter_cb), self);
 
519
        g_signal_connect_swapped (self->plan_unlisted_entry, "changed", G_CALLBACK (plan_update_complete), self);
 
520
 
 
521
        alignment = gtk_alignment_new (0, 0.5, 0.5, 0);
 
522
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 24, 0, 0);
 
523
        gtk_container_add (GTK_CONTAINER (alignment), self->plan_unlisted_entry);
 
524
        gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
 
525
 
 
526
#if GTK_CHECK_VERSION(3,1,6)
 
527
        hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
 
528
#else
 
529
        hbox = gtk_hbox_new (FALSE, 6);
 
530
#endif
 
531
        image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG);
 
532
        gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
 
533
        gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
 
534
 
 
535
        label = gtk_label_new (_("Warning: Selecting an incorrect plan may result in billing issues for your broadband account or may prevent connectivity.\n\nIf you are unsure of your plan please ask your provider for your plan's APN."));
 
536
        gtk_widget_set_size_request (label, 500, -1);
 
537
        gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 
538
        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
 
539
        gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
 
540
 
 
541
        self->plan_idx = gtk_assistant_append_page (GTK_ASSISTANT (self->assistant), vbox);
 
542
        gtk_assistant_set_page_title (GTK_ASSISTANT (self->assistant), vbox, _("Choose your Billing Plan"));
 
543
        gtk_assistant_set_page_type (GTK_ASSISTANT (self->assistant), vbox, GTK_ASSISTANT_PAGE_CONTENT);
 
544
        gtk_widget_show_all (vbox);
 
545
 
 
546
        self->plan_page = vbox;
 
547
}
 
548
 
 
549
static void
 
550
plan_prepare (NMAMobileWizard *self)
 
551
{
 
552
        NmnMobileProvider *provider;
 
553
        GtkTreeIter method_iter;
 
554
 
 
555
        gtk_tree_store_clear (self->plan_store);
 
556
 
 
557
        provider = get_selected_provider (self);
 
558
        if (provider) {
 
559
                GSList *iter;
 
560
                guint32 count = 0;
 
561
 
 
562
                for (iter = provider->methods; iter; iter = g_slist_next (iter)) {
 
563
                        NmnMobileAccessMethod *method = iter->data;
 
564
 
 
565
                        if (   (self->method_type != NMN_MOBILE_ACCESS_METHOD_TYPE_UNKNOWN)
 
566
                            && (method->type != self->method_type))
 
567
                                continue;
 
568
 
 
569
                        gtk_tree_store_append (GTK_TREE_STORE (self->plan_store), &method_iter, NULL);
 
570
                        gtk_tree_store_set (GTK_TREE_STORE (self->plan_store),
 
571
                                            &method_iter,
 
572
                                            PLAN_COL_NAME,
 
573
                                            method->name,
 
574
                                            PLAN_COL_METHOD,
 
575
                                            method,
 
576
                                            -1);
 
577
                        count++;
 
578
                }
 
579
 
 
580
                /* Draw the separator */
 
581
                if (count)
 
582
                        gtk_tree_store_append (GTK_TREE_STORE (self->plan_store), &method_iter, NULL);
 
583
        }
 
584
 
 
585
        /* Add the "My plan is not listed..." item */
 
586
        gtk_tree_store_append (GTK_TREE_STORE (self->plan_store), &method_iter, NULL);
 
587
        gtk_tree_store_set (GTK_TREE_STORE (self->plan_store),
 
588
                            &method_iter,
 
589
                            PLAN_COL_NAME,
 
590
                            _("My plan is not listed..."),
 
591
                            PLAN_COL_MANUAL,
 
592
                            TRUE,
 
593
                            -1);
 
594
 
 
595
        /* Select the first item by default if nothing is yet selected */
 
596
        if (gtk_combo_box_get_active (GTK_COMBO_BOX (self->plan_combo)) < 0)
 
597
                gtk_combo_box_set_active (GTK_COMBO_BOX (self->plan_combo), 0);
 
598
 
 
599
        plan_combo_changed (self);
 
600
}
 
601
 
 
602
/**********************************************************/
 
603
/* Providers page */
 
604
/**********************************************************/
 
605
 
 
606
#define PROVIDER_COL_NAME 0
 
607
#define PROVIDER_COL_PROVIDER 1
 
608
 
 
609
static gboolean
 
610
providers_search_func (GtkTreeModel *model,
 
611
                       gint column,
 
612
                       const char *key,
 
613
                       GtkTreeIter *iter,
 
614
                       gpointer search_data)
 
615
{
 
616
        gboolean unmatched = TRUE;
 
617
        char *provider = NULL;
 
618
 
 
619
        if (!key)
 
620
                return TRUE;
 
621
 
 
622
        gtk_tree_model_get (model, iter, column, &provider, -1);
 
623
        if (!provider)
 
624
                return TRUE;
 
625
 
 
626
        unmatched = !!g_ascii_strncasecmp (provider, key, strlen (key));
 
627
        g_free (provider);
 
628
        return unmatched;
 
629
}
 
630
 
 
631
static NmnMobileProvider *
 
632
get_selected_provider (NMAMobileWizard *self)
 
633
{
 
634
        GtkTreeSelection *selection;
 
635
        GtkTreeModel *model = NULL;
 
636
        GtkTreeIter iter;
 
637
        NmnMobileProvider *provider = NULL;
 
638
 
 
639
        if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->providers_view_radio)))
 
640
                return NULL;
 
641
 
 
642
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->providers_view));
 
643
        g_assert (selection);
 
644
 
 
645
        if (!gtk_tree_selection_get_selected (GTK_TREE_SELECTION (selection), &model, &iter))
 
646
                return NULL;
 
647
 
 
648
        gtk_tree_model_get (model, &iter, PROVIDER_COL_PROVIDER, &provider, -1);
 
649
        return provider;
 
650
}
 
651
 
 
652
static void
 
653
providers_update_complete (NMAMobileWizard *self)
 
654
{
 
655
        GtkAssistant *assistant = GTK_ASSISTANT (self->assistant);
 
656
        gboolean use_view;
 
657
 
 
658
        use_view = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->providers_view_radio));
 
659
        if (use_view) {
 
660
                NmnMobileProvider *provider;
 
661
 
 
662
                provider = get_selected_provider (self);
 
663
                gtk_assistant_set_page_complete (assistant, self->providers_page, !!provider);
 
664
                if (provider)
 
665
                        nmn_mobile_provider_unref (provider);
 
666
        } else {
 
667
                const char *manual_provider;
 
668
 
 
669
                manual_provider = gtk_entry_get_text (GTK_ENTRY (self->provider_unlisted_entry));
 
670
                gtk_assistant_set_page_complete (assistant, self->providers_page,
 
671
                                                 (manual_provider && strlen (manual_provider)));
 
672
        }
 
673
}
 
674
 
 
675
static gboolean
 
676
focus_providers_view (gpointer user_data)
 
677
{
 
678
        NMAMobileWizard *self = user_data;
 
679
 
 
680
        self->providers_focus_id = 0;
 
681
        gtk_widget_grab_focus (self->providers_view);
 
682
        return FALSE;
 
683
}
 
684
 
 
685
static gboolean
 
686
focus_provider_unlisted_entry (gpointer user_data)
 
687
{
 
688
        NMAMobileWizard *self = user_data;
 
689
 
 
690
        self->providers_focus_id = 0;
 
691
        gtk_widget_grab_focus (self->provider_unlisted_entry);
 
692
        return FALSE;
 
693
}
 
694
 
 
695
static void
 
696
providers_radio_toggled (GtkToggleButton *button, gpointer user_data)
 
697
{
 
698
        NMAMobileWizard *self = user_data;
 
699
        gboolean use_view;
 
700
 
 
701
        use_view = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->providers_view_radio));
 
702
        if (use_view) {
 
703
                if (!self->providers_focus_id)
 
704
                        self->providers_focus_id = g_idle_add (focus_providers_view, self);
 
705
                gtk_widget_set_sensitive (self->providers_view, TRUE);
 
706
                gtk_widget_set_sensitive (self->provider_unlisted_entry, FALSE);
 
707
                gtk_widget_set_sensitive (self->provider_unlisted_type_combo, FALSE);
 
708
        } else {
 
709
                if (!self->providers_focus_id)
 
710
                        self->providers_focus_id = g_idle_add (focus_provider_unlisted_entry, self);
 
711
                gtk_widget_set_sensitive (self->providers_view, FALSE);
 
712
                gtk_widget_set_sensitive (self->provider_unlisted_entry, TRUE);
 
713
                gtk_widget_set_sensitive (self->provider_unlisted_type_combo, TRUE);
 
714
        }
 
715
 
 
716
        providers_update_complete (self);
 
717
}
 
718
 
 
719
static NmnMobileAccessMethodType
 
720
get_provider_unlisted_type (NMAMobileWizard *self)
 
721
{
 
722
        switch (gtk_combo_box_get_active (GTK_COMBO_BOX (self->provider_unlisted_type_combo))) {
 
723
        case 0:
 
724
                return NMN_MOBILE_ACCESS_METHOD_TYPE_GSM;
 
725
        case 1:
 
726
                return NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA;
 
727
        default:
 
728
                return NMN_MOBILE_ACCESS_METHOD_TYPE_UNKNOWN;
 
729
        }
 
730
}
 
731
 
 
732
static void
 
733
providers_setup (NMAMobileWizard *self)
 
734
{
 
735
        GtkWidget *vbox, *scroll, *alignment, *unlisted_table, *label;
 
736
        GtkCellRenderer *renderer;
 
737
        GtkTreeViewColumn *column;
 
738
        GtkTreeSelection *selection;
 
739
 
 
740
#if GTK_CHECK_VERSION(3,1,6)
 
741
        vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
 
742
#else
 
743
        vbox = gtk_vbox_new (FALSE, 6);
 
744
#endif
 
745
        gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
 
746
 
 
747
        self->providers_view_radio = gtk_radio_button_new_with_mnemonic (NULL, _("Select your provider from a _list:"));
 
748
        g_signal_connect (self->providers_view_radio, "toggled", G_CALLBACK (providers_radio_toggled), self);
 
749
        gtk_box_pack_start (GTK_BOX (vbox), self->providers_view_radio, FALSE, TRUE, 0);
 
750
 
 
751
        self->providers_store = gtk_tree_store_new (2, G_TYPE_STRING, NMN_TYPE_MOBILE_PROVIDER);
 
752
 
 
753
        self->providers_sort = GTK_TREE_MODEL_SORT (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (self->providers_store)));
 
754
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self->providers_sort),
 
755
                                              PROVIDER_COL_NAME, GTK_SORT_ASCENDING);
 
756
 
 
757
        self->providers_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (self->providers_sort));
 
758
 
 
759
        renderer = gtk_cell_renderer_text_new ();
 
760
        column = gtk_tree_view_column_new_with_attributes (_("Provider"),
 
761
                                                           renderer,
 
762
                                                           "text", PROVIDER_COL_NAME,
 
763
                                                           NULL);
 
764
        gtk_tree_view_append_column (GTK_TREE_VIEW (self->providers_view), column);
 
765
        gtk_tree_view_column_set_clickable (column, TRUE);
 
766
 
 
767
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->providers_view));
 
768
        g_assert (selection);
 
769
        g_signal_connect_swapped (selection, "changed", G_CALLBACK (providers_update_complete), self);
 
770
 
 
771
        scroll = gtk_scrolled_window_new (NULL, NULL);
 
772
        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
 
773
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
 
774
                                        GTK_POLICY_NEVER,
 
775
                                        GTK_POLICY_AUTOMATIC);
 
776
        gtk_widget_set_size_request (scroll, -1, 140);
 
777
        gtk_container_add (GTK_CONTAINER (scroll), self->providers_view);
 
778
 
 
779
        alignment = gtk_alignment_new (0, 0, 1, 1);
 
780
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 12, 25, 0);
 
781
        gtk_container_add (GTK_CONTAINER (alignment), scroll);
 
782
        gtk_box_pack_start (GTK_BOX (vbox), alignment, TRUE, TRUE, 0);
 
783
 
 
784
        self->provider_unlisted_radio = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON (self->providers_view_radio),
 
785
                                                    _("I can't find my provider and I wish to enter it _manually:"));
 
786
        g_signal_connect (self->providers_view_radio, "toggled", G_CALLBACK (providers_radio_toggled), self);
 
787
        gtk_box_pack_start (GTK_BOX (vbox), self->provider_unlisted_radio, FALSE, TRUE, 0);
 
788
 
 
789
        alignment = gtk_alignment_new (0, 0, 0, 0);
 
790
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 15, 0);
 
791
        gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
 
792
 
 
793
        unlisted_table = gtk_table_new (2, 2, FALSE);
 
794
        gtk_container_add (GTK_CONTAINER (alignment), unlisted_table);
 
795
 
 
796
        label = gtk_label_new (_("Provider:"));
 
797
        gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
 
798
        gtk_table_attach (GTK_TABLE (unlisted_table), label, 0, 1, 0, 1, 0, 0, 6, 6);
 
799
 
 
800
        self->provider_unlisted_entry = gtk_entry_new ();
 
801
        gtk_entry_set_width_chars (GTK_ENTRY (self->provider_unlisted_entry), 40);
 
802
        g_signal_connect_swapped (self->provider_unlisted_entry, "changed", G_CALLBACK (providers_update_complete), self);
 
803
 
 
804
        alignment = gtk_alignment_new (0, 0.5, 0.66, 0);
 
805
        gtk_container_add (GTK_CONTAINER (alignment), self->provider_unlisted_entry);
 
806
        gtk_table_attach (GTK_TABLE (unlisted_table), alignment,
 
807
                          1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 6, 6);
 
808
 
 
809
#if GTK_CHECK_VERSION(2,23,0)
 
810
        self->provider_unlisted_type_combo = gtk_combo_box_text_new ();
 
811
#else
 
812
        self->provider_unlisted_type_combo = gtk_combo_box_new_text ();
 
813
#endif
 
814
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->provider_unlisted_type_combo);
 
815
#if GTK_CHECK_VERSION(2,23,0)
 
816
        gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (self->provider_unlisted_type_combo),
 
817
#else
 
818
        gtk_combo_box_append_text (GTK_COMBO_BOX (self->provider_unlisted_type_combo),
 
819
#endif
 
820
                                   _("My provider uses GSM technology (GPRS, EDGE, UMTS, HSPA)"));
 
821
#if GTK_CHECK_VERSION(2,23,0)
 
822
        gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (self->provider_unlisted_type_combo),
 
823
#else
 
824
        gtk_combo_box_append_text (GTK_COMBO_BOX (self->provider_unlisted_type_combo),
 
825
#endif
 
826
                                   _("My provider uses CDMA technology (1xRTT, EVDO)"));
 
827
        gtk_combo_box_set_active (GTK_COMBO_BOX (self->provider_unlisted_type_combo), 0);
 
828
 
 
829
        gtk_table_attach (GTK_TABLE (unlisted_table), self->provider_unlisted_type_combo,
 
830
                          1, 2, 1, 2, 0, 0, 6, 6);
 
831
 
 
832
        /* Only show the CDMA/GSM combo if we don't know the device type */
 
833
        if (self->method_type != NMN_MOBILE_ACCESS_METHOD_TYPE_UNKNOWN)
 
834
                gtk_widget_hide (self->provider_unlisted_type_combo);
 
835
 
 
836
        self->providers_idx = gtk_assistant_append_page (GTK_ASSISTANT (self->assistant), vbox);
 
837
        gtk_assistant_set_page_title (GTK_ASSISTANT (self->assistant), vbox, _("Choose your Provider"));
 
838
        gtk_assistant_set_page_type (GTK_ASSISTANT (self->assistant), vbox, GTK_ASSISTANT_PAGE_CONTENT);
 
839
        gtk_widget_show_all (vbox);
 
840
 
 
841
        self->providers_page = vbox;
 
842
}
 
843
 
 
844
static void
 
845
providers_prepare (NMAMobileWizard *self)
 
846
{
 
847
        GtkTreeSelection *selection;
 
848
        GSList *providers, *piter;
 
849
        char *country;
 
850
 
 
851
        gtk_tree_store_clear (self->providers_store);
 
852
 
 
853
        country = get_selected_country (self, NULL);
 
854
        if (!country) {
 
855
                /* Unlisted country */
 
856
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->provider_unlisted_radio), TRUE);
 
857
                gtk_widget_set_sensitive (GTK_WIDGET (self->providers_view_radio), FALSE);
 
858
                goto done;
 
859
        }
 
860
        gtk_widget_set_sensitive (GTK_WIDGET (self->providers_view_radio), TRUE);
 
861
 
 
862
        providers = g_hash_table_lookup (self->providers, country);
 
863
        g_free (country);
 
864
 
 
865
        for (piter = providers; piter; piter = g_slist_next (piter)) {
 
866
                NmnMobileProvider *provider = piter->data;
 
867
                GtkTreeIter provider_iter;
 
868
 
 
869
                /* Ignore providers that don't match the current device type */
 
870
                if (self->method_type != NMN_MOBILE_ACCESS_METHOD_TYPE_UNKNOWN) {
 
871
                        GSList *miter;
 
872
                        guint32 count = 0;
 
873
 
 
874
                        for (miter = provider->methods; miter; miter = g_slist_next (miter)) {
 
875
                                NmnMobileAccessMethod *method = miter->data;
 
876
 
 
877
                                if (self->method_type == method->type)
 
878
                                        count++;
 
879
                        }
 
880
 
 
881
                        if (!count)
 
882
                                continue;
 
883
                }
 
884
 
 
885
                gtk_tree_store_append (GTK_TREE_STORE (self->providers_store), &provider_iter, NULL);
 
886
                gtk_tree_store_set (GTK_TREE_STORE (self->providers_store),
 
887
                                    &provider_iter,
 
888
                                    PROVIDER_COL_NAME,
 
889
                                    provider->name,
 
890
                                    PROVIDER_COL_PROVIDER,
 
891
                                    provider,
 
892
                                    -1);
 
893
        }
 
894
 
 
895
        g_object_set (G_OBJECT (self->providers_view), "enable-search", TRUE, NULL);
 
896
 
 
897
        gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->providers_view), PROVIDER_COL_NAME);
 
898
        gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (self->providers_view),
 
899
                                             providers_search_func, self, NULL);
 
900
 
 
901
        /* If no row has focus yet, focus the first row so that the user can start
 
902
         * incremental search without clicking.
 
903
         */
 
904
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->providers_view));
 
905
        g_assert (selection);
 
906
        if (!gtk_tree_selection_count_selected_rows (selection)) {
 
907
                GtkTreeIter first_iter;
 
908
                GtkTreePath *first_path;
 
909
 
 
910
                if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->providers_sort), &first_iter)) {
 
911
                        first_path = gtk_tree_model_get_path (GTK_TREE_MODEL (self->providers_sort), &first_iter);
 
912
                        if (first_path) {
 
913
                                gtk_tree_selection_select_path (selection, first_path);
 
914
                                gtk_tree_path_free (first_path);
 
915
                        }
 
916
                }
 
917
        }
 
918
 
 
919
done:
 
920
        providers_radio_toggled (NULL, self);
 
921
 
 
922
        /* Initial completeness state */
 
923
        providers_update_complete (self);
 
924
 
 
925
        /* If there's already a selected device, hide the GSM/CDMA radios */
 
926
        if (self->method_type != NMN_MOBILE_ACCESS_METHOD_TYPE_UNKNOWN)
 
927
                gtk_widget_hide (self->provider_unlisted_type_combo);
 
928
        else
 
929
                gtk_widget_show (self->provider_unlisted_type_combo);
 
930
}
 
931
 
 
932
/**********************************************************/
 
933
/* Country page */
 
934
/**********************************************************/
 
935
 
 
936
static gboolean
 
937
country_search_func (GtkTreeModel *model,
 
938
                     gint column,
 
939
                     const char *key,
 
940
                     GtkTreeIter *iter,
 
941
                     gpointer search_data)
 
942
{
 
943
        gboolean unmatched = TRUE;
 
944
        char *country = NULL;
 
945
 
 
946
        if (!key)
 
947
                return TRUE;
 
948
 
 
949
        gtk_tree_model_get (model, iter, column, &country, -1);
 
950
        if (!country)
 
951
                return TRUE;
 
952
 
 
953
        unmatched = !!g_ascii_strncasecmp (country, key, strlen (key));
 
954
        g_free (country);
 
955
        return unmatched;
 
956
}
 
957
 
 
958
static void
 
959
add_one_country (gpointer key, gpointer value, gpointer user_data)
 
960
{
 
961
        NMAMobileWizard *self = user_data;
 
962
        GtkTreeIter country_iter;
 
963
        GtkTreePath *country_path, *country_view_path;
 
964
 
 
965
        g_assert (key);
 
966
 
 
967
        gtk_tree_store_append (GTK_TREE_STORE (self->country_store), &country_iter, NULL);
 
968
        gtk_tree_store_set (GTK_TREE_STORE (self->country_store), &country_iter, 0, key, -1);
 
969
 
 
970
        /* If this country is the same country as the user's current locale,
 
971
         * select it by default.
 
972
         */
 
973
        if (!self->country || g_ascii_strcasecmp (self->country, key))
 
974
                return;
 
975
 
 
976
        country_path = gtk_tree_model_get_path (GTK_TREE_MODEL (self->country_store), &country_iter);
 
977
        if (!country_path)
 
978
                return;
 
979
 
 
980
        country_view_path = gtk_tree_model_sort_convert_child_path_to_path (self->country_sort, country_path);
 
981
        if (country_view_path) {
 
982
                GtkTreeSelection *selection;
 
983
 
 
984
                gtk_tree_view_expand_row (GTK_TREE_VIEW (self->country_view), country_view_path, TRUE);
 
985
 
 
986
                selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->country_view));
 
987
                g_assert (selection);
 
988
                gtk_tree_selection_select_path (selection, country_view_path);
 
989
                gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (self->country_view),
 
990
                                              country_view_path, NULL, TRUE, 0, 0);
 
991
                gtk_tree_path_free (country_view_path);
 
992
        }
 
993
        gtk_tree_path_free (country_path);
 
994
}
 
995
 
 
996
static char *
 
997
get_selected_country (NMAMobileWizard *self, gboolean *out_unlisted)
 
998
{
 
999
        GtkTreeSelection *selection;
 
1000
        GtkTreeModel *model = NULL;
 
1001
        GtkTreeIter iter;
 
1002
        char *country = NULL;
 
1003
        gboolean unlisted = FALSE;
 
1004
 
 
1005
        if (!self->country_codes)
 
1006
                return NULL;
 
1007
 
 
1008
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->country_view));
 
1009
        g_assert (selection);
 
1010
 
 
1011
        if (gtk_tree_selection_get_selected (GTK_TREE_SELECTION (selection), &model, &iter)) {
 
1012
                gtk_tree_model_get (model, &iter, 0, &country, 1, &unlisted, -1);
 
1013
                if (unlisted) {
 
1014
                        g_free (country);
 
1015
                        country = NULL;
 
1016
                        if (out_unlisted)
 
1017
                                *out_unlisted = unlisted;
 
1018
                }
 
1019
        }
 
1020
 
 
1021
        return country;
 
1022
}
 
1023
 
 
1024
static void
 
1025
country_update_complete (NMAMobileWizard *self)
 
1026
{
 
1027
        char *country = NULL;
 
1028
        gboolean unlisted = FALSE;
 
1029
 
 
1030
        country = get_selected_country (self, &unlisted);
 
1031
        gtk_assistant_set_page_complete (GTK_ASSISTANT (self->assistant),
 
1032
                                         self->country_page,
 
1033
                                         (!!country || unlisted));
 
1034
        g_free (country);
 
1035
}
 
1036
 
 
1037
static gint
 
1038
country_sort_func (GtkTreeModel *model,
 
1039
                   GtkTreeIter *a,
 
1040
                   GtkTreeIter *b,
 
1041
                   gpointer user_data)
 
1042
{
 
1043
        char *a_str = NULL, *b_str = NULL;
 
1044
        gboolean a_def = FALSE, b_def = FALSE;
 
1045
        gint ret = 0;
 
1046
 
 
1047
        gtk_tree_model_get (model, a, 0, &a_str, 1, &a_def, -1);
 
1048
        gtk_tree_model_get (model, b, 0, &b_str, 1, &b_def, -1);
 
1049
 
 
1050
        if (a_def) {
 
1051
                ret = -1;
 
1052
                goto out;
 
1053
        } else if (b_def) {
 
1054
                ret = 1;
 
1055
                goto out;
 
1056
        }
 
1057
 
 
1058
        if (a_str && !b_str)
 
1059
                ret = -1;
 
1060
        else if (!a_str && b_str)
 
1061
                ret = 1;
 
1062
        else if (!a_str && !b_str)
 
1063
                ret = 0;
 
1064
        else
 
1065
                ret = g_utf8_collate (a_str, b_str);
 
1066
 
 
1067
out:
 
1068
        g_free (a_str);
 
1069
        g_free (b_str);
 
1070
        return ret;
 
1071
}
 
1072
 
 
1073
static void
 
1074
country_setup (NMAMobileWizard *self)
 
1075
{
 
1076
        GtkWidget *vbox, *label, *scroll, *alignment;
 
1077
        GtkCellRenderer *renderer;
 
1078
        GtkTreeViewColumn *column;
 
1079
        GtkTreeSelection *selection;
 
1080
        GtkTreeIter unlisted_iter;
 
1081
 
 
1082
#if GTK_CHECK_VERSION(3,1,6)
 
1083
        vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
 
1084
#else
 
1085
        vbox = gtk_vbox_new (FALSE, 6);
 
1086
#endif
 
1087
        gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
 
1088
        label = gtk_label_new (_("Country or Region List:"));
 
1089
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
1090
        gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
 
1091
 
 
1092
        self->country_store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
 
1093
 
 
1094
        self->country_sort = GTK_TREE_MODEL_SORT (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (self->country_store)));
 
1095
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self->country_sort), 0, GTK_SORT_ASCENDING);
 
1096
 
 
1097
        self->country_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (self->country_sort));
 
1098
 
 
1099
        renderer = gtk_cell_renderer_text_new ();
 
1100
        column = gtk_tree_view_column_new_with_attributes (_("Country or region"), renderer, "text", 0, NULL);
 
1101
        gtk_tree_view_append_column (GTK_TREE_VIEW (self->country_view), column);
 
1102
        gtk_tree_view_column_set_clickable (column, TRUE);
 
1103
 
 
1104
        /* My country is not listed... */
 
1105
        gtk_tree_store_append (GTK_TREE_STORE (self->country_store), &unlisted_iter, NULL);
 
1106
        gtk_tree_store_set (GTK_TREE_STORE (self->country_store), &unlisted_iter,
 
1107
                            0, _("My country is not listed"),
 
1108
                            1, TRUE,
 
1109
                            -1);
 
1110
        gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (self->country_sort),
 
1111
                                         0,
 
1112
                                         country_sort_func,
 
1113
                                         NULL,
 
1114
                                         NULL);
 
1115
 
 
1116
        /* Add the rest of the providers */
 
1117
        if (self->providers)
 
1118
                g_hash_table_foreach (self->providers, add_one_country, self);
 
1119
        g_object_set (G_OBJECT (self->country_view), "enable-search", TRUE, NULL);
 
1120
 
 
1121
        /* If no row has focus yet, focus the first row so that the user can start
 
1122
         * incremental search without clicking.
 
1123
         */
 
1124
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->country_view));
 
1125
        g_assert (selection);
 
1126
        if (!gtk_tree_selection_count_selected_rows (selection)) {
 
1127
                GtkTreeIter first_iter;
 
1128
                GtkTreePath *first_path;
 
1129
 
 
1130
                if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->country_sort), &first_iter)) {
 
1131
                        first_path = gtk_tree_model_get_path (GTK_TREE_MODEL (self->country_sort), &first_iter);
 
1132
                        if (first_path) {
 
1133
                                gtk_tree_selection_select_path (selection, first_path);
 
1134
                                gtk_tree_path_free (first_path);
 
1135
                        }
 
1136
                }
 
1137
        }
 
1138
 
 
1139
        g_signal_connect_swapped (selection, "changed", G_CALLBACK (country_update_complete), self);
 
1140
 
 
1141
        scroll = gtk_scrolled_window_new (NULL, NULL);
 
1142
        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
 
1143
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
 
1144
                                        GTK_POLICY_NEVER,
 
1145
                                        GTK_POLICY_AUTOMATIC);
 
1146
        gtk_container_add (GTK_CONTAINER (scroll), self->country_view);
 
1147
 
 
1148
        alignment = gtk_alignment_new (0, 0, 1, 1);
 
1149
        gtk_container_add (GTK_CONTAINER (alignment), scroll);
 
1150
        gtk_box_pack_start (GTK_BOX (vbox), alignment, TRUE, TRUE, 6);
 
1151
 
 
1152
        self->country_idx = gtk_assistant_append_page (GTK_ASSISTANT (self->assistant), vbox);
 
1153
        gtk_assistant_set_page_title (GTK_ASSISTANT (self->assistant), vbox, _("Choose your Provider's Country or Region"));
 
1154
        gtk_assistant_set_page_type (GTK_ASSISTANT (self->assistant), vbox, GTK_ASSISTANT_PAGE_CONTENT);
 
1155
        gtk_assistant_set_page_complete (GTK_ASSISTANT (self->assistant), vbox, TRUE);
 
1156
        gtk_widget_show_all (vbox);
 
1157
 
 
1158
        self->country_page = vbox;
 
1159
 
 
1160
        /* Initial completeness state */
 
1161
        country_update_complete (self);
 
1162
}
 
1163
 
 
1164
static gboolean
 
1165
focus_country_view (gpointer user_data)
 
1166
{
 
1167
        NMAMobileWizard *self = user_data;
 
1168
 
 
1169
        self->country_focus_id = 0;
 
1170
        gtk_widget_grab_focus (self->country_view);
 
1171
        return FALSE;
 
1172
}
 
1173
 
 
1174
static void
 
1175
country_prepare (NMAMobileWizard *self)
 
1176
{
 
1177
        gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->country_view), 0);
 
1178
        gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (self->country_view), country_search_func, self, NULL);
 
1179
 
 
1180
        if (!self->country_focus_id)
 
1181
                self->country_focus_id = g_idle_add (focus_country_view, self);
 
1182
 
 
1183
        country_update_complete (self);
 
1184
}
 
1185
 
 
1186
/**********************************************************/
 
1187
/* Intro page */
 
1188
/**********************************************************/
 
1189
 
 
1190
#define INTRO_COL_NAME 0
 
1191
#define INTRO_COL_DEVICE 1
 
1192
#define INTRO_COL_SEPARATOR 2
 
1193
 
 
1194
static gboolean
 
1195
__intro_device_added (NMAMobileWizard *self, NMDevice *device, gboolean select_it)
 
1196
{
 
1197
        GtkTreeIter iter;
 
1198
        const char *desc = utils_get_device_description (device);
 
1199
        NMDeviceModemCapabilities caps;
 
1200
 
 
1201
        if (!NM_IS_DEVICE_MODEM (device))
 
1202
                return FALSE;
 
1203
 
 
1204
        caps = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device));
 
1205
        if (caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS) {
 
1206
                if (!desc)
 
1207
                        desc = _("Installed GSM device");
 
1208
        } else if (caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO) {
 
1209
                if (!desc)
 
1210
                        desc = _("Installed CDMA device");
 
1211
        } else
 
1212
                return FALSE;
 
1213
 
 
1214
        gtk_tree_store_append (GTK_TREE_STORE (self->dev_store), &iter, NULL);
 
1215
        gtk_tree_store_set (GTK_TREE_STORE (self->dev_store),
 
1216
                            &iter,
 
1217
                            INTRO_COL_NAME, desc,
 
1218
                            INTRO_COL_DEVICE, device,
 
1219
                            -1);
 
1220
 
 
1221
        /* Select the device just added */
 
1222
        if (select_it)
 
1223
                gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self->dev_combo), &iter);
 
1224
 
 
1225
        gtk_widget_set_sensitive (self->dev_combo, TRUE);
 
1226
        return TRUE;
 
1227
}
 
1228
 
 
1229
static void
 
1230
intro_device_added_cb (NMClient *client, NMDevice *device, NMAMobileWizard *self)
 
1231
{
 
1232
        __intro_device_added (self, device, TRUE);
 
1233
}
 
1234
 
 
1235
static void
 
1236
intro_device_removed_cb (NMClient *client, NMDevice *device, NMAMobileWizard *self)
 
1237
{
 
1238
        GtkTreeIter iter;
 
1239
        gboolean have_device = FALSE, removed = FALSE;
 
1240
 
 
1241
        if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->dev_store), &iter))
 
1242
                return;
 
1243
 
 
1244
        do {
 
1245
                NMDevice *candidate = NULL;
 
1246
 
 
1247
                gtk_tree_model_get (GTK_TREE_MODEL (self->dev_store), &iter,
 
1248
                                    INTRO_COL_DEVICE, &candidate, -1);
 
1249
                if (candidate) {
 
1250
                        if (candidate == device) {
 
1251
                                gtk_tree_store_remove (GTK_TREE_STORE (self->dev_store), &iter);
 
1252
                                removed = TRUE;
 
1253
                        }
 
1254
                        g_object_unref (candidate);
 
1255
                }
 
1256
        } while (!removed && gtk_tree_model_iter_next (GTK_TREE_MODEL (self->dev_store), &iter));
 
1257
 
 
1258
        /* There's already a selected device item; nothing more to do */
 
1259
        if (gtk_combo_box_get_active (GTK_COMBO_BOX (self->dev_combo)) > 1)
 
1260
                return;
 
1261
 
 
1262
        /* If there are no more devices, select the "Any" item and disable the
 
1263
         * combo box.  If there is no selected item and there is at least one device
 
1264
         * item, select the first one.
 
1265
         */
 
1266
        if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->dev_store), &iter))
 
1267
                return;
 
1268
 
 
1269
        do {
 
1270
                NMDevice *candidate = NULL;
 
1271
 
 
1272
                gtk_tree_model_get (GTK_TREE_MODEL (self->dev_store), &iter,
 
1273
                                    INTRO_COL_DEVICE, &candidate, -1);
 
1274
                if (candidate) {
 
1275
                        have_device = TRUE;
 
1276
                        g_object_unref (candidate);
 
1277
                }
 
1278
        } while (!have_device && gtk_tree_model_iter_next (GTK_TREE_MODEL (self->dev_store), &iter));
 
1279
 
 
1280
        if (have_device) {
 
1281
                /* Iter should point to the last device item in the combo */
 
1282
                gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self->dev_combo), &iter);
 
1283
        } else {
 
1284
                gtk_combo_box_set_active (GTK_COMBO_BOX (self->dev_combo), 0);
 
1285
                gtk_widget_set_sensitive (self->dev_combo, FALSE);
 
1286
        }
 
1287
}
 
1288
 
 
1289
static void
 
1290
intro_add_initial_devices (NMAMobileWizard *self)
 
1291
{
 
1292
        const GPtrArray *devices;
 
1293
        gboolean selected_first = FALSE;
 
1294
        int i;
 
1295
 
 
1296
        devices = nm_client_get_devices (self->client);
 
1297
        for (i = 0; devices && (i < devices->len); i++) {
 
1298
                if (__intro_device_added (self, g_ptr_array_index (devices, i), !selected_first)) {
 
1299
                        if (selected_first == FALSE)
 
1300
                                selected_first = TRUE;
 
1301
                }
 
1302
        }
 
1303
 
 
1304
        /* Otherwise the "Any device" item */
 
1305
        if (!selected_first) {
 
1306
                /* Select the first device item by default */
 
1307
                gtk_combo_box_set_active (GTK_COMBO_BOX (self->dev_combo), 0);
 
1308
                gtk_widget_set_sensitive (self->dev_combo, FALSE);
 
1309
        }
 
1310
}
 
1311
 
 
1312
static void
 
1313
intro_remove_all_devices (NMAMobileWizard *self)
 
1314
{
 
1315
        gtk_tree_store_clear (self->dev_store);
 
1316
 
 
1317
        /* Select the "Any device" item */
 
1318
        gtk_combo_box_set_active (GTK_COMBO_BOX (self->dev_combo), 0);
 
1319
        gtk_widget_set_sensitive (self->dev_combo, FALSE);
 
1320
}
 
1321
 
 
1322
static void
 
1323
intro_manager_running_cb (NMClient *client, GParamSpec *pspec, NMAMobileWizard *self)
 
1324
{
 
1325
        if (nm_client_get_manager_running (client))
 
1326
                intro_add_initial_devices (self);
 
1327
        else
 
1328
                intro_remove_all_devices (self);
 
1329
}
 
1330
 
 
1331
static gboolean
 
1332
intro_row_separator_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
 
1333
{
 
1334
        gboolean separator = FALSE;
 
1335
        gtk_tree_model_get (model, iter, INTRO_COL_SEPARATOR, &separator, -1);
 
1336
        return separator;
 
1337
}
 
1338
 
 
1339
static void
 
1340
intro_combo_changed (NMAMobileWizard *self)
 
1341
{
 
1342
        GtkTreeIter iter;
 
1343
        NMDevice *selected = NULL;
 
1344
        NMDeviceModemCapabilities caps;
 
1345
 
 
1346
        g_free (self->dev_desc);
 
1347
        self->dev_desc = NULL;
 
1348
 
 
1349
        if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self->dev_combo), &iter))
 
1350
                return;
 
1351
 
 
1352
        gtk_tree_model_get (GTK_TREE_MODEL (self->dev_store), &iter,
 
1353
                            INTRO_COL_DEVICE, &selected, -1);
 
1354
        if (selected) {
 
1355
                self->dev_desc = g_strdup (utils_get_device_description (selected));
 
1356
                caps = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (selected));
 
1357
                if (caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS)
 
1358
                        self->method_type = NMN_MOBILE_ACCESS_METHOD_TYPE_GSM;
 
1359
                else if (caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)
 
1360
                        self->method_type = NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA;
 
1361
                else
 
1362
                        g_warning ("%s: unknown modem capabilities 0x%X", __func__, caps);
 
1363
 
 
1364
                g_object_unref (selected);
 
1365
        }
 
1366
}
 
1367
 
 
1368
static void
 
1369
intro_setup (NMAMobileWizard *self)
 
1370
{
 
1371
        GtkWidget *vbox, *label, *alignment, *info_vbox;
 
1372
        GtkCellRenderer *renderer;
 
1373
        char *s;
 
1374
 
 
1375
#if GTK_CHECK_VERSION(3,1,6)
 
1376
        vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
 
1377
#else
 
1378
        vbox = gtk_vbox_new (FALSE, 6);
 
1379
#endif
 
1380
        gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
 
1381
 
 
1382
        label = gtk_label_new (_("This assistant helps you easily set up a mobile broadband connection to a cellular (3G) network."));
 
1383
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
1384
        gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 
1385
        gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 6);
 
1386
 
 
1387
        label = gtk_label_new (_("You will need the following information:"));
 
1388
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
1389
        gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 
1390
        gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 6);
 
1391
 
 
1392
        alignment = gtk_alignment_new (0, 0, 1, 0);
 
1393
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 25, 25, 0);
 
1394
#if GTK_CHECK_VERSION(3,1,6)
 
1395
        info_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
 
1396
#else
 
1397
        info_vbox = gtk_vbox_new (FALSE, 6);
 
1398
#endif
 
1399
        gtk_container_add (GTK_CONTAINER (alignment), info_vbox);
 
1400
        gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 6);
 
1401
 
 
1402
        s = g_strdup_printf ("• %s", _("Your broadband provider's name"));
 
1403
        label = gtk_label_new (s);
 
1404
        g_free (s);
 
1405
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
1406
        gtk_box_pack_start (GTK_BOX (info_vbox), label, FALSE, TRUE, 0);
 
1407
 
 
1408
        s = g_strdup_printf ("• %s", _("Your broadband billing plan name"));
 
1409
        label = gtk_label_new (s);
 
1410
        g_free (s);
 
1411
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
1412
        gtk_box_pack_start (GTK_BOX (info_vbox), label, FALSE, TRUE, 0);
 
1413
 
 
1414
        s = g_strdup_printf ("• %s", _("(in some cases) Your broadband billing plan APN (Access Point Name)"));
 
1415
        label = gtk_label_new (s);
 
1416
        g_free (s);
 
1417
        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
1418
        gtk_box_pack_start (GTK_BOX (info_vbox), label, FALSE, TRUE, 0);
 
1419
 
 
1420
        /* Device combo; only built if the wizard's caller didn't pass one in */
 
1421
        if (!self->initial_method_type) {
 
1422
                GtkTreeIter iter;
 
1423
 
 
1424
                self->client = nm_client_new ();
 
1425
                g_signal_connect (self->client, "device-added",
 
1426
                                  G_CALLBACK (intro_device_added_cb), self);
 
1427
                g_signal_connect (self->client, "device-removed",
 
1428
                                  G_CALLBACK (intro_device_removed_cb), self);
 
1429
                g_signal_connect (self->client, "notify::manager-running",
 
1430
                                  G_CALLBACK (intro_manager_running_cb), self);
 
1431
 
 
1432
                self->dev_store = gtk_tree_store_new (3, G_TYPE_STRING, NM_TYPE_DEVICE, G_TYPE_BOOLEAN);
 
1433
                self->dev_combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (self->dev_store));
 
1434
                gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (self->dev_combo),
 
1435
                                                      intro_row_separator_func, NULL, NULL);
 
1436
 
 
1437
                renderer = gtk_cell_renderer_text_new ();
 
1438
                gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self->dev_combo), renderer, TRUE);
 
1439
                gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self->dev_combo), renderer, "text", INTRO_COL_NAME);
 
1440
 
 
1441
                label = gtk_label_new_with_mnemonic (_("Create a connection for _this mobile broadband device:"));
 
1442
                gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->dev_combo);
 
1443
                gtk_misc_set_alignment (GTK_MISC (label), 0, 1);
 
1444
                gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
 
1445
 
 
1446
                alignment = gtk_alignment_new (0, 0, 0.5, 0);
 
1447
                gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 25, 0);
 
1448
                gtk_container_add (GTK_CONTAINER (alignment), self->dev_combo);
 
1449
                gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
 
1450
 
 
1451
                g_signal_connect_swapped (self->dev_combo, "changed", G_CALLBACK (intro_combo_changed), self);
 
1452
 
 
1453
                /* Any device */
 
1454
                gtk_tree_store_append (GTK_TREE_STORE (self->dev_store), &iter, NULL);
 
1455
                gtk_tree_store_set (GTK_TREE_STORE (self->dev_store), &iter,
 
1456
                                    INTRO_COL_NAME, _("Any device"), -1);
 
1457
 
 
1458
                /* Separator */
 
1459
                gtk_tree_store_append (GTK_TREE_STORE (self->dev_store), &iter, NULL);
 
1460
                gtk_tree_store_set (GTK_TREE_STORE (self->dev_store), &iter,
 
1461
                                    INTRO_COL_SEPARATOR, TRUE, -1);
 
1462
 
 
1463
                intro_add_initial_devices (self);
 
1464
        }
 
1465
 
 
1466
        gtk_widget_show_all (vbox);
 
1467
        gtk_assistant_append_page (GTK_ASSISTANT (self->assistant), vbox);
 
1468
        gtk_assistant_set_page_title (GTK_ASSISTANT (self->assistant),
 
1469
                                      vbox, _("Set up a Mobile Broadband Connection"));
 
1470
 
 
1471
        gtk_assistant_set_page_complete (GTK_ASSISTANT (self->assistant), vbox, TRUE);
 
1472
        gtk_assistant_set_page_type (GTK_ASSISTANT (self->assistant), vbox, GTK_ASSISTANT_PAGE_INTRO);
 
1473
}
 
1474
 
 
1475
/**********************************************************/
 
1476
/* General assistant stuff */
 
1477
/**********************************************************/
 
1478
 
 
1479
static void
 
1480
remove_provider_focus_idle (NMAMobileWizard *self)
 
1481
{
 
1482
        if (self->providers_focus_id) {
 
1483
                g_source_remove (self->providers_focus_id);
 
1484
                self->providers_focus_id = 0;
 
1485
        }
 
1486
}
 
1487
 
 
1488
static void
 
1489
remove_country_focus_idle (NMAMobileWizard *self)
 
1490
{
 
1491
        if (self->country_focus_id) {
 
1492
                g_source_remove (self->country_focus_id);
 
1493
                self->country_focus_id = 0;
 
1494
        }
 
1495
}
 
1496
 
 
1497
static void
 
1498
assistant_prepare (GtkAssistant *assistant, GtkWidget *page, gpointer user_data)
 
1499
{
 
1500
        NMAMobileWizard *self = user_data;
 
1501
 
 
1502
        if (page != self->providers_page)
 
1503
                remove_provider_focus_idle (self);
 
1504
        if (page != self->country_page)
 
1505
                remove_country_focus_idle (self);
 
1506
 
 
1507
        if (page == self->country_page)
 
1508
                country_prepare (self);
 
1509
        else if (page == self->providers_page)
 
1510
                providers_prepare (self);
 
1511
        else if (page == self->plan_page)
 
1512
                plan_prepare (self);
 
1513
        else if (page == self->confirm_page)
 
1514
                confirm_prepare (self);
 
1515
}
 
1516
 
 
1517
static gint
 
1518
forward_func (gint current_page, gpointer user_data)
 
1519
{
 
1520
        NMAMobileWizard *self = user_data;
 
1521
 
 
1522
        if (current_page == self->providers_idx) {
 
1523
                NmnMobileAccessMethodType method_type = self->method_type;
 
1524
 
 
1525
                /* If the provider is unlisted, we can skip ahead of the user's
 
1526
                 * access technology is CDMA.
 
1527
                 */
 
1528
                if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->provider_unlisted_radio))) {
 
1529
                        if (method_type == NMN_MOBILE_ACCESS_METHOD_TYPE_UNKNOWN)
 
1530
                                method_type = get_provider_unlisted_type (self);
 
1531
                } else {
 
1532
                        /* Or, if the provider is only CDMA, then we can also skip ahead */
 
1533
                        NmnMobileProvider *provider;
 
1534
                        GSList *iter;
 
1535
                        gboolean gsm = FALSE, cdma = FALSE;
 
1536
 
 
1537
                        provider = get_selected_provider (self);
 
1538
                        if (provider) {
 
1539
                                for (iter = provider->methods; iter; iter = g_slist_next (iter)) {
 
1540
                                        NmnMobileAccessMethod *method = iter->data;
 
1541
 
 
1542
                                        if (method->type == NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA)
 
1543
                                                cdma = TRUE;
 
1544
                                        else if (method->type == NMN_MOBILE_ACCESS_METHOD_TYPE_GSM)
 
1545
                                                gsm = TRUE;
 
1546
                                }
 
1547
                                nmn_mobile_provider_unref (provider);
 
1548
 
 
1549
                                if (cdma && !gsm)
 
1550
                                        method_type = NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA;
 
1551
                        }
 
1552
                }
 
1553
 
 
1554
                /* Skip to the confirm page if we know its CDMA */
 
1555
                if (method_type == NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA) {
 
1556
                        self->provider_only_cdma = TRUE;
 
1557
                        return self->confirm_idx;
 
1558
                } else
 
1559
                        self->provider_only_cdma = FALSE;
 
1560
        }
 
1561
 
 
1562
        return current_page + 1;
 
1563
}
 
1564
 
 
1565
static char *
 
1566
get_country_from_locale (void)
 
1567
{
 
1568
        char *p, *m, *cc, *lang;
 
1569
 
 
1570
        lang = getenv ("LC_ALL");
 
1571
        if (!lang)
 
1572
                lang = getenv ("LANG");
 
1573
        if (!lang)
 
1574
                return NULL;
 
1575
 
 
1576
        p = strchr (lang, '_');
 
1577
        if (!p || !strlen (p)) {
 
1578
                g_free (p);
 
1579
                return NULL;
 
1580
        }
 
1581
 
 
1582
        p = cc = g_strdup (++p);
 
1583
        m = strchr (cc, '.');
 
1584
        if (m)
 
1585
                *m = '\0';
 
1586
 
 
1587
        while (*p) {
 
1588
                *p = g_ascii_toupper (*p);
 
1589
                p++;
 
1590
        }
 
1591
 
 
1592
        return cc;
 
1593
}
 
1594
 
 
1595
NMAMobileWizard *
 
1596
nma_mobile_wizard_new (GtkWindow *parent,
 
1597
                   GtkWindowGroup *window_group,
 
1598
                   NMDeviceModemCapabilities modem_caps,
 
1599
                   gboolean will_connect_after,
 
1600
                   NMAMobileWizardCallback cb,
 
1601
                   gpointer user_data)
 
1602
{
 
1603
        NMAMobileWizard *self;
 
1604
        char *cc;
 
1605
 
 
1606
        self = g_malloc0 (sizeof (NMAMobileWizard));
 
1607
        g_return_val_if_fail (self != NULL, NULL);
 
1608
 
 
1609
        self->providers = nmn_mobile_providers_parse (&(self->country_codes));
 
1610
        if (!self->providers || !self->country_codes) {
 
1611
                nma_mobile_wizard_destroy (self);
 
1612
                return NULL;
 
1613
        }
 
1614
 
 
1615
        cc = get_country_from_locale ();
 
1616
        if (cc)
 
1617
                self->country = g_hash_table_lookup (self->country_codes, cc);
 
1618
        g_free (cc);
 
1619
 
 
1620
        self->will_connect_after = will_connect_after;
 
1621
        self->callback = cb;
 
1622
        self->user_data = user_data;
 
1623
        if (modem_caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS)
 
1624
                self->method_type = NMN_MOBILE_ACCESS_METHOD_TYPE_GSM;
 
1625
        else if (modem_caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)
 
1626
                self->method_type = NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA;
 
1627
        if (self->method_type)
 
1628
                self->initial_method_type = TRUE;  /* Skip device selection */
 
1629
 
 
1630
        self->assistant = gtk_assistant_new ();
 
1631
        gtk_assistant_set_forward_page_func (GTK_ASSISTANT (self->assistant),
 
1632
                                             forward_func, self, NULL);
 
1633
        gtk_window_set_title (GTK_WINDOW (self->assistant), _("New Mobile Broadband Connection"));
 
1634
        gtk_window_set_position (GTK_WINDOW (self->assistant), GTK_WIN_POS_CENTER_ALWAYS);
 
1635
 
 
1636
        intro_setup (self);
 
1637
        country_setup (self);
 
1638
        providers_setup (self);
 
1639
        plan_setup (self);
 
1640
        confirm_setup (self);
 
1641
 
 
1642
        g_signal_connect (self->assistant, "close", G_CALLBACK (assistant_closed), self);
 
1643
        g_signal_connect (self->assistant, "cancel", G_CALLBACK (assistant_cancel), self);
 
1644
        g_signal_connect (self->assistant, "prepare", G_CALLBACK (assistant_prepare), self);
 
1645
 
 
1646
        /* Run the wizard */
 
1647
        if (parent)
 
1648
                gtk_window_set_transient_for (GTK_WINDOW (self->assistant), parent);
 
1649
        gtk_window_set_modal (GTK_WINDOW (self->assistant), TRUE);
 
1650
        gtk_window_set_skip_taskbar_hint (GTK_WINDOW (self->assistant), TRUE);
 
1651
        gtk_window_set_type_hint (GTK_WINDOW (self->assistant), GDK_WINDOW_TYPE_HINT_DIALOG);
 
1652
 
 
1653
        if (window_group)
 
1654
                gtk_window_group_add_window (window_group, GTK_WINDOW (self->assistant));
 
1655
 
 
1656
        return self;
 
1657
}
 
1658
 
 
1659
void
 
1660
nma_mobile_wizard_present (NMAMobileWizard *self)
 
1661
{
 
1662
        g_return_if_fail (self != NULL);
 
1663
 
 
1664
        gtk_window_present (GTK_WINDOW (self->assistant));
 
1665
        gtk_widget_show_all (self->assistant);
 
1666
}
 
1667
 
 
1668
void
 
1669
nma_mobile_wizard_destroy (NMAMobileWizard *self)
 
1670
{
 
1671
        g_return_if_fail (self != NULL);
 
1672
 
 
1673
        g_free (self->dev_desc);
 
1674
 
 
1675
        if (self->assistant) {
 
1676
                gtk_widget_hide (self->assistant);
 
1677
                gtk_widget_destroy (self->assistant);
 
1678
        }
 
1679
 
 
1680
        if (self->client)
 
1681
                g_object_unref (self->client);
 
1682
 
 
1683
        remove_provider_focus_idle (self);
 
1684
        remove_country_focus_idle (self);
 
1685
 
 
1686
        if (self->providers)
 
1687
                g_hash_table_destroy (self->providers);
 
1688
 
 
1689
        if (self->country_codes)
 
1690
                g_hash_table_destroy (self->country_codes);
 
1691
 
 
1692
        g_free (self);
 
1693
}
 
1694
 
 
1695