OSDN Git Service

LinGui: change the top level structure that contains presets from a dictionary
[handbrake-jp/handbrake-jp-git.git] / gtk / src / presets.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 #include <glib.h>
15 #include <glib-object.h>
16 #include <glib/gstdio.h>
17 #include <string.h>
18 #include <gtk/gtk.h>
19 #include "settings.h"
20 #include "audiohandler.h"
21 #include "hb-backend.h"
22 #include "plist.h"
23 #include "resources.h"
24 #include "presets.h"
25 #include "values.h"
26
27 static GValue *presetsPlist = NULL;
28 static GValue *internalPlist = NULL;
29 static GValue *prefsPlist = NULL;
30
31 static GValue*
32 plist_get_dict(GValue *presets, const gchar *name)
33 {
34         if (presets == NULL || name == NULL) return NULL;
35         return ghb_dict_lookup(presets, name);
36 }
37
38 static GValue*
39 presets_get_dict(GValue *presets, const gchar *name)
40 {
41         GValue *dict, *gval;
42         gint count, ii;
43         
44         if (presets == NULL || name == NULL) return NULL;
45         count = ghb_array_len(presets);
46         for (ii = 0; ii < count; ii++)
47         {
48                 const gchar *str;
49                 dict = ghb_array_get_nth(presets, ii);
50                 gval = ghb_dict_lookup(dict, "preset_name");
51                 str = g_value_get_string(gval);
52                 if (strcmp(str, name) == 0)
53                         return dict;
54         }
55         return NULL;
56 }
57
58 static gint
59 presets_remove(GValue *presets, const gchar *name)
60 {
61         GValue *dict, *gval;
62         gint count, ii;
63         
64         if (presets == NULL || name == NULL) return -1;
65         count = ghb_array_len(presets);
66         for (ii = 0; ii < count; ii++)
67         {
68                 const gchar *str;
69                 dict = ghb_array_get_nth(presets, ii);
70                 gval = ghb_dict_lookup(dict, "preset_name");
71                 str = g_value_get_string(gval);
72                 if (strcmp(str, name) == 0)
73                 {
74                         ghb_array_remove(presets, ii);
75                         return ii;
76                 }
77         }
78         return -1;
79 }
80
81 void
82 ghb_set_preset_default(GValue *settings)
83 {
84         gchar *preset;
85         
86         preset = ghb_settings_get_string (settings, "preset");
87         ghb_settings_set_string(settings, "default_preset", preset);
88         ghb_prefs_save(settings);
89         g_free(preset);
90 }
91
92 // Used for sorting dictionaries.
93 gint
94 key_cmp(gconstpointer a, gconstpointer b)
95 {
96         gchar *stra = (gchar*)a;
97         gchar *strb = (gchar*)b;
98
99         return strcmp(stra, strb);
100 }
101
102 gchar*
103 ghb_presets_get_description(const gchar *name)
104 {
105         GValue *pdict;
106         pdict = presets_get_dict(presetsPlist, name);
107         if (pdict == NULL) return g_strdup("");
108         return ghb_value_string(ghb_dict_lookup(pdict, "preset_description"));
109 }
110
111 static const GValue*
112 preset_dict_get_value(
113         GValue *dict,
114         const gchar *key)
115 {
116         const GValue *gval = NULL;
117
118         if (dict)
119         {
120                 gval = ghb_dict_lookup(dict, key);
121         }
122         if (internalPlist == NULL) return NULL;
123         if (gval == NULL)
124         {
125                 dict = plist_get_dict(internalPlist, "Presets");
126                 if (dict == NULL) return NULL;
127                 gval = ghb_dict_lookup(dict, key);
128         }
129         return gval;
130 }
131
132 static const GValue*
133 preset_get_value(
134         const gchar *name,
135         const gchar *key)
136 {
137         GValue *dict;
138
139         dict = presets_get_dict(presetsPlist, name);
140         return preset_dict_get_value(dict, key);
141 }
142
143 GList*
144 ghb_presets_get_names()
145 {
146         GList *names;
147         GList *standard = NULL;
148         GList *custom = NULL;
149         gint ii, count;
150
151         if (presetsPlist == NULL) return NULL;
152         count = ghb_array_len(presetsPlist);
153         for (ii = 0; ii < count; ii++)
154         {
155                 gchar *name;
156                 gint ptype;
157                 GValue *dict;
158                 GValue *gval;
159
160                 dict = ghb_array_get_nth(presetsPlist, ii);
161                 gval = ghb_dict_lookup(dict, "preset_name");
162                 name = (gchar*)g_value_get_string(gval);
163                 ptype = ghb_value_int(preset_dict_get_value(dict, "preset_type"));
164                 if (ptype)
165                 {
166                         custom = g_list_append(custom, name);
167                 }
168                 else
169                 {
170                         standard = g_list_append(standard, name);
171                 }
172         }
173         custom = g_list_sort(custom, key_cmp);
174         standard = g_list_sort(standard, key_cmp);
175         names = g_list_concat(standard, custom);
176         return names;
177 }
178
179 gint
180 ghb_preset_flags(const gchar *name)
181 {
182         GValue *dict;
183         const GValue *gval;
184         gint ptype;
185         gint ret = 0;
186
187         dict = presets_get_dict(presetsPlist, name);
188         gval = preset_dict_get_value(dict, "preset_type");
189         if (gval)
190         {
191                 ptype = ghb_value_int(gval);
192                 ret = (ptype != 0 ? PRESET_CUSTOM : 0);
193         }
194         return ret;
195 }
196
197 static void init_settings_from_dict(
198         GValue *dest, GValue *internal, GValue *dict);
199
200 static void
201 init_settings_from_array(
202         GValue *dest, 
203         GValue *internal,
204         GValue *array)
205 {
206         GValue *gval, *val;
207         gint count, ii;
208         
209         count = ghb_array_len(array);
210         // The first element of the internal version is always the 
211         // template for the allowed values
212         gval = ghb_array_get_nth(internal, 0);
213         for (ii = 0; ii < count; ii++)
214         {
215                 val = NULL;
216                 val = ghb_array_get_nth(array, ii);
217                 if (val == NULL)
218                         val = gval;
219                 if (G_VALUE_TYPE(gval) == ghb_dict_get_type())
220                 {
221                         GValue *new_dict;
222                         new_dict = ghb_dict_value_new();
223                         ghb_array_append(dest, new_dict);
224                         if (G_VALUE_TYPE(val) == ghb_dict_get_type())
225                                 init_settings_from_dict(new_dict, gval, val);
226                         else
227                                 init_settings_from_dict(new_dict, gval, gval);
228                 }
229                 else if (G_VALUE_TYPE(gval) == ghb_array_get_type())
230                 {
231                         GValue *new_array;
232                         new_array = ghb_array_value_new(8);
233                         ghb_array_append(dest, new_array);
234                         if (G_VALUE_TYPE(val) == ghb_array_get_type())
235                                 init_settings_from_array(new_array, gval, val);
236                         else
237                                 init_settings_from_array(new_array, gval, gval);
238                 }
239                 else
240                 {
241                         ghb_array_append(dest, val);
242                 }
243         }
244 }
245
246 static void
247 init_settings_from_dict(
248         GValue *dest, 
249         GValue *internal,
250         GValue *dict)
251 {
252         GHashTableIter iter;
253         gchar *key;
254         GValue *gval, *val;
255         
256         ghb_dict_iter_init(&iter, internal);
257         // middle (void*) cast prevents gcc warning "defreferencing type-punned
258         // pointer will break strict-aliasing rules"
259         while (g_hash_table_iter_next(
260                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
261         {
262                 val = NULL;
263                 if (dict)
264                         val = ghb_dict_lookup(dict, key);
265                 if (val == NULL)
266                         val = gval;
267                 if (G_VALUE_TYPE(gval) == ghb_dict_get_type())
268                 {
269                         GValue *new_dict;
270                         new_dict = ghb_dict_value_new();
271                         ghb_settings_take_value(dest, key, new_dict);
272                         if (G_VALUE_TYPE(val) == ghb_dict_get_type())
273                                 init_settings_from_dict(new_dict, gval, val);
274                         else
275                                 init_settings_from_dict(new_dict, gval, gval);
276                 }
277                 else if (G_VALUE_TYPE(gval) == ghb_array_get_type())
278                 {
279                         GValue *new_array;
280                         new_array = ghb_array_value_new(8);
281                         ghb_settings_take_value(dest, key, new_array);
282                         if (G_VALUE_TYPE(val) == ghb_array_get_type())
283                                 init_settings_from_array(new_array, gval, val);
284                         else
285                                 init_settings_from_array(new_array, gval, gval);
286         
287                 }
288                 else
289                 {
290                         ghb_settings_set_value(dest, key, val);
291                 }
292         }
293 }
294
295 void
296 init_ui_from_dict(
297         signal_user_data_t *ud, 
298         GValue *internal,
299         GValue *dict)
300 {
301         GHashTableIter iter;
302         gchar *key;
303         GValue *gval, *val;
304         
305         ghb_dict_iter_init(&iter, internal);
306         // middle (void*) cast prevents gcc warning "defreferencing type-punned
307         // pointer will break strict-aliasing rules"
308         while (g_hash_table_iter_next(
309                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
310         {
311                 val = NULL;
312                 if (dict)
313                         val = ghb_dict_lookup(dict, key);
314                 if (val == NULL)
315                         val = gval;
316                 ghb_ui_update(ud, key, val);
317         }
318 }
319
320 static void
321 preset_to_ui(signal_user_data_t *ud, GValue *dict)
322 {
323         g_debug("preset_to_ui()\n");
324         // Initialize the ui from presets file.
325         GValue *internal;
326
327         // Get key list from internal default presets.  This way we do not
328         // load any unknown keys.
329         if (internalPlist == NULL) return;
330         internal = plist_get_dict(internalPlist, "Presets");
331         // Setting a ui widget will cause the corresponding setting
332         // to be set, but it also triggers a callback that can 
333         // have the side effect of using other settings values
334         // that have not yet been set.  So set *all* settings first
335         // then update the ui.
336         init_settings_from_dict(ud->settings, internal, dict);
337         init_ui_from_dict(ud, internal, dict);
338
339         if (ghb_settings_get_boolean(ud->settings, "allow_tweaks"))
340         {
341                 const GValue *gval;
342                 gval = preset_dict_get_value(dict, "deinterlace");
343                 if (gval)
344                 {
345                         ghb_ui_update(ud, "tweak_deinterlace", gval);
346                 }
347                 gval = preset_dict_get_value(dict, "denoise");
348                 if (gval)
349                 {
350                         ghb_ui_update(ud, "tweak_denoise", gval);
351                 }
352         }
353 }
354
355 void
356 ghb_set_preset(signal_user_data_t *ud, const gchar *name)
357 {
358         GValue *dict;
359         
360         g_debug("ghb_set_preset() %s\n", name);
361         if (name == NULL)
362         {
363                 GList *presets;
364                 // Try to get the first preset
365                 presets = ghb_presets_get_names();
366                 if (presets)
367                 {
368                         name = (const gchar*)presets->data;
369                         g_list_free(presets);
370                 }
371         }
372         dict = presets_get_dict(presetsPlist, name);
373         if (dict == NULL || name == NULL)
374         {
375                 preset_to_ui(ud, NULL);
376         }
377         else
378         {
379                 preset_to_ui(ud, dict);
380                 ghb_settings_set_string(ud->settings, "preset", name);
381         }
382 }
383
384 void
385 ghb_update_from_preset(
386         signal_user_data_t *ud, 
387         const gchar *name, 
388         const gchar *key)
389 {
390         const GValue *gval;
391         
392         g_debug("ghb_update_from_preset() %s %s", name, key);
393         if (name == NULL) return;
394         gval = preset_get_value(name, key);
395         if (gval != NULL)
396         {
397                 ghb_ui_update(ud, key, gval);
398         }
399 }
400
401 gchar*
402 ghb_get_user_config_dir()
403 {
404         const gchar *dir;
405         gchar *config;
406
407         dir = g_get_user_config_dir();
408         if (!g_file_test(dir, G_FILE_TEST_IS_DIR))
409         {
410                 dir = g_get_home_dir();
411                 config = g_strdup_printf ("%s/.ghb", dir);
412                 if (!g_file_test(config, G_FILE_TEST_IS_DIR))
413                         g_mkdir (config, 0755);
414         }
415         else
416         {
417                 config = g_strdup_printf ("%s/ghb", dir);
418                 if (!g_file_test(config, G_FILE_TEST_IS_DIR))
419                         g_mkdir (config, 0755);
420         }
421         return config;
422 }
423
424 static void
425 store_plist(GValue *plist, const gchar *name)
426 {
427         gchar *config, *path;
428         FILE *file;
429
430         config = ghb_get_user_config_dir();
431         path = g_strdup_printf ("%s/%s", config, name);
432         file = g_fopen(path, "w");
433         g_free(config);
434         g_free(path);
435         ghb_plist_write(file, plist);
436         fclose(file);
437 }
438
439 static GValue*
440 load_plist(const gchar *name)
441 {
442         gchar *config, *path;
443         GValue *plist = NULL;
444
445         config = ghb_get_user_config_dir();
446         path = g_strdup_printf ("%s/%s", config, name);
447         if (g_file_test(path, G_FILE_TEST_IS_REGULAR))
448         {
449                 plist = ghb_plist_parse_file(path);
450         }
451         g_free(config);
452         g_free(path);
453         return plist;
454 }
455
456 static void
457 remove_plist(const gchar *name)
458 {
459         gchar *config, *path;
460
461         config = ghb_get_user_config_dir();
462         path = g_strdup_printf ("%s/%s", config, name);
463         if (g_file_test(path, G_FILE_TEST_IS_REGULAR))
464         {
465                 g_unlink(path);
466         }
467         g_free(path);
468         g_free(config);
469 }
470
471 static gboolean prefs_initializing = FALSE;
472
473 void
474 ghb_prefs_to_ui(signal_user_data_t *ud)
475 {
476         const GValue *gval;
477         gchar *key;
478         gchar *str;
479         GValue *internal, *dict;
480         GHashTableIter iter;
481         
482
483         prefs_initializing = TRUE;
484
485         // Setting a ui widget will cause the corresponding setting
486         // to be set, but it also triggers a callback that can 
487         // have the side effect of using other settings values
488         // that have not yet been set.  So set *all* settings first
489         // then update the ui.
490         internal = plist_get_dict(internalPlist, "Initialization");
491         ghb_dict_iter_init(&iter, internal);
492         // middle (void*) cast prevents gcc warning "defreferencing type-punned
493         // pointer will break strict-aliasing rules"
494         while (g_hash_table_iter_next(
495                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
496         {
497                 ghb_ui_update(ud, key, gval);
498         }
499
500         dict = plist_get_dict(prefsPlist, "Preferences");
501         internal = plist_get_dict(internalPlist, "Preferences");
502         ghb_dict_iter_init(&iter, internal);
503         // middle (void*) cast prevents gcc warning "defreferencing type-punned
504         // pointer will break strict-aliasing rules"
505         while (g_hash_table_iter_next(
506                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
507     {
508                 const GValue *value = NULL;
509                 if (dict)
510                         value = ghb_dict_lookup(dict, key);
511                 if (value == NULL)
512                         value = gval;
513                 ghb_settings_set_value(ud->settings, key, value);
514     }
515         internal = plist_get_dict(internalPlist, "Preferences");
516         ghb_dict_iter_init(&iter, internal);
517         // middle (void*) cast prevents gcc warning "defreferencing type-punned
518         // pointer will break strict-aliasing rules"
519         while (g_hash_table_iter_next(
520                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
521         {
522                 const GValue *value = NULL;
523                 if (dict)
524                         value = ghb_dict_lookup(dict, key);
525                 if (value == NULL)
526                         value = gval;
527                 ghb_ui_update(ud, key, value);
528         }
529         const GValue *val;
530         val = ghb_settings_get_value(ud->settings, "show_presets");
531         ghb_ui_update(ud, "show_presets", val);
532         if (ghb_settings_get_boolean(ud->settings, "hbfd_feature"))
533         {
534                 GtkAction *action;
535                 val = ghb_settings_get_value(ud->settings, "hbfd");
536                 ghb_ui_update(ud, "hbfd", val);
537                 action = GHB_ACTION (ud->builder, "hbfd");
538                 gtk_action_set_visible(action, TRUE);
539         }
540         else
541         {
542                 ghb_ui_update(ud, "hbfd", ghb_int64_value(0));
543         }
544         gval = ghb_settings_get_value(ud->settings, "default_source");
545         ghb_settings_set_value (ud->settings, "source", gval);
546         str = ghb_settings_get_string(ud->settings, "destination_dir");
547
548         gchar *path = g_strdup_printf ("%s/new_video.mp4", str);
549         ghb_ui_update(ud, "destination", ghb_string_value(path));
550         g_free(str);
551         g_free(path);
552
553         prefs_initializing = FALSE;
554 }
555
556 void
557 ghb_prefs_save(GValue *settings)
558 {
559         GValue *dict;
560         GValue *pref_dict;
561         GHashTableIter iter;
562         gchar *key;
563         const GValue *value;
564         
565         if (prefs_initializing) return;
566         dict = plist_get_dict(internalPlist, "Preferences");
567         if (dict == NULL) return;
568         pref_dict = plist_get_dict(prefsPlist, "Preferences");
569         if (pref_dict == NULL) return;
570         ghb_dict_iter_init(&iter, dict);
571         // middle (void*) cast prevents gcc warning "defreferencing type-punned
572         // pointer will break strict-aliasing rules"
573         while (g_hash_table_iter_next(
574                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
575     {
576             value = ghb_settings_get_value(settings, key);
577             if (value != NULL)
578             {
579                         ghb_dict_insert(pref_dict, g_strdup(key), ghb_value_dup(value));
580             }
581         }
582     store_plist(prefsPlist, "preferences");
583 }
584
585 void
586 ghb_pref_save(GValue *settings, const gchar *key)
587 {
588         const GValue *value;
589         
590         if (prefs_initializing) return;
591         value = ghb_settings_get_value(settings, key);
592         if (value != NULL)
593         {
594                 GValue *dict;
595                 dict = plist_get_dict(prefsPlist, "Preferences");
596                 if (dict == NULL) return;
597                 ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(value));
598                 store_plist(prefsPlist, "preferences");
599         }
600 }
601
602 void
603 ghb_settings_init(signal_user_data_t *ud)
604 {
605         GValue *internal;
606         GHashTableIter iter;
607         gchar *key;
608         GValue *gval;
609
610
611         g_debug("ghb_settings_init");
612         prefs_initializing = TRUE;
613
614         internalPlist = ghb_resource_get("internal-defaults");
615         // Setting a ui widget will cause the corresponding setting
616         // to be set, but it also triggers a callback that can 
617         // have the side effect of using other settings values
618         // that have not yet been set.  So set *all* settings first
619         // then update the ui.
620         internal = plist_get_dict(internalPlist, "Initialization");
621         ghb_dict_iter_init(&iter, internal);
622         // middle (void*) cast prevents gcc warning "defreferencing type-punned
623         // pointer will break strict-aliasing rules"
624         while (g_hash_table_iter_next(
625                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
626         {
627                 ghb_settings_set_value(ud->settings, key, gval);
628         }
629
630         internal = plist_get_dict(internalPlist, "Presets");
631         ghb_dict_iter_init(&iter, internal);
632         // middle (void*) cast prevents gcc warning "defreferencing type-punned
633         // pointer will break strict-aliasing rules"
634         while (g_hash_table_iter_next(
635                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
636         {
637                 ghb_settings_set_value(ud->settings, key, gval);
638         }
639
640         internal = plist_get_dict(internalPlist, "Preferences");
641         ghb_dict_iter_init(&iter, internal);
642         // middle (void*) cast prevents gcc warning "defreferencing type-punned
643         // pointer will break strict-aliasing rules"
644         while (g_hash_table_iter_next(
645                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
646         {
647                 ghb_settings_set_value(ud->settings, key, gval);
648         }
649         prefs_initializing = FALSE;
650 }
651
652 void
653 ghb_settings_close()
654 {
655         if (internalPlist)
656                 ghb_value_free(internalPlist);
657         if (presetsPlist)
658                 ghb_value_free(presetsPlist);
659         if (prefsPlist)
660                 ghb_value_free(prefsPlist);
661 }
662
663 void
664 ghb_prefs_load(signal_user_data_t *ud)
665 {
666         GValue *dict, *internal;
667         GHashTableIter iter;
668         gchar *key;
669         GValue *gval;
670         
671         g_debug("ghb_prefs_load");
672         prefsPlist = load_plist("preferences");
673         if (prefsPlist == NULL)
674                 prefsPlist = ghb_dict_value_new();
675         dict = plist_get_dict(prefsPlist, "Preferences");
676         internal = plist_get_dict(internalPlist, "Preferences");
677     if (dict == NULL && internal)
678     {
679                 dict = ghb_dict_value_new();
680                 ghb_dict_insert(prefsPlist, g_strdup("Preferences"), dict);
681
682         // Get defaults from internal defaults 
683                 ghb_dict_iter_init(&iter, internal);
684                 // middle (void*) cast prevents gcc warning "defreferencing type-punned
685                 // pointer will break strict-aliasing rules"
686                 while (g_hash_table_iter_next(
687                                 &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
688         {
689                         ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(gval));
690         }
691                 const gchar *dir = g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS);
692                 if (dir == NULL)
693                 {
694                         dir = ".";
695                 }
696                 ghb_dict_insert(dict, 
697                         g_strdup("destination_dir"), ghb_value_dup(ghb_string_value(dir)));
698                 store_plist(prefsPlist, "preferences");
699     }
700 }
701
702 void
703 ghb_presets_reload(signal_user_data_t *ud)
704 {
705         GValue *std_presets;
706         gint count, ii;
707
708         g_debug("ghb_presets_reload()\n");
709         std_presets = ghb_resource_get("standard-presets");
710         if (std_presets == NULL) return;
711
712         // Merge the keyfile contents into our presets
713         count = ghb_array_len(std_presets);
714         for (ii = 0; ii < count; ii++)
715         {
716                 const gchar *name;
717                 GValue *std_dict;
718                 GValue *copy_dict;
719                 GHashTableIter iter;
720                 gchar *key;
721                 GValue *value;
722                 gint pos;
723
724                 std_dict = ghb_array_get_nth(std_presets, ii);
725                 name = g_value_get_string(ghb_dict_lookup(std_dict, "preset_name"));
726                 pos = presets_remove(presetsPlist, name);
727
728                 copy_dict = ghb_dict_value_new();
729                 if (pos >= 0)
730                         ghb_array_insert(presetsPlist, pos, copy_dict);
731                 else
732                         ghb_array_append(presetsPlist, copy_dict);
733                 ghb_dict_iter_init(&iter, std_dict);
734                 // middle (void*) cast prevents gcc warning "defreferencing type-punned
735                 // pointer will break strict-aliasing rules"
736                 while (g_hash_table_iter_next(
737                                 &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
738                 {
739                         ghb_dict_insert(copy_dict, g_strdup(key), ghb_value_dup(value));
740                 }
741         }
742         store_plist(presetsPlist, "presets");
743 }
744
745 static void
746 presets_store()
747 {
748         g_debug("presets_store ()\n");
749         store_plist(presetsPlist, "presets");
750 }
751
752 void
753 ghb_save_queue(GValue *queue)
754 {
755         store_plist(queue, "queue");
756 }
757
758 GValue*
759 ghb_load_queue()
760 {
761         return load_plist("queue");
762 }
763
764 void
765 ghb_remove_queue_file()
766 {
767         remove_plist("queue");
768 }
769
770 void
771 ghb_presets_load()
772 {
773         presetsPlist = load_plist("presets");
774         if (presetsPlist == NULL)
775         {
776                 presetsPlist = ghb_value_dup(ghb_resource_get("standard-presets"));
777                 presets_store();
778         }
779         if (G_VALUE_TYPE(presetsPlist) == ghb_dict_get_type())
780         { // Presets is older dictionary format. Convert to array
781                 GHashTableIter old_iter;
782                 GValue *presets;
783                 gchar *name;
784                 GValue *orig_dict;
785
786                 presets = ghb_array_value_new(32);
787                 ghb_dict_iter_init(&old_iter, presetsPlist);
788                 // middle (void*) cast prevents gcc warning "defreferencing type-punned
789                 // pointer will break strict-aliasing rules"
790                 while (g_hash_table_iter_next(
791                         &old_iter, (gpointer*)(void*)&name, (gpointer*)(void*)&orig_dict))
792                 {
793                         GHashTableIter iter;
794                         gchar *key;
795                         GValue *value, *dict;
796
797                         dict = ghb_dict_value_new();
798                         ghb_dict_insert(dict, g_strdup("preset_name"), 
799                                 ghb_string_value_new(name));
800                         ghb_array_append(presets, dict);
801                         ghb_dict_iter_init(&iter, orig_dict);
802                         // middle (void*) cast prevents gcc warning "defreferencing 
803                         // type-punned pointer will break strict-aliasing rules"
804                         while (g_hash_table_iter_next(
805                                 &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
806                         {
807                                 ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(value));
808                         }
809                 }
810                 ghb_value_free(presetsPlist);
811                 presetsPlist = presets;
812                 presets_store();
813         }
814 }
815
816 void
817 ghb_settings_save(signal_user_data_t *ud, const gchar *name)
818 {
819         GValue *dict, *internal;
820         GHashTableIter iter;
821         gchar *key;
822         GValue *value;
823         gboolean autoscale;
824
825         if (internalPlist == NULL) return;
826         if (ghb_settings_get_boolean(ud->settings, "allow_tweaks"))
827         {
828                 gchar *str;
829                 str = ghb_settings_get_string(ud->settings, "tweak_deinterlace");
830                 if (str)
831                 {
832                         ghb_settings_set_string(ud->settings, "deinterlace", str);
833                         g_free(str);
834                 }
835                 str = ghb_settings_get_string(ud->settings, "tweak_denoise");
836                 if (str)
837                 {
838                         ghb_settings_set_string(ud->settings, "denoise", str);
839                         g_free(str);
840                 }
841         }
842         autoscale = ghb_settings_get_boolean(ud->settings, "autoscale");
843         ghb_settings_set_int64(ud->settings, "preset_type", 1);
844
845         dict = ghb_dict_value_new();
846         ghb_dict_insert(dict, g_strdup("preset_name"), ghb_string_value_new(name));
847         ghb_array_append(presetsPlist, dict);
848         internal = plist_get_dict(internalPlist, "Presets");
849
850         ghb_dict_iter_init(&iter, internal);
851         // middle (void*) cast prevents gcc warning "defreferencing type-punned
852         // pointer will break strict-aliasing rules"
853         while (g_hash_table_iter_next(
854                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
855         {
856                 const GValue *gval;
857                 gchar *key2;
858
859                 key2 = key;
860                 if (!autoscale)
861                 {
862                         if (strcmp(key, "max_width") == 0)
863                         {
864                                 key2 = "scale_width";
865                         }
866                         else if (strcmp(key, "max_height") == 0)
867                         {
868                                 key2 = "scale_height";
869                         }
870                 }
871                 gval = ghb_settings_get_value(ud->settings, key2);
872                 if (gval == NULL)
873                 {
874                         g_debug("Setting (%s) is not in defaults\n", (gchar*)key);
875                         continue;
876                 }
877                 if (ghb_value_cmp(gval, value) != 0)
878                 {
879                         // Differs from default value.  Store it.
880                         ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(gval));
881                 }
882         }
883         presets_store();
884         ud->dont_clear_presets = TRUE;
885         ghb_set_preset (ud, name);
886         ud->dont_clear_presets = FALSE;
887 }
888
889 void
890 ghb_presets_remove(const gchar *name)
891 {
892         if (presets_get_dict(presetsPlist, name))
893         {
894                 presets_remove(presetsPlist, name);
895                 presets_store();
896         }
897 }
898
899 void
900 ghb_presets_list_update(signal_user_data_t *ud)
901 {
902         GtkTreeView *treeview;
903         GtkTreeIter iter;
904         GtkListStore *store;
905         gboolean done;
906         GList *presets, *plink;
907         gchar *preset, *def_preset;
908         gchar *description;
909         gint flags, custom, def;
910         
911         g_debug("ghb_presets_list_update ()");
912         def_preset = ghb_settings_get_string(ud->settings, "default_preset");
913         plink = presets = ghb_presets_get_names();
914         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
915         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
916         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
917         {
918                 do
919                 {
920                         if (plink)
921                         {
922                                 // Update row with settings data
923                                 g_debug("Updating row");
924                                 preset = (gchar*)plink->data;
925                                 def = 0;
926                                 if (strcmp(preset, def_preset) == 0)
927                                         def = PRESET_DEFAULT;
928                                 
929                                 description = ghb_presets_get_description(preset);
930                                 flags = ghb_preset_flags(preset);
931                                 custom = flags & PRESET_CUSTOM;
932                                 gtk_list_store_set(store, &iter, 
933                                                         0, preset, 
934                                                         1, def ? 800 : 400, 
935                                                         2, def ? 2 : 0,
936                                                         3, custom ? "black" : "blue", 
937                                                         4, description,
938                                                         -1);
939                                 plink = plink->next;
940                                 g_free(description);
941                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
942                         }
943                         else
944                         {
945                                 // No more settings data, remove row
946                                 g_debug("Removing row");
947                                 done = !gtk_list_store_remove(store, &iter);
948                         }
949                 } while (!done);
950         }
951         while (plink)
952         {
953                 // Additional settings, add row
954                 g_debug("Adding rows");
955                 preset = (gchar*)plink->data;
956                 def = 0;
957                 if (strcmp(preset, def_preset) == 0)
958                         def = PRESET_DEFAULT;
959
960                 description = ghb_presets_get_description(preset);
961                 gtk_list_store_append(store, &iter);
962                 flags = ghb_preset_flags(preset);
963                 custom = flags & PRESET_CUSTOM;
964                 gtk_list_store_set(store, &iter, 0, preset, 
965                                                         1, def ? 800 : 400, 
966                                                         2, def ? 2 : 0,
967                                                         3, custom ? "black" : "blue", 
968                                                         4, description,
969                                                         -1);
970                 plink = plink->next;
971                 g_free(description);
972         }
973         g_free(def_preset);
974         g_list_free (presets);
975 }
976
977 void
978 ghb_select_preset(GtkBuilder *builder, const gchar *preset)
979 {
980         GtkTreeView *treeview;
981         GtkTreeSelection *selection;
982         GtkTreeModel *store;
983         GtkTreeIter iter;
984         gchar *tpreset;
985         gboolean done;
986         gboolean foundit = FALSE;
987         
988         g_debug("select_preset()");
989         if (preset == NULL) return;
990         treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
991         selection = gtk_tree_view_get_selection (treeview);
992         store = gtk_tree_view_get_model (treeview);
993         if (gtk_tree_model_get_iter_first(store, &iter))
994         {
995                 do
996                 {
997                         gtk_tree_model_get(store, &iter, 0, &tpreset, -1);
998                         if (strcmp(preset, tpreset) == 0)
999                         {
1000                                 gtk_tree_selection_select_iter (selection, &iter);
1001                                 foundit = TRUE;
1002                                 g_free(tpreset);
1003                                 break;
1004                         }
1005                         g_free(tpreset);
1006                         done = !gtk_tree_model_iter_next(store, &iter);
1007                 } while (!done);
1008         }
1009         if (!foundit)
1010         {
1011                 gtk_tree_model_get_iter_first(store, &iter);
1012                 gtk_tree_selection_select_iter (selection, &iter);
1013         }
1014 }
1015
1016 static void
1017 update_audio_presets(signal_user_data_t *ud)
1018 {
1019         g_debug("update_audio_presets");
1020         const GValue *audio_list;
1021
1022         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
1023         ghb_settings_set_value(ud->settings, "pref_audio_list", audio_list);
1024 }
1025
1026 void
1027 presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1028 {
1029         GtkWidget *dialog;
1030         GtkEntry *entry;
1031         GtkTextView *desc;
1032         GtkResponseType response;
1033         gchar *preset;
1034
1035         g_debug("presets_save_clicked_cb ()");
1036         preset = ghb_settings_get_string (ud->settings, "preset");
1037         // Clear the description
1038         desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "preset_description"));
1039         dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
1040         entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "preset_name"));
1041         gtk_entry_set_text(entry, preset);
1042         g_free(preset);
1043         response = gtk_dialog_run(GTK_DIALOG(dialog));
1044         gtk_widget_hide(dialog);
1045         if (response == GTK_RESPONSE_OK)
1046         {
1047                 // save the preset
1048                 const gchar *name = gtk_entry_get_text(entry);
1049                 g_debug("description to settings");
1050                 ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
1051                 // Construct the audio settings presets from the current audio list
1052                 update_audio_presets(ud);
1053                 ghb_settings_save(ud, name);
1054                 ghb_presets_list_update(ud);
1055                 // Make the new preset the selected item
1056                 ghb_select_preset(ud->builder, name);
1057         }
1058 }
1059
1060 void
1061 presets_restore_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1062 {
1063         g_debug("presets_restore_clicked_cb ()");
1064         // Reload only the standard presets
1065         ghb_presets_reload(ud);
1066         ghb_presets_list_update(ud);
1067         // Updating the presets list shuffles things around
1068         // need to make sure the proper preset is selected
1069         gchar *preset = ghb_settings_get_string (ud->settings, "preset");
1070         ghb_select_preset(ud->builder, preset);
1071         g_free(preset);
1072 }
1073
1074 void
1075 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1076 {
1077         GtkTreeView *treeview;
1078         GtkTreeSelection *selection;
1079         GtkTreeModel *store;
1080         GtkTreeIter iter;
1081         gchar *preset;
1082         GtkResponseType response;
1083
1084         g_debug("presets_remove_clicked_cb ()");
1085         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1086         selection = gtk_tree_view_get_selection (treeview);
1087         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1088         {
1089                 GtkWidget *dialog;
1090
1091                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1092                 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1093                                                                 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1094                                                                 "Confirm deletion of preset %s.", preset);
1095                 response = gtk_dialog_run(GTK_DIALOG(dialog));
1096                 gtk_widget_destroy (dialog);
1097                 if (response == GTK_RESPONSE_YES)
1098                 {
1099                         GtkTreeIter nextIter = iter;
1100                         gchar *nextPreset = NULL;
1101                         if (!gtk_tree_model_iter_next(store, &nextIter))
1102                         {
1103                                 if (gtk_tree_model_get_iter_first(store, &nextIter))
1104                                 {
1105                                         gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1106                                 }
1107                         }
1108                         else
1109                         {
1110                                 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1111                         }
1112                         // Remove the selected item
1113                         // First unselect it so that selecting the new item works properly
1114                         gtk_tree_selection_unselect_iter (selection, &iter);
1115                         ghb_presets_remove(preset);
1116                         ghb_presets_list_update(ud);
1117                         ghb_select_preset(ud->builder, nextPreset);
1118                 }
1119         }
1120 }
1121
1122 static void
1123 preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
1124 {
1125         GtkWidget *widget;
1126
1127         ghb_ui_update(ud, "scale_width", 
1128                         ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3]));
1129         // If anamorphic or keep_aspect, the hight will be automatically calculated
1130         gboolean keep_aspect, anamorphic;
1131         keep_aspect = ghb_settings_get_boolean(ud->settings, "keep_aspect");
1132         anamorphic = ghb_settings_get_boolean(ud->settings, "anamorphic");
1133         if (!(keep_aspect || anamorphic))
1134         {
1135                 ghb_ui_update(ud, "scale_height", 
1136                         ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1]));
1137         }
1138
1139         // Set the limits of cropping.  hb_set_anamorphic_size crashes if
1140         // you pass it a cropped width or height == 0.
1141         gint bound;
1142         bound = tinfo->height / 2 - 2;
1143         widget = GHB_WIDGET (ud->builder, "crop_top");
1144         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1145         widget = GHB_WIDGET (ud->builder, "crop_bottom");
1146         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1147         bound = tinfo->width / 2 - 2;
1148         widget = GHB_WIDGET (ud->builder, "crop_left");
1149         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1150         widget = GHB_WIDGET (ud->builder, "crop_right");
1151         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1152         if (ghb_settings_get_boolean(ud->settings, "autocrop"))
1153         {
1154                 ghb_ui_update(ud, "crop_top", ghb_int64_value(tinfo->crop[0]));
1155                 ghb_ui_update(ud, "crop_bottom", ghb_int64_value(tinfo->crop[1]));
1156                 ghb_ui_update(ud, "crop_left", ghb_int64_value(tinfo->crop[2]));
1157                 ghb_ui_update(ud, "crop_right", ghb_int64_value(tinfo->crop[3]));
1158         }
1159 }
1160
1161 void
1162 presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
1163 {
1164         GtkTreeModel *store;
1165         GtkTreeIter iter;
1166         gchar *preset;
1167         ghb_title_info_t tinfo;
1168         GtkWidget *widget;
1169         
1170         g_debug("presets_list_selection_changed_cb ()");
1171         widget = GHB_WIDGET (ud->builder, "presets_remove");
1172         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1173         {
1174                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1175                 ud->dont_clear_presets = TRUE;
1176                 // Temporarily set the video_quality range to (0,100)
1177                 // This is needed so the video_quality value does not get
1178                 // truncated when set.  The range will be readjusted below
1179                 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1180                 gtk_range_set_range (GTK_RANGE(qp), 0, 100);
1181                 // Clear the audio list prior to changing the preset.  Existing audio
1182                 // can cause the container extension to be automatically changed when
1183                 // it shouldn't be
1184                 ghb_clear_audio_list(ud);
1185                 ghb_set_preset(ud, preset);
1186                 gint titleindex;
1187                 titleindex = ghb_settings_combo_int(ud->settings, "title");
1188                 ghb_set_pref_audio(titleindex, ud);
1189                 ghb_settings_set_boolean(ud->settings, "preset_modified", FALSE);
1190                 ud->dont_clear_presets = FALSE;
1191                 if (ghb_get_title_info (&tinfo, titleindex))
1192                 {
1193                         preset_update_title_deps(ud, &tinfo);
1194                 }
1195                 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1196
1197                 gint vqmin, vqmax;
1198                 ghb_vquality_range(ud, &vqmin, &vqmax);
1199                 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1200                 gtk_widget_set_sensitive(widget, TRUE);
1201         }
1202         else
1203         {
1204                 g_debug("No selection???  Perhaps unselected.");
1205                 gtk_widget_set_sensitive(widget, FALSE);
1206         }
1207 }
1208
1209 void
1210 ghb_clear_presets_selection(signal_user_data_t *ud)
1211 {
1212         GtkTreeView *treeview;
1213         GtkTreeSelection *selection;
1214         
1215         if (ud->dont_clear_presets) return;
1216         g_debug("ghb_clear_presets_selection()");
1217         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1218         selection = gtk_tree_view_get_selection (treeview);
1219         gtk_tree_selection_unselect_all (selection);
1220         ghb_settings_set_boolean(ud->settings, "preset_modified", TRUE);
1221 }
1222
1223 void
1224 presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
1225 {
1226         GtkTreeView *treeview;
1227         GtkTreeSelection *selection;
1228         GtkTreeModel *store;
1229         GtkTreeIter iter;
1230         
1231         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1232         selection = gtk_tree_view_get_selection(treeview);
1233         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1234         {
1235                 GtkTreePath *path;
1236                 path = gtk_tree_model_get_path (store, &iter);
1237                 // Make the parent visible in scroll window if it is not.
1238                 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
1239                 gtk_tree_path_free(path);
1240         }
1241 }
1242
1243 void
1244 presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1245 {
1246         ghb_set_preset_default(ud->settings);
1247         ghb_presets_list_update(ud);
1248 }
1249