GCC Code Coverage Report


Directory: ./
File: panels/wwan/cc-wwan-network-dialog.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 167 0.0%
Functions: 0 23 0.0%
Branches: 0 64 0.0%

Line Branch Exec Source
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* cc-wwan-network-dialog.c
3 *
4 * Copyright 2019,2022 Purism SPC
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 3 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
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author(s):
20 * Mohammed Sadiq <sadiq@sadiqpk.org>
21 *
22 * SPDX-License-Identifier: GPL-3.0-or-later
23 */
24
25 #undef G_LOG_DOMAIN
26 #define G_LOG_DOMAIN "cc-wwan-network-dialog"
27
28 #include <config.h>
29 #include <glib/gi18n.h>
30 #include <libmm-glib.h>
31
32 #include "cc-wwan-errors-private.h"
33 #include "cc-wwan-network-dialog.h"
34 #include "cc-wwan-resources.h"
35
36 /**
37 * @short_description: WWAN network operator selection dialog
38 */
39
40 #define CC_TYPE_WWAN_NETWORK_ROW (cc_wwan_network_row_get_type())
41 G_DECLARE_FINAL_TYPE (CcWwanNetworkRow, cc_wwan_network_row, CC, WWAN_NETWORK_ROW, GtkListBoxRow)
42
43 struct _CcWwanNetworkDialog
44 {
45 GtkDialog parent_instance;
46
47 AdwToastOverlay *toast_overlay;
48 AdwSwitchRow *automatic_row;
49 GtkButton *button_apply;
50 GtkSpinner *loading_spinner;
51 GtkBox *network_search_title;
52 GtkListBox *operator_list_box;
53 GtkButton *refresh_button;
54
55 CcWwanDevice *device;
56 GList *operator_list;
57
58 CcWwanNetworkRow *selected_row;
59
60 GCancellable *search_cancellable;
61
62 gboolean no_update_network;
63 };
64
65 G_DEFINE_TYPE (CcWwanNetworkDialog, cc_wwan_network_dialog, GTK_TYPE_DIALOG)
66
67
68 enum {
69 PROP_0,
70 PROP_DEVICE,
71 N_PROPS
72 };
73
74 static GParamSpec *properties[N_PROPS];
75
76 struct _CcWwanNetworkRow
77 {
78 GtkListBoxRow parent_instance;
79 GtkImage *ok_emblem;
80 gchar *operator_code;
81 };
82
83 G_DEFINE_TYPE (CcWwanNetworkRow, cc_wwan_network_row, GTK_TYPE_LIST_BOX_ROW)
84
85 static void
86 cc_wwan_network_row_finalize (GObject *object)
87 {
88 CcWwanNetworkRow *row = (CcWwanNetworkRow *)object;
89
90 g_free (row->operator_code);
91
92 G_OBJECT_CLASS (cc_wwan_network_row_parent_class)->finalize (object);
93 }
94
95 static void
96 cc_wwan_network_row_class_init (CcWwanNetworkRowClass *klass)
97 {
98 GObjectClass *object_class = G_OBJECT_CLASS (klass);
99
100 object_class->finalize = cc_wwan_network_row_finalize;
101 }
102
103 static void
104 cc_wwan_network_row_init (CcWwanNetworkRow *row)
105 {
106 }
107
108 static void
109 cc_wwan_network_changed_cb (CcWwanNetworkDialog *self,
110 CcWwanNetworkRow *row)
111 {
112 if (row == self->selected_row)
113 return;
114
115 gtk_widget_set_sensitive (GTK_WIDGET (self->button_apply), TRUE);
116 gtk_widget_set_visible (GTK_WIDGET (row->ok_emblem), TRUE);
117
118 if (self->selected_row)
119 gtk_widget_set_visible (GTK_WIDGET (self->selected_row->ok_emblem), FALSE);
120
121 self->selected_row = row;
122 }
123
124 /*
125 * cc_wwan_network_dialog_row_new:
126 * @self: a #CcWwanNetworkDialog
127 * @operator_name: (transfer full): The long operator name
128 * @operator_id: (transfer full): operator id
129 */
130 static CcWwanNetworkRow *
131 cc_wwan_network_dialog_row_new (CcWwanNetworkDialog *self,
132 const gchar *operator_name,
133 const gchar *operator_code)
134 {
135 CcWwanNetworkRow *row;
136 GtkWidget *box, *label, *image;
137
138 row = g_object_new (CC_TYPE_WWAN_NETWORK_ROW, NULL);
139
140 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
141 g_object_set (box,
142 "margin-top", 18,
143 "margin-bottom", 18,
144 "margin-start", 18,
145 "margin-end", 18,
146 NULL);
147 gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
148
149 label = gtk_label_new (operator_name);
150 gtk_widget_set_hexpand (label, TRUE);
151 gtk_widget_set_halign (label, GTK_ALIGN_START);
152 gtk_box_append (GTK_BOX (box), label);
153
154 image = gtk_image_new_from_icon_name ("emblem-ok-symbolic");
155 gtk_widget_set_visible (image, FALSE);
156 row->ok_emblem = GTK_IMAGE (image);
157 gtk_box_append (GTK_BOX (box), image);
158
159 row->operator_code = g_strdup (operator_code);
160
161 return row;
162 }
163
164 static void
165 cc_wwan_network_dialog_update_current_network (CcWwanNetworkDialog *self)
166 {
167 CcWwanNetworkRow *row;
168 GtkWidget *child;
169 const gchar *operator_name;
170
171 operator_name = cc_wwan_device_get_operator_name (self->device);
172
173 if (!operator_name || operator_name[0] == '\0')
174 return;
175
176 child = gtk_widget_get_first_child (GTK_WIDGET (self->operator_list_box));
177
178 while (child)
179 {
180 GtkWidget *next;
181
182 next = gtk_widget_get_next_sibling (child);
183 gtk_list_box_remove (GTK_LIST_BOX (self->operator_list_box), child);
184
185 child = next;
186 }
187
188 row = cc_wwan_network_dialog_row_new (self, operator_name, "");
189 self->selected_row = row;
190 gtk_widget_set_visible (GTK_WIDGET (row->ok_emblem), TRUE);
191 gtk_list_box_append (GTK_LIST_BOX (self->operator_list_box), GTK_WIDGET (row));
192 }
193
194 static void
195 cc_wwan_network_dialog_update (CcWwanNetworkDialog *self)
196 {
197 CcWwanNetworkRow *row;
198 GtkWidget *child;
199 GList *item;
200 const gchar *operator_code, *operator_name;
201
202 child = gtk_widget_get_first_child (GTK_WIDGET (self->operator_list_box));
203
204 while (child)
205 {
206 GtkWidget *next;
207
208 next = gtk_widget_get_next_sibling (child);
209 gtk_list_box_remove (GTK_LIST_BOX (self->operator_list_box), child);
210
211 child = next;
212 }
213
214 for (item = self->operator_list; item; item = item->next)
215 {
216 operator_code = mm_modem_3gpp_network_get_operator_code (item->data);
217 operator_name = mm_modem_3gpp_network_get_operator_long (item->data);
218
219 row = cc_wwan_network_dialog_row_new (self, operator_name, operator_code);
220 gtk_list_box_append (GTK_LIST_BOX (self->operator_list_box), GTK_WIDGET (row));
221 }
222 }
223
224 static void
225 cc_wwan_network_scan_complete_cb (GObject *object,
226 GAsyncResult *result,
227 gpointer user_data)
228 {
229 g_autoptr(CcWwanNetworkDialog) self = user_data;
230 g_autoptr(GError) error = NULL;
231
232 if (self->operator_list)
233 g_list_free_full (self->operator_list, (GDestroyNotify)mm_modem_3gpp_network_free);
234
235 gtk_widget_set_sensitive (GTK_WIDGET (self->refresh_button), TRUE);
236 gtk_spinner_stop (self->loading_spinner);
237 self->operator_list = cc_wwan_device_scan_networks_finish (self->device, result, &error);
238 gtk_widget_set_sensitive (GTK_WIDGET (self->operator_list_box), !error);
239
240 if (!error)
241 {
242 cc_wwan_network_dialog_update (self);
243 gtk_widget_set_visible (GTK_WIDGET (self->operator_list_box), TRUE);
244 }
245 else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
246 {
247 AdwToast *toast;
248
249 self->no_update_network = TRUE;
250 gtk_widget_activate (GTK_WIDGET (self->automatic_row));
251 gtk_widget_set_sensitive (GTK_WIDGET (self->operator_list_box), FALSE);
252
253 toast = adw_toast_new (cc_wwan_error_get_message (error));
254 adw_toast_overlay_add_toast (self->toast_overlay, toast);
255
256 gtk_widget_set_visible (GTK_WIDGET (self->operator_list_box), TRUE);
257 g_warning ("Error: scanning networks failed: %s", error->message);
258 }
259 }
260
261 static void
262 cc_wwan_network_dialog_refresh_networks (CcWwanNetworkDialog *self)
263 {
264 gtk_widget_set_sensitive (GTK_WIDGET (self->refresh_button), FALSE);
265 gtk_spinner_start (self->loading_spinner);
266 cc_wwan_device_scan_networks (self->device, self->search_cancellable,
267 (GAsyncReadyCallback)cc_wwan_network_scan_complete_cb,
268 g_object_ref (self));
269 }
270
271 static void
272 cc_wwan_network_dialog_apply_clicked_cb (CcWwanNetworkDialog *self)
273 {
274 gboolean is_auto;
275
276 g_assert (CC_IS_WWAN_NETWORK_DIALOG (self));
277
278 is_auto = adw_switch_row_get_active (self->automatic_row);
279
280 if (is_auto)
281 cc_wwan_device_register_network (self->device, "", NULL, NULL, NULL);
282 else if (self->selected_row)
283 cc_wwan_device_register_network (self->device, self->selected_row->operator_code, NULL, NULL, self);
284 else
285 g_warn_if_reached ();
286
287 gtk_widget_set_visible (GTK_WIDGET (self), FALSE);
288 }
289
290 static void
291 cc_wwan_auto_network_changed_cb (CcWwanNetworkDialog *self,
292 GParamSpec *pspec,
293 AdwSwitchRow *auto_network_row)
294 {
295 gboolean is_auto;
296
297 g_assert (CC_IS_WWAN_NETWORK_DIALOG (self));
298 g_assert (ADW_IS_SWITCH_ROW (auto_network_row));
299
300 is_auto = adw_switch_row_get_active (auto_network_row);
301 gtk_widget_set_sensitive (GTK_WIDGET (self->button_apply), is_auto);
302
303 if (self->no_update_network)
304 {
305 self->no_update_network = FALSE;
306 return;
307 }
308
309 self->selected_row = NULL;
310 gtk_widget_set_visible (GTK_WIDGET (self->network_search_title), !is_auto);
311 gtk_widget_set_sensitive (GTK_WIDGET (self->operator_list_box), !is_auto);
312 gtk_widget_set_visible (GTK_WIDGET (self->operator_list_box), FALSE);
313
314 if (is_auto)
315 {
316 g_cancellable_cancel (self->search_cancellable);
317 g_cancellable_reset (self->search_cancellable);
318 }
319 else
320 {
321 cc_wwan_network_dialog_refresh_networks (self);
322 }
323 }
324
325 static void
326 cc_wwan_network_dialog_show (GtkWidget *widget)
327 {
328 CcWwanNetworkDialog *self = (CcWwanNetworkDialog *)widget;
329 gboolean is_auto;
330
331 is_auto = cc_wwan_device_is_auto_network (self->device);
332
333 self->no_update_network = TRUE;
334 g_object_set (self->automatic_row, "active", is_auto, NULL);
335
336 cc_wwan_network_dialog_update_current_network (self);
337
338 GTK_WIDGET_CLASS (cc_wwan_network_dialog_parent_class)->show (widget);
339 }
340
341 static void
342 cc_wwan_network_dialog_set_property (GObject *object,
343 guint prop_id,
344 const GValue *value,
345 GParamSpec *pspec)
346 {
347 CcWwanNetworkDialog *self = (CcWwanNetworkDialog *)object;
348
349 switch (prop_id)
350 {
351 case PROP_DEVICE:
352 self->device = g_value_dup_object (value);
353 break;
354
355 default:
356 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
357 }
358 }
359
360 static void
361 cc_wwan_network_dialog_dispose (GObject *object)
362 {
363 CcWwanNetworkDialog *self = (CcWwanNetworkDialog *)object;
364
365 g_cancellable_cancel (self->search_cancellable);
366
367 g_clear_object (&self->search_cancellable);
368 g_clear_object (&self->device);
369
370 G_OBJECT_CLASS (cc_wwan_network_dialog_parent_class)->dispose (object);
371 }
372
373 static void
374 cc_wwan_network_dialog_class_init (CcWwanNetworkDialogClass *klass)
375 {
376 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
377 GObjectClass *object_class = G_OBJECT_CLASS (klass);
378
379 object_class->set_property = cc_wwan_network_dialog_set_property;
380 object_class->dispose = cc_wwan_network_dialog_dispose;
381
382 widget_class->show = cc_wwan_network_dialog_show;
383
384 properties[PROP_DEVICE] =
385 g_param_spec_object ("device",
386 "Device",
387 "The WWAN Device",
388 CC_TYPE_WWAN_DEVICE,
389 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
390
391 g_object_class_install_properties (object_class, N_PROPS, properties);
392
393 gtk_widget_class_set_template_from_resource (widget_class,
394 "/org/gnome/control-center/wwan/cc-wwan-network-dialog.ui");
395
396 gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, toast_overlay);
397 gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, automatic_row);
398 gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, button_apply);
399 gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, loading_spinner);
400 gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, network_search_title);
401 gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, operator_list_box);
402 gtk_widget_class_bind_template_child (widget_class, CcWwanNetworkDialog, refresh_button);
403
404 gtk_widget_class_bind_template_callback (widget_class, cc_wwan_network_changed_cb);
405 gtk_widget_class_bind_template_callback (widget_class, cc_wwan_auto_network_changed_cb);
406 gtk_widget_class_bind_template_callback (widget_class, cc_wwan_network_dialog_refresh_networks);
407 gtk_widget_class_bind_template_callback (widget_class, cc_wwan_network_dialog_apply_clicked_cb);
408 }
409
410 static void
411 cc_wwan_network_dialog_init (CcWwanNetworkDialog *self)
412 {
413 gtk_widget_init_template (GTK_WIDGET (self));
414
415 self->search_cancellable = g_cancellable_new ();
416 }
417
418 GtkWindow *
419 cc_wwan_network_dialog_new (GtkWindow *parent_window,
420 CcWwanDevice *device)
421 {
422 g_return_val_if_fail (GTK_IS_WINDOW (parent_window), NULL);
423 g_return_val_if_fail (CC_IS_WWAN_DEVICE (device), NULL);
424
425 return GTK_WINDOW (g_object_new (CC_TYPE_WWAN_NETWORK_DIALOG,
426 "transient-for", parent_window,
427 "use-header-bar", 1,
428 "device", device,
429 NULL));
430 }
431