GCC Code Coverage Report


Directory: ./
File: panels/printers/pp-ipp-option-widget.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 224 0.0%
Functions: 0 20 0.0%
Branches: 0 111 0.0%

Line Branch Exec Source
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright 2012 Red Hat, Inc,
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Marek Kasik <mkasik@redhat.com>
19 */
20
21 #include "config.h"
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <glib/gi18n-lib.h>
27
28 #include "pp-ipp-option-widget.h"
29 #include "pp-utils.h"
30
31 static void pp_ipp_option_widget_finalize (GObject *object);
32
33 static gboolean construct_widget (PpIPPOptionWidget *self);
34 static void update_widget (PpIPPOptionWidget *self);
35 static void update_widget_real (PpIPPOptionWidget *self);
36
37 struct _PpIPPOptionWidget
38 {
39 GtkBox parent_instance;
40
41 GtkWidget *switch_button;
42 GtkWidget *spin_button;
43 GtkWidget *dropdown;
44
45 IPPAttribute *option_supported;
46 IPPAttribute *option_default;
47
48 gchar *printer_name;
49 gchar *option_name;
50
51 GHashTable *ipp_attribute;
52
53 GCancellable *cancellable;
54 };
55
56 G_DEFINE_TYPE (PpIPPOptionWidget, pp_ipp_option_widget, GTK_TYPE_BOX)
57
58 static const struct {
59 const char *keyword;
60 const char *choice;
61 const char *translation;
62 } ipp_choice_translations[] = {
63 /* Translators: this is an option of "Two Sided" */
64 { "sides", "one-sided", N_("One Sided") },
65 /* Translators: this is an option of "Two Sided" */
66 { "sides", "two-sided-long-edge", N_("Long Edge (Standard)") },
67 /* Translators: this is an option of "Two Sided" */
68 { "sides", "two-sided-short-edge", N_("Short Edge (Flip)") },
69 /* Translators: this is an option of "Orientation" */
70 { "orientation-requested", "3", N_("Portrait") },
71 /* Translators: this is an option of "Orientation" */
72 { "orientation-requested", "4", N_("Landscape") },
73 /* Translators: this is an option of "Orientation" */
74 { "orientation-requested", "5", N_("Reverse landscape") },
75 /* Translators: this is an option of "Orientation" */
76 { "orientation-requested", "6", N_("Reverse portrait") },
77 };
78
79 static const gchar *
80 ipp_choice_translate (const gchar *option,
81 const gchar *choice)
82 {
83 gint i;
84
85 for (i = 0; i < G_N_ELEMENTS (ipp_choice_translations); i++)
86 {
87 if (g_strcmp0 (ipp_choice_translations[i].keyword, option) == 0 &&
88 g_strcmp0 (ipp_choice_translations[i].choice, choice) == 0)
89 {
90 return _(ipp_choice_translations[i].translation);
91 }
92 }
93
94 return choice;
95 }
96
97 static void
98 pp_ipp_option_widget_class_init (PpIPPOptionWidgetClass *class)
99 {
100 GObjectClass *object_class;
101
102 object_class = G_OBJECT_CLASS (class);
103
104 object_class->finalize = pp_ipp_option_widget_finalize;
105 }
106
107 static void
108 pp_ipp_option_widget_init (PpIPPOptionWidget *self)
109 {
110 gtk_orientable_set_orientation (GTK_ORIENTABLE (self),
111 GTK_ORIENTATION_HORIZONTAL);
112 }
113
114 static void
115 pp_ipp_option_widget_finalize (GObject *object)
116 {
117 PpIPPOptionWidget *self = PP_IPP_OPTION_WIDGET (object);
118
119 g_cancellable_cancel (self->cancellable);
120
121 g_clear_pointer (&self->option_name, g_free);
122 g_clear_pointer (&self->printer_name, g_free);
123 g_clear_pointer (&self->option_supported, ipp_attribute_free);
124 g_clear_pointer (&self->option_default, ipp_attribute_free);
125 g_clear_pointer (&self->ipp_attribute, g_hash_table_unref);
126 g_clear_object (&self->cancellable);
127
128 G_OBJECT_CLASS (pp_ipp_option_widget_parent_class)->finalize (object);
129 }
130
131 GtkWidget *
132 pp_ipp_option_widget_new (IPPAttribute *attr_supported,
133 IPPAttribute *attr_default,
134 const gchar *option_name,
135 const gchar *printer)
136 {
137 PpIPPOptionWidget *self = NULL;
138
139 if (attr_supported && option_name && printer)
140 {
141 self = g_object_new (PP_TYPE_IPP_OPTION_WIDGET, NULL);
142
143 self->printer_name = g_strdup (printer);
144 self->option_name = g_strdup (option_name);
145 self->option_supported = ipp_attribute_copy (attr_supported);
146 self->option_default = ipp_attribute_copy (attr_default);
147
148 if (construct_widget (self))
149 {
150 update_widget_real (self);
151 }
152 else
153 {
154 g_object_ref_sink (self);
155 g_object_unref (self);
156 self = NULL;
157 }
158 }
159
160 return (GtkWidget *) self;
161 }
162
163 static GtkWidget *
164 dropdown_new (void)
165 {
166 GtkStringList *store = NULL;
167 GtkWidget *dropdown;
168
169 store = gtk_string_list_new (NULL);
170
171 dropdown = gtk_drop_down_new (G_LIST_MODEL (store), NULL);
172
173 return dropdown;
174 }
175
176 static void
177 dropdown_append (GtkWidget *dropdown,
178 const gchar *display_text)
179 {
180 GtkStringList *store;
181
182 store = GTK_STRING_LIST (gtk_drop_down_get_model (GTK_DROP_DOWN (dropdown)));
183
184 gtk_string_list_append (store, display_text);
185 }
186
187 static void
188 dropdown_set (GtkWidget *dropdown,
189 IPPAttribute *option,
190 const gchar *value)
191 {
192 g_autofree gchar *attribute_value = NULL;
193
194 for (guint i = 0; i < option->num_of_values; i++)
195 {
196 if (option->attribute_type == IPP_ATTRIBUTE_TYPE_INTEGER)
197 attribute_value = g_strdup_printf ("%d", option->attribute_values[i].integer_value);
198 else
199 attribute_value = g_strdup (option->attribute_values[i].string_value);
200
201 if (g_strcmp0 (attribute_value, value) == 0)
202 {
203 gtk_drop_down_set_selected (GTK_DROP_DOWN (dropdown), i);
204 break;
205 }
206 }
207 }
208
209 static char *
210 dropdown_get (GtkWidget *dropdown,
211 IPPAttribute *option)
212 {
213 guint selected_item;
214 gchar *value = NULL;
215
216 selected_item = gtk_drop_down_get_selected (GTK_DROP_DOWN (dropdown));
217
218 if (selected_item != GTK_INVALID_LIST_POSITION)
219 {
220 if (option->attribute_type == IPP_ATTRIBUTE_TYPE_INTEGER)
221 value = g_strdup_printf ("%d", option->attribute_values[selected_item].integer_value);
222 else
223 value = option->attribute_values[selected_item].string_value;
224 }
225
226 return value;
227 }
228
229 static void
230 printer_add_option_async_cb (gboolean success,
231 gpointer user_data)
232 {
233 PpIPPOptionWidget *self = user_data;
234
235 update_widget (user_data);
236 g_clear_object (&self->cancellable);
237 }
238
239 static void
240 switch_changed_cb (PpIPPOptionWidget *self)
241 {
242 gchar **values;
243
244 values = g_new0 (gchar *, 2);
245
246 if (gtk_switch_get_active (GTK_SWITCH (self->switch_button)))
247 values[0] = g_strdup ("True");
248 else
249 values[0] = g_strdup ("False");
250
251 g_cancellable_cancel (self->cancellable);
252 g_clear_object (&self->cancellable);
253
254 self->cancellable = g_cancellable_new ();
255 printer_add_option_async (self->printer_name,
256 self->option_name,
257 values,
258 TRUE,
259 self->cancellable,
260 printer_add_option_async_cb,
261 self);
262
263 g_strfreev (values);
264 }
265
266 static void
267 dropdown_changed_cb (PpIPPOptionWidget *self)
268 {
269 gchar **values;
270
271 values = g_new0 (gchar *, 2);
272 values[0] = g_strdup (dropdown_get (self->dropdown, self->option_supported));
273
274 g_cancellable_cancel (self->cancellable);
275 g_clear_object (&self->cancellable);
276
277 self->cancellable = g_cancellable_new ();
278 printer_add_option_async (self->printer_name,
279 self->option_name,
280 values,
281 TRUE,
282 self->cancellable,
283 printer_add_option_async_cb,
284 self);
285
286 g_strfreev (values);
287 }
288
289 static void
290 spin_button_changed_cb (PpIPPOptionWidget *self)
291 {
292 gchar **values;
293
294 values = g_new0 (gchar *, 2);
295 values[0] = g_strdup_printf ("%d", gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (self->spin_button)));
296
297 g_cancellable_cancel (self->cancellable);
298 g_clear_object (&self->cancellable);
299
300 self->cancellable = g_cancellable_new ();
301 printer_add_option_async (self->printer_name,
302 self->option_name,
303 values,
304 TRUE,
305 self->cancellable,
306 printer_add_option_async_cb,
307 self);
308
309 g_strfreev (values);
310 }
311
312 static gboolean
313 construct_widget (PpIPPOptionWidget *self)
314 {
315 gboolean trivial_option = FALSE;
316 gboolean result = FALSE;
317 gint i;
318
319 if (self->option_supported)
320 {
321 switch (self->option_supported->attribute_type)
322 {
323 case IPP_ATTRIBUTE_TYPE_INTEGER:
324 if (self->option_supported->num_of_values <= 1)
325 trivial_option = TRUE;
326 break;
327
328 case IPP_ATTRIBUTE_TYPE_STRING:
329 if (self->option_supported->num_of_values <= 1)
330 trivial_option = TRUE;
331 break;
332
333 case IPP_ATTRIBUTE_TYPE_RANGE:
334 if (self->option_supported->attribute_values[0].lower_range ==
335 self->option_supported->attribute_values[0].upper_range)
336 trivial_option = TRUE;
337 break;
338 }
339
340 if (!trivial_option)
341 {
342 switch (self->option_supported->attribute_type)
343 {
344 case IPP_ATTRIBUTE_TYPE_BOOLEAN:
345 self->switch_button = gtk_switch_new ();
346
347 gtk_box_append (GTK_BOX (self), self->switch_button);
348 g_signal_connect_object (self->switch_button, "notify::active", G_CALLBACK (switch_changed_cb), self, G_CONNECT_SWAPPED);
349 break;
350
351 case IPP_ATTRIBUTE_TYPE_INTEGER:
352 self->dropdown = dropdown_new ();
353
354 for (i = 0; i < self->option_supported->num_of_values; i++)
355 {
356 g_autofree gchar *value = NULL;
357
358 value = g_strdup_printf ("%d", self->option_supported->attribute_values[i].integer_value);
359 dropdown_append (self->dropdown,
360 ipp_choice_translate (self->option_name,
361 value));
362 }
363
364 gtk_box_append (GTK_BOX (self), self->dropdown);
365 g_signal_connect_object (self->dropdown, "notify::selected", G_CALLBACK (dropdown_changed_cb), self, G_CONNECT_SWAPPED);
366 break;
367
368 case IPP_ATTRIBUTE_TYPE_STRING:
369 self->dropdown = dropdown_new ();
370
371 for (i = 0; i < self->option_supported->num_of_values; i++)
372 dropdown_append (self->dropdown,
373 ipp_choice_translate (self->option_name,
374 self->option_supported->attribute_values[i].string_value));
375
376 gtk_box_append (GTK_BOX (self), self->dropdown);
377 g_signal_connect_object (self->dropdown, "notify::selected", G_CALLBACK (dropdown_changed_cb), self, G_CONNECT_SWAPPED);
378 break;
379
380 case IPP_ATTRIBUTE_TYPE_RANGE:
381 self->spin_button = gtk_spin_button_new_with_range (
382 self->option_supported->attribute_values[0].lower_range,
383 self->option_supported->attribute_values[0].upper_range,
384 1);
385
386 gtk_box_append (GTK_BOX (self), self->spin_button);
387 g_signal_connect_object (self->spin_button, "value-changed", G_CALLBACK (spin_button_changed_cb), self, G_CONNECT_SWAPPED);
388 break;
389
390 default:
391 break;
392 }
393
394 result = TRUE;
395 }
396 }
397
398 return result;
399 }
400
401 static void
402 update_widget_real (PpIPPOptionWidget *self)
403 {
404 IPPAttribute *attr = NULL;
405
406 if (self->option_default)
407 {
408 attr = ipp_attribute_copy (self->option_default);
409
410 ipp_attribute_free (self->option_default);
411 self->option_default = NULL;
412 }
413 else if (self->ipp_attribute)
414 {
415 g_autofree gchar *attr_name = g_strdup_printf ("%s-default", self->option_name);
416 attr = ipp_attribute_copy (g_hash_table_lookup (self->ipp_attribute, attr_name));
417
418 g_hash_table_unref (self->ipp_attribute);
419 self->ipp_attribute = NULL;
420 }
421
422 switch (self->option_supported->attribute_type)
423 {
424 case IPP_ATTRIBUTE_TYPE_BOOLEAN:
425 g_signal_handlers_block_by_func (self->switch_button, switch_changed_cb, self);
426
427 if (attr && attr->num_of_values > 0 &&
428 attr->attribute_type == IPP_ATTRIBUTE_TYPE_BOOLEAN)
429 {
430 gtk_switch_set_active (GTK_SWITCH (self->switch_button),
431 attr->attribute_values[0].boolean_value);
432 }
433
434 g_signal_handlers_unblock_by_func (self->switch_button, switch_changed_cb, self);
435 break;
436
437 case IPP_ATTRIBUTE_TYPE_INTEGER:
438 g_signal_handlers_block_by_func (self->dropdown, dropdown_changed_cb, self);
439
440 if (attr && attr->num_of_values > 0 &&
441 attr->attribute_type == IPP_ATTRIBUTE_TYPE_INTEGER)
442 {
443 g_autofree gchar *value = g_strdup_printf ("%d", attr->attribute_values[0].integer_value);
444 dropdown_set (self->dropdown, self->option_supported, value);
445 }
446 else
447 {
448 g_autofree gchar *value = g_strdup_printf ("%d", self->option_supported->attribute_values[0].integer_value);
449 dropdown_set (self->dropdown, self->option_supported, value);
450 }
451
452 g_signal_handlers_unblock_by_func (self->dropdown, dropdown_changed_cb, self);
453 break;
454
455 case IPP_ATTRIBUTE_TYPE_STRING:
456 g_signal_handlers_block_by_func (self->dropdown, dropdown_changed_cb, self);
457
458 if (attr && attr->num_of_values > 0 &&
459 attr->attribute_type == IPP_ATTRIBUTE_TYPE_STRING)
460 {
461 dropdown_set (self->dropdown, self->option_supported, attr->attribute_values[0].string_value);
462 }
463 else
464 {
465 dropdown_set (self->dropdown, self->option_supported, self->option_supported->attribute_values[0].string_value);
466 }
467
468 g_signal_handlers_unblock_by_func (self->dropdown, dropdown_changed_cb, self);
469 break;
470
471 case IPP_ATTRIBUTE_TYPE_RANGE:
472 g_signal_handlers_block_by_func (self->spin_button, spin_button_changed_cb, self);
473
474 if (attr && attr->num_of_values > 0 &&
475 attr->attribute_type == IPP_ATTRIBUTE_TYPE_INTEGER)
476 {
477 gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->spin_button),
478 attr->attribute_values[0].integer_value);
479 }
480 else
481 {
482 gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->spin_button),
483 self->option_supported->attribute_values[0].lower_range);
484 }
485
486 g_signal_handlers_unblock_by_func (self->spin_button, spin_button_changed_cb, self);
487 break;
488
489 default:
490 break;
491 }
492
493 ipp_attribute_free (attr);
494 }
495
496 static void
497 get_ipp_attributes_cb (GHashTable *table,
498 gpointer user_data)
499 {
500 PpIPPOptionWidget *self = user_data;
501
502 if (self->ipp_attribute)
503 g_hash_table_unref (self->ipp_attribute);
504
505 self->ipp_attribute = g_hash_table_ref (table);
506
507 update_widget_real (self);
508 }
509
510 static void
511 update_widget (PpIPPOptionWidget *self)
512 {
513 gchar **attributes_names;
514
515 attributes_names = g_new0 (gchar *, 2);
516 attributes_names[0] = g_strdup_printf ("%s-default", self->option_name);
517
518 get_ipp_attributes_async (self->printer_name,
519 attributes_names,
520 get_ipp_attributes_cb,
521 self);
522
523 g_strfreev (attributes_names);
524 }
525