OSDN Git Service

LinGui: tidy up how combobox values are handled internally and stored in plists
[handbrake-jp/handbrake-jp-git.git] / gtk / src / values.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * presets.c
4  * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
5  * 
6  * presets.c is free software.
7  * 
8  * You may redistribute it and/or modify it under the terms of the
9  * GNU General Public License, as published by the Free Software
10  * Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  * 
13  */
14
15 #include <glib.h>
16 #include <glib-object.h>
17 #include <string.h>
18 #include "values.h"
19
20 static void dict_delete_key(gpointer data);
21 static void dict_delete_value(gpointer data);
22
23 GValue*
24 ghb_value_new(GType gtype)
25 {
26         GValue *gval = g_malloc0(sizeof(GValue));
27         g_value_init(gval, gtype);
28         return gval;
29 }
30
31 void
32 ghb_value_free(GValue *gval)
33 {
34         if (gval == NULL) return;
35         g_value_unset(gval);
36         g_free(gval);
37 }
38
39 GValue*
40 ghb_value_dup(const GValue *val)
41 {
42         if (val == NULL) return NULL;
43         GValue *copy = ghb_value_new(G_VALUE_TYPE(val));
44         g_value_copy(val, copy);
45         return copy;
46 }
47
48 static void
49 debug_show_type(GType tp)
50 {
51         const gchar *str = "unknown";
52         if (tp == G_TYPE_STRING)
53         {
54                 str ="string";
55         }
56         else if (tp == G_TYPE_INT)
57         {
58                 str ="int";
59         }
60         else if (tp == G_TYPE_INT64)
61         {
62                 str ="int64";
63         }
64         else if (tp == G_TYPE_BOOLEAN)
65         {
66                 str ="bool";
67         }
68         else if (tp == ghb_array_get_type())
69         {
70                 str ="array";
71         }
72         else if (tp == ghb_dict_get_type())
73         {
74                 str ="dict";
75         }
76         g_debug("%s", str);
77 }
78
79 gint
80 ghb_value_int(const GValue *val)
81 {
82         gint result;
83
84         if (val == NULL) return 0;
85         GValue xform = {0,};
86         if (G_VALUE_TYPE(val) != G_TYPE_INT64)
87         {
88                 g_value_init(&xform, G_TYPE_INT64);
89                 if (!g_value_transform(val, &xform))
90                 {
91                         debug_show_type(G_VALUE_TYPE(val));
92                         g_warning("int can't transform");
93                         return 0;
94                 }
95                 result = (gint)g_value_get_int64(&xform);
96                 g_value_unset(&xform);
97         }
98         else
99         {
100                 result = (gint)g_value_get_int64(val);
101         }
102         return result;
103 }
104
105 gint64
106 ghb_value_int64(const GValue *val)
107 {
108         gint64 result;
109
110         if (val == NULL) return 0;
111         GValue xform = {0,};
112         if (G_VALUE_TYPE(val) != G_TYPE_INT64)
113         {
114                 g_value_init(&xform, G_TYPE_INT64);
115                 if (!g_value_transform(val, &xform))
116                 {
117                         debug_show_type(G_VALUE_TYPE(val));
118                         g_warning("int64 can't transform");
119                         return 0;
120                 }
121                 result = g_value_get_int64(&xform);
122                 g_value_unset(&xform);
123         }
124         else
125         {
126                 result = g_value_get_int64(val);
127         }
128         return result;
129 }
130
131 gdouble
132 ghb_value_double(const GValue *val)
133 {
134         gdouble result;
135
136         if (val == NULL) return 0;
137         GValue xform = {0,};
138         if (G_VALUE_TYPE(val) != G_TYPE_DOUBLE)
139         {
140                 g_value_init(&xform, G_TYPE_DOUBLE);
141                 if (!g_value_transform(val, &xform))
142                 {
143                         debug_show_type(G_VALUE_TYPE(val));
144                         g_warning("double can't transform");
145                         return 0;
146                 }
147                 result = g_value_get_double(&xform);
148                 g_value_unset(&xform);
149         }
150         else
151         {
152                 result = g_value_get_double(val);
153         }
154         return result;
155 }
156
157 gchar*
158 ghb_value_string(const GValue *val)
159 {
160         gchar *result;
161
162         if (val == NULL) return 0;
163         GValue xform = {0,};
164         if (G_VALUE_TYPE(val) != G_TYPE_STRING)
165         {
166                 g_value_init(&xform, G_TYPE_STRING);
167                 if (!g_value_transform(val, &xform))
168                 {
169                         debug_show_type(G_VALUE_TYPE(val));
170                         g_warning("string can't transform");
171                         return NULL;
172                 }
173                 result = g_strdup(g_value_get_string(&xform));
174                 g_value_unset(&xform);
175         }
176         else
177         {
178                 result = g_strdup(g_value_get_string(val));
179         }
180         return result;
181 }
182
183 gboolean
184 ghb_value_boolean(const GValue *val)
185 {
186         gboolean result;
187
188         if (val == NULL) return FALSE;
189         GValue xform = {0,};
190         if (G_VALUE_TYPE(val) != G_TYPE_BOOLEAN)
191         {
192                 g_value_init(&xform, G_TYPE_BOOLEAN);
193                 if (!g_value_transform(val, &xform))
194                 {
195                         debug_show_type(G_VALUE_TYPE(val));
196                         g_warning("boolean can't transform");
197                         return FALSE;
198                 }
199                 result = g_value_get_boolean(&xform);
200                 g_value_unset(&xform);
201         }
202         else
203         {
204                 result = g_value_get_boolean(val);
205         }
206         return result;
207 }
208
209 gint
210 ghb_value_cmp(const GValue *vala, const GValue *valb)
211 {
212         GType typa;
213         GType typb;
214
215         typa = G_VALUE_TYPE(vala);
216         typb = G_VALUE_TYPE(valb);
217         if (typa != typb)
218         {
219                 return 1;
220         }
221         
222         if (typa == G_TYPE_STRING)
223         {
224                 char *stra, *strb;
225                 gint res;
226                 stra = ghb_value_string(vala);
227                 strb = ghb_value_string(valb);
228                 if (stra == NULL && strb == NULL)
229                         return 0;
230                 if (stra == NULL)
231                 {
232                         g_free(strb);
233                         return -1;
234                 }
235                 if (strb == NULL)
236                 {
237                         g_free(stra);
238                         return 1;
239                 }
240                 res =  strcmp(stra, strb);
241                 g_free(stra);
242                 g_free(strb);
243                 return res;
244         }
245         else if (typa == G_TYPE_INT64 || typa == G_TYPE_INT || 
246                         typa == G_TYPE_BOOLEAN)
247         {
248                 return ghb_value_int64(vala) - ghb_value_int64(valb);
249         }
250         else if (typa == G_TYPE_DOUBLE || typa == G_TYPE_FLOAT)
251         {
252                 return ghb_value_double(vala) - ghb_value_double(valb);
253         }
254         else if (typa == ghb_array_get_type())
255         {
256                 // Cheating here.  Just assume they are different.
257                 // Maybe later I'll recurse through these
258                 return 1;
259         }
260         else if (typa == ghb_dict_get_type())
261         {
262                 // Cheating here.  Just assume they are different.
263                 // Maybe later I'll recurse through these
264                 return 1;
265         }
266         else
267         {
268                 g_warning("ghb_value_cmp: unrecognized type");
269                 return 1;
270         }
271         return 0;
272 }
273
274 GValue*
275 ghb_string_value(const gchar *str)
276 {
277         static GValue gval = {0,};
278         if (!G_IS_VALUE(&gval))
279                 g_value_init(&gval, G_TYPE_STRING);
280         g_value_set_string(&gval, str);
281         return &gval;
282 }
283
284 GValue*
285 ghb_int64_value(gint64 ival)
286 {
287         static GValue gval = {0,};
288         if (!G_IS_VALUE(&gval))
289                 g_value_init(&gval, G_TYPE_INT64);
290         g_value_set_int64(&gval, ival);
291         return &gval;
292 }
293
294 GValue*
295 ghb_int_value(gint ival)
296 {
297         static GValue gval = {0,};
298         if (!G_IS_VALUE(&gval))
299                 g_value_init(&gval, G_TYPE_INT64);
300         g_value_set_int64(&gval, (gint64)ival);
301         return &gval;
302 }
303
304 GValue*
305 ghb_double_value(gdouble dval)
306 {
307         static GValue gval = {0,};
308         if (!G_IS_VALUE(&gval))
309                 g_value_init(&gval, G_TYPE_DOUBLE);
310         g_value_set_double(&gval, dval);
311         return &gval;
312 }
313
314 GValue*
315 ghb_boolean_value(gboolean bval)
316 {
317         static GValue gval = {0,};
318         if (!G_IS_VALUE(&gval))
319                 g_value_init(&gval, G_TYPE_BOOLEAN);
320         g_value_set_boolean(&gval, bval);
321         return &gval;
322 }
323
324 GValue*
325 ghb_string_value_new(const gchar *str)
326 {
327         if (str == NULL) str = "";
328         GValue *gval = ghb_value_new(G_TYPE_STRING);
329         g_value_set_string(gval, str);
330         return gval;
331 }
332
333 GValue*
334 ghb_int64_value_new(gint64 ival)
335 {
336         GValue *gval = ghb_value_new(G_TYPE_INT64);
337         g_value_set_int64(gval, ival);
338         return gval;
339 }
340
341 GValue*
342 ghb_int_value_new(gint ival)
343 {
344         GValue *gval = ghb_value_new(G_TYPE_INT64);
345         g_value_set_int64(gval, ival);
346         return gval;
347 }
348
349 GValue*
350 ghb_double_value_new(gdouble dval)
351 {
352         GValue *gval = ghb_value_new(G_TYPE_DOUBLE);
353         g_value_set_double(gval, dval);
354         return gval;
355 }
356
357 GValue*
358 ghb_boolean_value_new(gboolean bval)
359 {
360         GValue *gval = ghb_value_new(G_TYPE_BOOLEAN);
361         g_value_set_boolean(gval, bval);
362         return gval;
363 }
364
365 GValue*
366 ghb_dict_value_new()
367 {
368         GHashTable *dict;
369         GValue *gval = ghb_value_new(ghb_dict_get_type());
370         dict = g_hash_table_new_full(g_str_hash, g_str_equal,
371                                                                 dict_delete_key, dict_delete_value);
372         g_value_take_boxed(gval, dict);
373         return gval;
374 }
375
376 GValue*
377 ghb_array_value_new(guint size)
378 {
379         GValue *gval = ghb_value_new(ghb_array_get_type());
380         GArray *array;
381
382         array = g_array_sized_new(FALSE, FALSE, sizeof(GValue*), size);
383         g_value_take_boxed(gval, array);
384         return gval;
385 }
386
387 void
388 ghb_array_value_reset(GValue *gval, guint size)
389 {
390         GArray *array;
391         g_value_reset(gval);
392         array = g_array_sized_new(FALSE, FALSE, sizeof(GValue*), size);
393         g_value_take_boxed(gval, array);
394 }
395
396 GValue* 
397 ghb_date_value_new(GDate *date)
398 {
399         GValue *gval = ghb_value_new(g_date_get_type());
400         g_value_set_boxed(gval, date);
401         return gval;
402 }
403
404 GValue* 
405 ghb_rawdata_value_new(ghb_rawdata_t *data)
406 {
407         GValue *gval = ghb_value_new(ghb_rawdata_get_type());
408         g_value_take_boxed(gval, data);
409         return gval;
410 }
411
412 static gpointer
413 rawdata_copy(gpointer boxed)
414 {
415         const ghb_rawdata_t *data = (const ghb_rawdata_t*)boxed;
416         ghb_rawdata_t *copy = g_malloc(sizeof(ghb_rawdata_t));
417         copy->size = data->size;
418         if (data->data)
419         {
420                 copy->data = g_malloc(data->size);
421                 memcpy(copy->data, data->data, data->size);
422         }
423         else
424         {
425                 copy->data = NULL;
426                 copy->size = 0;
427         }
428         return copy;
429 }
430
431 static void
432 rawdata_free(gpointer boxed)
433 {
434         ghb_rawdata_t *data = (ghb_rawdata_t*)boxed;
435         if (data->data) g_free(data->data);
436         g_free(data);
437 }
438
439
440 GType
441 ghb_rawdata_get_type(void)
442 {
443         static GType type_id = 0;
444         if (!type_id)
445                 type_id = g_boxed_type_register_static(g_intern_static_string("GHBData"),
446                         (GBoxedCopyFunc) rawdata_copy,
447                         (GBoxedFreeFunc) rawdata_free);
448         return type_id;
449 }
450
451 static void
452 dict_delete_key(gpointer data)
453 {
454         if (data == NULL)
455         {
456                 g_warning("dict frees null key");
457                 return;
458         }
459         g_free(data);
460 }
461
462 static void
463 dict_delete_value(gpointer data)
464 {
465         GValue *gval = (GValue*)data;
466         if (gval == NULL)
467         {
468                 g_warning("dict frees null value");
469                 return;
470         }
471         ghb_value_free(gval);
472 }
473
474 static gpointer
475 dict_copy(gpointer boxed)
476 {
477         GHashTable *dict = (GHashTable*)boxed;
478         GHashTable *copy;
479         GHashTableIter iter;
480         gchar *key;
481         GValue *gval;
482
483         copy = g_hash_table_new_full(g_str_hash, g_str_equal,
484                                                                 dict_delete_key, dict_delete_value);
485
486         g_hash_table_iter_init(&iter, dict);
487         // middle (void*) cast prevents gcc warning "defreferencing type-punned
488         // pointer will break strict-aliasing rules"
489         while (g_hash_table_iter_next(
490                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
491         {
492                 g_hash_table_insert(copy, g_strdup(key), ghb_value_dup(gval));
493         }
494         return copy;
495 }
496
497 static void
498 dict_free(gpointer boxed)
499 {
500         GHashTable *dict = (GHashTable*)boxed;
501         g_hash_table_destroy(dict);
502 }
503
504
505 GType
506 ghb_dict_get_type(void)
507 {
508         static GType type_id = 0;
509         if (!type_id)
510                 type_id = g_boxed_type_register_static(
511                                                 g_intern_static_string("GHBDict"),
512                                                 (GBoxedCopyFunc) dict_copy,
513                                                 (GBoxedFreeFunc) dict_free);
514         return type_id;
515 }
516
517 void
518 ghb_dict_insert(GValue *gval, gchar *key, GValue *val)
519 {
520         GHashTable *dict = g_value_get_boxed(gval);
521         g_hash_table_insert(dict, key, val);
522 }
523
524 void
525 ghb_dict_iter_init(GHashTableIter *iter, GValue *gval)
526 {
527         GHashTable *dict = g_value_get_boxed(gval);
528         g_hash_table_iter_init(iter, dict);
529 }
530
531 GValue*
532 ghb_dict_lookup(GValue *gval, const gchar *key)
533 {
534         GHashTable *dict = g_value_get_boxed(gval);
535         return g_hash_table_lookup(dict, key);
536 }
537
538 gboolean
539 ghb_dict_remove(GValue *gval, const gchar *key)
540 {
541         GHashTable *dict = g_value_get_boxed(gval);
542         return g_hash_table_remove(dict, key);
543 }
544
545 static gpointer
546 array_copy(gpointer boxed)
547 {
548         const GArray *array = (const GArray*)boxed;
549         GArray *copy = g_array_new(FALSE, FALSE, sizeof(GValue*));
550
551         GValue *gval, *gval_copy;
552         gint ii;
553
554         for (ii = 0; ii < array->len; ii++)
555         {
556                 gval = g_array_index(array, GValue*, ii);
557                 if (gval)
558                 {
559                         gval_copy = ghb_value_dup(gval);
560                         g_array_append_val(copy, gval_copy);
561                 }
562         }
563         return copy;
564 }
565
566 static void
567 array_free(gpointer boxed)
568 {
569         GArray *array = (GArray*)boxed;
570         GValue *gval;
571         gint ii;
572
573         for (ii = 0; ii < array->len; ii++)
574         {
575                 gval = g_array_index(array, GValue*, ii);
576                 if (gval)
577                 {
578                         ghb_value_free(gval);
579                 }
580         }
581         g_array_free(array, TRUE);
582 }
583
584
585 GType
586 ghb_array_get_type(void)
587 {
588         static GType type_id = 0;
589         if (!type_id)
590                 type_id = g_boxed_type_register_static(
591                                                 g_intern_static_string("GHBArray"),
592                                                 (GBoxedCopyFunc) array_copy,
593                                                 (GBoxedFreeFunc) array_free);
594         return type_id;
595 }
596
597 GValue*
598 ghb_array_get_nth(const GValue *gval, gint ii)
599 {
600         GArray *arr = g_value_get_boxed(gval);
601         return g_array_index(arr, GValue*, ii);
602 }
603
604 void
605 ghb_array_insert(GValue *gval, guint ii, GValue *val)
606 {
607         GArray *arr = g_value_get_boxed(gval);
608         // A little nastyness here.  The array pointer
609         // can change when the array changes size.  So
610         // I must re-box it in the GValue each time.
611         arr = g_array_insert_val(arr, ii, val);
612         memset(gval, 0, sizeof(GValue));
613         g_value_init(gval, ghb_array_get_type());
614         g_value_take_boxed(gval, arr);
615 }
616
617 void
618 ghb_array_append(GValue *gval, GValue *val)
619 {
620         GArray *arr = g_value_get_boxed(gval);
621         // A little nastyness here.  The array pointer
622         // can change when the array changes size.  So
623         // I must re-box it in the GValue each time.
624         arr = g_array_append_val(arr, val);
625         memset(gval, 0, sizeof(GValue));
626         g_value_init(gval, ghb_array_get_type());
627         g_value_take_boxed(gval, arr);
628 }
629
630 void
631 ghb_array_remove(GValue *gval, guint ii)
632 {
633         GArray *arr = g_value_get_boxed(gval);
634         // A little nastyness here.  The array pointer
635         // can change when the array changes size.  So
636         // I must re-box it in the GValue each time.
637         arr = g_array_remove_index(arr, ii);
638         memset(gval, 0, sizeof(GValue));
639         g_value_init(gval, ghb_array_get_type());
640         g_value_take_boxed(gval, arr);
641 }
642
643 gint
644 ghb_array_len(const GValue *gval)
645 {
646         if (gval == NULL) return 0;
647         GArray *arr = g_value_get_boxed(gval);
648         return arr->len;
649 }
650
651 static void
652 xform_string_int(const GValue *sval, GValue *ival)
653 {
654         const gchar *str = g_value_get_string(sval);
655         gint val = g_strtod(str, NULL);
656         g_value_set_int(ival, val);
657 }
658
659 static void
660 xform_string_int64(const GValue *sval, GValue *ival)
661 {
662         const gchar *str = g_value_get_string(sval);
663         gint64 val = g_strtod(str, NULL);
664         g_value_set_int64(ival, val);
665 }
666
667 static void
668 xform_string_double(const GValue *sval, GValue *dval)
669 {
670         const gchar *str = g_value_get_string(sval);
671         double val = g_strtod(str, NULL);
672         g_value_set_double(dval, val);
673 }
674
675 static void
676 xform_boolean_double(const GValue *bval, GValue *dval)
677 {
678         gboolean b = g_value_get_boolean(bval);
679         double val = b;
680         g_value_set_double(dval, val);
681 }
682
683 void
684 ghb_register_transforms()
685 {
686         g_value_register_transform_func(G_TYPE_STRING, G_TYPE_INT64, 
687                                                                 xform_string_int64);
688         g_value_register_transform_func(G_TYPE_STRING, G_TYPE_INT, 
689                                                                 xform_string_int);
690         g_value_register_transform_func(G_TYPE_STRING, G_TYPE_DOUBLE, 
691                                                                 xform_string_double);
692         g_value_register_transform_func(G_TYPE_BOOLEAN, G_TYPE_DOUBLE, 
693                                                                 xform_boolean_double);
694 }