OSDN Git Service

LinGui: make the destination file entry box wider.
[handbrake-jp/handbrake-jp-git.git] / gtk / src / queuehandler.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * callbacks.c
4  * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
5  * 
6  * callbacks.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 <gtk/gtk.h>
15 #include <gdk/gdkkeysyms.h>
16 #include <glib/gstdio.h>
17 #include <gio/gio.h>
18 #include "hb.h"
19 #include "settings.h"
20 #include "hb-backend.h"
21 #include "values.h"
22 #include "callbacks.h"
23 #include "presets.h"
24 #include "ghb-dvd.h"
25
26 void
27 queue_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
28 {
29         GtkTreeModel *store;
30         GtkTreeIter iter, piter;
31         
32         g_debug("queue_list_selection_changed_cb ()");
33         // A queue entry is made up of a parent and multiple
34         // children that are visible when expanded.  When and entry
35         // is selected, I want the parent to be selected.
36         // This is purely cosmetic.
37         if (gtk_tree_selection_get_selected(selection, &store, &iter))
38         {
39                 GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_edit");
40                 gtk_widget_set_sensitive (widget, TRUE);
41                 if (gtk_tree_model_iter_parent (store, &piter, &iter))
42                 {
43                         GtkTreePath *path;
44                         GtkTreeView *treeview;
45                         
46                         gtk_tree_selection_select_iter (selection, &piter);
47                         path = gtk_tree_model_get_path (store, &piter);
48                         treeview = gtk_tree_selection_get_tree_view (selection);
49                         // Make the parent visible in scroll window if it is not.
50                         gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
51                         gtk_tree_path_free(path);
52                 }
53         }
54         else
55         {
56                 GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_edit");
57                 gtk_widget_set_sensitive (widget, FALSE);
58         }
59 }
60
61 static void
62 add_to_queue_list(signal_user_data_t *ud, GValue *settings, GtkTreeIter *piter)
63 {
64         GtkTreeView *treeview;
65         GtkTreeIter iter;
66         GtkTreeStore *store;
67         gchar *info;
68         gint status;
69         GtkTreeIter citer;
70         gchar *dest, *preset, *vol_name, *basename;
71         const gchar *vcodec, *container;
72         gchar *fps, *vcodec_abbr;
73         gint title, start_chapter, end_chapter, width, height;
74         gint source_width, source_height;
75         gboolean pass2, anamorphic, round_dim, keep_aspect, vqtype, turbo;
76         gboolean tweaks;
77         
78         g_debug("update_queue_list ()");
79         if (settings == NULL) return;
80         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
81         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
82                 
83         tweaks = ghb_settings_get_boolean(settings, "allow_tweaks");
84         title = ghb_settings_combo_int(settings, "title");
85         start_chapter = ghb_settings_get_int(settings, "start_chapter");
86         end_chapter = ghb_settings_get_int(settings, "end_chapter");
87         pass2 = ghb_settings_get_boolean(settings, "VideoTwoPass");
88         vol_name = ghb_settings_get_string(settings, "volume_label");
89         dest = ghb_settings_get_string(settings, "destination");
90         basename = g_path_get_basename(dest);
91         info = g_strdup_printf 
92         (
93                 "<big><b>%s</b></big> "
94                 "<small>(Title %d, Chapters %d through %d, %d Video %s)"
95                 " --> %s</small>",
96                  vol_name, title+1, start_chapter, end_chapter, 
97                  pass2 ? 2:1, pass2 ? "Passes":"Pass", basename
98         );
99
100         if (piter)
101                 iter = *piter;
102         else
103                 gtk_tree_store_append(store, &iter, NULL);
104
105         gtk_tree_store_set(store, &iter, 1, info, 2, "hb-queue-delete", -1);
106         g_free(info);
107         status = ghb_settings_get_int(settings, "job_status");
108         switch (status)
109         {
110                 case GHB_QUEUE_PENDING:
111                         gtk_tree_store_set(store, &iter, 0, "hb-queue-job", -1);
112                         break;
113                 case GHB_QUEUE_CANCELED:
114                         gtk_tree_store_set(store, &iter, 0, "hb-canceled", -1);
115                         break;
116                 case GHB_QUEUE_RUNNING:
117                         gtk_tree_store_set(store, &iter, 0, "hb-working0", -1);
118                         break;
119                 case GHB_QUEUE_DONE:
120                         gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
121                         break;
122                 default:
123                         gtk_tree_store_set(store, &iter, 0, "hb-queue-job", -1);
124                         break;
125         }
126
127         GString *str = g_string_new("");
128         gboolean markers;
129         gboolean preset_modified;
130         gint mux;
131         const GValue *path;
132
133         container = ghb_settings_combo_option(settings, "FileFormat");
134         mux = ghb_settings_combo_int(settings, "FileFormat");
135         preset_modified = ghb_settings_get_boolean(settings, "preset_modified");
136         path = ghb_settings_get_value(settings, "preset");
137         preset = ghb_preset_path_string(path);
138         markers = ghb_settings_get_boolean(settings, "ChapterMarkers");
139
140         if (preset_modified)
141                 g_string_append_printf(str, 
142                         "<b>Modified Preset Based On:</b> <small>%s</small>\n", 
143                         preset);
144         else
145                 g_string_append_printf(str, 
146                         "<b>Preset:</b> <small>%s</small>\n", 
147                         preset);
148
149         if (markers)
150         {
151                 g_string_append_printf(str, 
152                         "<b>Format:</b> <small>%s Container, Chapter Markers</small>\n", 
153                         container);
154         }
155         else
156         {
157                 g_string_append_printf(str, 
158                         "<b>Format:</b> <small>%s Container</small>\n", container);
159         }
160         if (mux == HB_MUX_MP4)
161         {
162                 gboolean ipod, http, large;
163
164                 ipod = ghb_settings_get_boolean(settings, "Mp4iPodCompatible");
165                 http = ghb_settings_get_boolean(settings, "Mp4HttpOptimize");
166                 large = ghb_settings_get_boolean(settings, "Mp4LargeFile");
167                 if (http || ipod || large)
168                 {
169                         g_string_append_printf(str, "<b>MP4 Options:</b><small>");
170                         if (ipod)
171                                 g_string_append_printf(str, " - iPod 5G Support");
172                         if (http)
173                                 g_string_append_printf(str, " - Web Optimized");
174                         if (large)
175                                 g_string_append_printf(str, " - Large File Size (>4GB)");
176                         g_string_append_printf(str, "</small>\n");
177                 }
178         }
179         g_string_append_printf(str, 
180                 "<b>Destination:</b> <small>%s</small>\n", dest);
181
182         width = ghb_settings_get_int(settings, "scale_width");
183         height = ghb_settings_get_int(settings, "scale_height");
184         anamorphic = ghb_settings_get_boolean(settings, "anamorphic");
185         round_dim = ghb_settings_get_boolean(settings, "ModDimensions");
186         keep_aspect = ghb_settings_get_boolean(settings, "PictureKeepRatio");
187
188         gchar *aspect_desc;
189         if (anamorphic)
190         {
191                 if (round_dim)
192                 {
193                         aspect_desc = "(Anamorphic)";
194                 }
195                 else
196                 {
197                         aspect_desc = "(Strict Anamorphic)";
198                 }
199         }
200         else
201         {
202                 if (keep_aspect)
203                 {
204                         aspect_desc = "(Aspect Preserved)";
205                 }
206                 else
207                 {
208                         aspect_desc = "(Aspect Lost)";
209                 }
210         }
211         vqtype = ghb_settings_get_boolean(settings, "vquality_type_constant");
212
213         gchar *vq_desc = "Error";
214         gchar *vq_units = "";
215         gchar *vqstr;
216         gdouble vqvalue;
217         if (!vqtype)
218         {
219                 vqtype = ghb_settings_get_boolean(settings, "vquality_type_target");
220                 if (!vqtype)
221                 {
222                         // Has to be bitrate
223                         vqvalue = ghb_settings_get_int(settings, "VideoAvgBitrate");
224                         vq_desc = "Bitrate:";
225                         vq_units = "kbps";
226                 }
227                 else
228                 {
229                         // Target file size
230                         vqvalue = ghb_settings_get_int(settings, "VideoTargetSize");
231                         vq_desc = "Target Size:";
232                         vq_units = "MB";
233                 }
234                 vqstr = g_strdup_printf("%d", (gint)vqvalue);
235         }
236         else
237         {
238                 // Constant quality
239                 vqvalue = ghb_settings_get_double(settings, "VideoQualitySlider");
240                 vq_desc = "Constant Quality:";
241                 if (ghb_settings_get_boolean(settings, "directqp"))
242                 {
243                         vqstr = g_strdup_printf("%d", (gint)vqvalue);
244                         vq_units = "(crf)";
245                 }
246                 else
247                 {
248                         vqstr = g_strdup_printf("%.1f", 100*vqvalue);
249                         vq_units = "%";
250                 }
251         }
252         fps = ghb_settings_get_string(settings, "VideoFramerate");
253         if (strcmp("source", fps) == 0)
254         {
255                 g_free(fps);
256                 if (ghb_settings_get_boolean(settings, "PictureDetelecine"))
257                         fps = g_strdup("Same As Source (vfr detelecine)");
258                 else
259                         fps = g_strdup("Same As Source (variable)");
260         }
261         else
262         {
263                 gchar *tmp;
264                 tmp = g_strdup_printf("%s (constant frame rate)", fps);
265                 g_free(fps);
266                 fps = tmp;
267         }
268         vcodec = ghb_settings_combo_option(settings, "VideoEncoder");
269         vcodec_abbr = ghb_settings_get_string(settings, "VideoEncoder");
270         source_width = ghb_settings_get_int(settings, "source_width");
271         source_height = ghb_settings_get_int(settings, "source_height");
272         g_string_append_printf(str,
273                 "<b>Picture:</b> Source: <small>%d x %d, Output %d x %d %s</small>\n",
274                  source_width, source_height, width, height, aspect_desc);
275
276         gboolean decomb;
277         gboolean filters = FALSE;
278
279         decomb = ghb_settings_get_boolean(settings, "PictureDecomb");
280         g_string_append_printf(str, "<b>Filters:</b><small>");
281         if (ghb_settings_get_boolean(settings, "PictureDetelecine"))
282         {
283                 g_string_append_printf(str, " - Detelecine");
284                 filters = TRUE;
285         }
286         if (decomb)
287         {
288                 g_string_append_printf(str, " - Decomb");
289                 filters = TRUE;
290         }
291         else
292         {
293                 gint deint = ghb_settings_combo_int(settings, 
294                                         tweaks ? "tweak_PictureDeinterlace":"PictureDeinterlace");
295                 if (deint)
296                 {
297                         const gchar *opt = ghb_settings_combo_option(settings,
298                                         tweaks ? "tweak_PictureDeinterlace":"PictureDeinterlace");
299                         g_string_append_printf(str, " - Deinterlace: %s", opt);
300                         filters = TRUE;
301                 }
302         }
303         gint denoise = ghb_settings_combo_int(settings, 
304                                 tweaks ? "tweak_PictureDenoise":"PictureDenoise");
305         if (denoise)
306         {
307                 const gchar *opt = ghb_settings_combo_option(settings,
308                                 tweaks ? "tweak_PictureDenoise":"PictureDenoise");
309                 g_string_append_printf(str, " - Denoise: %s", opt);
310                 filters = TRUE;
311         }
312         gint deblock = ghb_settings_get_int(settings, "PictureDeblock");
313         if (deblock >= 5)
314         {
315                 g_string_append_printf(str, " - Deblock (%d)", deblock);
316                 filters = TRUE;
317         }
318         if (ghb_settings_get_boolean(settings, "VideoGrayScale"))
319         {
320                 g_string_append_printf(str, " - Grayscale");
321                 filters = TRUE;
322         }
323         if (!filters)
324                 g_string_append_printf(str, " None");
325         g_string_append_printf(str, "</small>\n");
326
327         g_string_append_printf(str,
328                 "<b>Video:</b> <small>%s, Framerate: %s, %s %s%s</small>\n",
329                  vcodec, fps, vq_desc, vqstr, vq_units);
330
331         turbo = ghb_settings_get_boolean(settings, "VideoTurboTwoPass");
332         if (turbo)
333         {
334                 g_string_append_printf(str, "<b>Turbo:</b> <small>On</small>\n");
335         }
336         if (strcmp(vcodec_abbr, "x264") == 0)
337         {
338                 gchar *x264opts = ghb_build_x264opts_string(settings);
339                 g_string_append_printf(str, 
340                         "<b>x264 Options:</b> <small>%s</small>\n", x264opts);
341                 g_free(x264opts);
342         }
343         // Add the audios
344         gint count, ii;
345         const GValue *audio_list;
346
347         audio_list = ghb_settings_get_value(settings, "audio_list");
348         count = ghb_array_len(audio_list);
349         for (ii = 0; ii < count; ii++)
350         {
351                 gchar *bitrate, *samplerate, *track;
352                 const gchar *acodec, *mix;
353                 GValue *asettings;
354
355                 asettings = ghb_array_get_nth(audio_list, ii);
356
357                 acodec = ghb_settings_combo_option(asettings, "AudioEncoder");
358                 bitrate = ghb_settings_get_string(asettings, "AudioBitrate");
359                 samplerate = ghb_settings_get_string(asettings, "AudioSamplerate");
360                 if (strcmp("source", samplerate) == 0)
361                 {
362                         g_free(samplerate);
363                         samplerate = g_strdup("Same As Source");
364                 }
365                 track = ghb_settings_get_string(asettings, "AudioTrackDescription");
366                 mix = ghb_settings_combo_option(asettings, "AudioMixdown");
367                 g_string_append_printf(str,
368                         "<b>Audio:</b><small> %s, Encoder: %s, Mixdown: %s, SampleRate: %s, Bitrate: %s</small>",
369                          track, acodec, mix, samplerate, bitrate);
370                 if (ii < count-1)
371                         g_string_append_printf(str, "\n");
372                 g_free(track);
373                 g_free(bitrate);
374                 g_free(samplerate);
375         }
376         info = g_string_free(str, FALSE);
377         gtk_tree_store_append(store, &citer, &iter);
378         gtk_tree_store_set(store, &citer, 1, info, -1);
379         g_free(info);
380         g_free(fps);
381         g_free(vcodec_abbr);
382         g_free(vol_name);
383         g_free(dest);
384         g_free(preset);
385 }
386
387 void
388 audio_list_refresh(signal_user_data_t *ud)
389 {
390         GtkTreeView *treeview;
391         GtkTreeIter iter;
392         GtkListStore *store;
393         gboolean done;
394         gint row = 0;
395         const GValue *audio_list;
396
397         g_debug("ghb_audio_list_refresh ()");
398         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_list"));
399         store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
400         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
401         {
402                 do
403                 {
404                         const gchar *track, *codec, *br, *sr, *mix;
405                         gchar *drc, *s_track, *s_codec, *s_br, *s_sr, *s_mix;
406                         gdouble s_drc;
407                         GValue *asettings;
408
409                         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
410                         if (row >= ghb_array_len(audio_list))
411                                 return;
412                         asettings = ghb_array_get_nth(audio_list, row);
413
414                         track = ghb_settings_combo_option(asettings, "AudioTrack");
415                         codec = ghb_settings_combo_option(asettings, "AudioEncoder");
416                         br = ghb_settings_combo_option(asettings, "AudioBitrate");
417                         sr = ghb_settings_combo_option(asettings, "AudioSamplerate");
418                         mix = ghb_settings_combo_option(asettings, "AudioMixdown");
419                         drc = ghb_settings_get_string(asettings, "AudioTrackDRCSlider");
420
421                         s_track = ghb_settings_get_string(asettings, "AudioTrack");
422                         s_codec = ghb_settings_get_string(asettings, "AudioEncoder");
423                         s_br = ghb_settings_get_string(asettings, "AudioBitrate");
424                         s_sr = ghb_settings_get_string(asettings, "AudioSamplerate");
425                         s_mix = ghb_settings_get_string(asettings, "AudioMixdown");
426                         s_drc = ghb_settings_get_double(asettings, "AudioTrackDRCSlider");
427
428                         gtk_list_store_set(GTK_LIST_STORE(store), &iter, 
429                                 // These are displayed in list
430                                 0, track,
431                                 1, codec,
432                                 2, br,
433                                 3, sr,
434                                 4, mix,
435                                 // These are used to set combo values when an item is selected
436                                 5, drc,
437                                 6, s_track,
438                                 7, s_codec,
439                                 8, s_br,
440                                 9, s_sr,
441                                 10, s_mix,
442                                 11, s_drc,
443                                 -1);
444                         g_free(drc);
445                         g_free(s_track);
446                         g_free(s_codec);
447                         g_free(s_br);
448                         g_free(s_sr);
449                         g_free(s_mix);
450                         done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
451                         row++;
452                 } while (!done);
453         }
454 }
455
456 static gboolean
457 validate_settings(signal_user_data_t *ud)
458 {
459         // Check to see if the dest file exists or is
460         // already in the queue
461         gchar *message, *dest;
462         gint count, ii;
463         gint titleindex;
464
465         titleindex = ghb_settings_combo_int(ud->settings, "title");
466         if (titleindex < 0) return FALSE;
467         dest = ghb_settings_get_string(ud->settings, "destination");
468         count = ghb_array_len(ud->queue);
469         for (ii = 0; ii < count; ii++)
470         {
471                 GValue *js;
472                 gchar *filename;
473
474                 js = ghb_array_get_nth(ud->queue, ii);
475                 filename = ghb_settings_get_string(js, "destination");
476                 if (strcmp(dest, filename) == 0)
477                 {
478                         message = g_strdup_printf(
479                                                 "Destination: %s\n\n"
480                                                 "Another queued job has specified the same destination.\n"
481                                                 "Do you want to overwrite?",
482                                                 dest);
483                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
484                         {
485                                 g_free(filename);
486                                 g_free(dest);
487                                 g_free(message);
488                                 return FALSE;
489                         }
490                         g_free(message);
491                         break;
492                 }
493                 g_free(filename);
494         }
495         gchar *destdir = g_path_get_dirname(dest);
496         if (!g_file_test(destdir, G_FILE_TEST_IS_DIR))
497         {
498                 message = g_strdup_printf(
499                                         "Destination: %s\n\n"
500                                         "This is not a valid directory.",
501                                         destdir);
502                 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
503                 g_free(dest);
504                 g_free(message);
505                 g_free(destdir);
506                 return FALSE;
507         }
508         if (g_access(destdir, R_OK|W_OK) != 0)
509         {
510                 message = g_strdup_printf(
511                                         "Destination: %s\n\n"
512                                         "Can not read or write the directory.",
513                                         destdir);
514                 ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
515                 g_free(dest);
516                 g_free(message);
517                 g_free(destdir);
518                 return FALSE;
519         }
520         GFile *gfile;
521         GFileInfo *info;
522         guint64 size;
523         gchar *resolved = ghb_resolve_symlink(destdir);
524
525         gfile = g_file_new_for_path(resolved);
526         info = g_file_query_filesystem_info(gfile, 
527                                                 G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, NULL);
528         if (info != NULL)
529         {
530                 if (g_file_info_has_attribute(info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE))
531                 {
532                         size = g_file_info_get_attribute_uint64(info, 
533                                                                         G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
534                         
535                         gint64 fsize = (guint64)10 * 1024 * 1024 * 1024;
536                         if (size < fsize)
537                         {
538                                 message = g_strdup_printf(
539                                                         "Destination filesystem is almost full: %uM free\n\n"
540                                                         "Encode may be incomplete if you proceed.\n",
541                                                         (guint)(size / (1024L*1024L)));
542                                 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Proceed"))
543                                 {
544                                         g_free(dest);
545                                         g_free(message);
546                                         return FALSE;
547                                 }
548                                 g_free(message);
549                         }
550                 }
551                 g_object_unref(info);
552         }
553         g_object_unref(gfile);
554         g_free(resolved);
555         g_free(destdir);
556         if (g_file_test(dest, G_FILE_TEST_EXISTS))
557         {
558                 message = g_strdup_printf(
559                                         "Destination: %s\n\n"
560                                         "File already exhists.\n"
561                                         "Do you want to overwrite?",
562                                         dest);
563                 if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite"))
564                 {
565                         g_free(dest);
566                         g_free(message);
567                         return FALSE;
568                 }
569                 g_free(message);
570                 g_unlink(dest);
571         }
572         g_free(dest);
573         // Validate video quality is in a reasonable range
574         if (!ghb_validate_vquality(ud->settings))
575         {
576                 return FALSE;
577         }
578         // Validate audio settings
579         if (!ghb_validate_audio(ud))
580         {
581                 return FALSE;
582         }
583         // Validate video settings
584         if (!ghb_validate_video(ud))
585         {
586                 return FALSE;
587         }
588         // Validate filter settings
589         if (!ghb_validate_filters(ud))
590         {
591                 return FALSE;
592         }
593         audio_list_refresh(ud);
594         return TRUE;
595 }
596
597 static gboolean
598 queue_add(signal_user_data_t *ud)
599 {
600         // Add settings to the queue
601         GValue *settings;
602         gint titleindex;
603         gint titlenum;
604         
605         g_debug("queue_add ()");
606         if (!validate_settings(ud))
607         {
608                 return FALSE;
609         }
610         if (ud->queue == NULL)
611                 ud->queue = ghb_array_value_new(32);
612         // Make a copy of current settings to be used for the new job
613         settings = ghb_value_dup(ud->settings);
614         ghb_settings_set_int(settings, "job_status", GHB_QUEUE_PENDING);
615         ghb_settings_set_int(settings, "job_unique_id", 0);
616         titleindex = ghb_settings_combo_int(settings, "title");
617         titlenum = ghb_get_title_number(titleindex);
618         ghb_settings_set_int(settings, "titlenum", titlenum);
619         ghb_array_append(ud->queue, settings);
620         add_to_queue_list(ud, settings, NULL);
621         ghb_save_queue(ud->queue);
622
623         return TRUE;
624 }
625
626 void
627 queue_add_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
628 {
629         g_debug("queue_add_clicked_cb ()");
630         queue_add(ud);
631 }
632
633 void
634 queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
635 {
636         GtkTreeView *treeview;
637         GtkTreePath *treepath;
638         GtkTreeModel *store;
639         GtkTreeIter iter;
640         gint row;
641         gint *indices;
642         gint unique_id;
643         GValue *settings;
644         gint status;
645
646         g_debug("queue_remove_clicked_cb ()");
647         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
648         store = gtk_tree_view_get_model(treeview);
649         treepath = gtk_tree_path_new_from_string (path);
650         if (gtk_tree_path_get_depth(treepath) > 1) return;
651         if (gtk_tree_model_get_iter(store, &iter, treepath))
652         {
653                 // Find the entry in the queue
654                 indices = gtk_tree_path_get_indices (treepath);
655                 row = indices[0];
656                 // Can only free the treepath After getting what I need from
657                 // indices since this points into treepath somewhere.
658                 gtk_tree_path_free (treepath);
659                 if (row < 0) return;
660                 if (row >= ghb_array_len(ud->queue))
661                         return;
662                 settings = ghb_array_get_nth(ud->queue, row);
663                 status = ghb_settings_get_int(settings, "job_status");
664                 if (status == GHB_QUEUE_RUNNING)
665                 {
666                         // Ask if wants to stop encode.
667                         if (!ghb_cancel_encode(NULL))
668                         {
669                                 return;
670                         }
671                         unique_id = ghb_settings_get_int(settings, "job_unique_id");
672                         ghb_remove_job(unique_id);
673                 }
674                 // Remove the selected item
675                 gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
676                 // Remove the corresponding item from the queue list
677                 GValue *old = ghb_array_get_nth(ud->queue, row);
678                 ghb_value_free(old);
679                 ghb_array_remove(ud->queue, row);
680                 ghb_save_queue(ud->queue);
681         }
682         else
683         {       
684                 gtk_tree_path_free (treepath);
685         }
686 }
687
688 static gint
689 find_last_finished(GValue *queue)
690 {
691         GValue *js;
692         gint ii, count;
693         gint status;
694         
695         g_debug("find_last_finished");
696         count = ghb_array_len(queue);
697         for (ii = 0; ii < count; ii++)
698         {
699                 js = ghb_array_get_nth(queue, ii);
700                 status = ghb_settings_get_int(js, "job_status");
701                 if (status != GHB_QUEUE_DONE && status != GHB_QUEUE_RUNNING)
702                 {
703                         return ii-1;
704                 }
705         }
706         return -1;
707 }
708
709 // This little bit is needed to prevent the default drag motion
710 // handler from expanding rows if you hover over them while
711 // dragging.
712 // Also controls where valid drop locations are
713 gboolean
714 queue_drag_motion_cb(
715         GtkTreeView *tv,
716         GdkDragContext *ctx,
717         gint x,
718         gint y,
719         guint time,
720         signal_user_data_t *ud)
721 {
722         GtkTreePath *path = NULL;
723         GtkTreeViewDropPosition pos;
724         gint *indices, row, status, finished;
725         GValue *js;
726         GtkTreeIter iter;
727         GtkTreeView *srctv;
728         GtkTreeModel *model;
729         GtkTreeSelection *select;
730
731         // This bit checks to see if the source is allowed to be
732         // moved.  Only pending and canceled items may be moved.
733         srctv = GTK_TREE_VIEW(gtk_drag_get_source_widget(ctx));
734         select = gtk_tree_view_get_selection (srctv);
735         gtk_tree_selection_get_selected (select, &model, &iter);
736         path = gtk_tree_model_get_path (model, &iter);
737         indices = gtk_tree_path_get_indices(path);
738         row = indices[0];
739         gtk_tree_path_free(path);
740         js = ghb_array_get_nth(ud->queue, row);
741         status = ghb_settings_get_int(js, "job_status");
742         if (status != GHB_QUEUE_PENDING && status != GHB_QUEUE_CANCELED)
743         {
744                 gdk_drag_status(ctx, 0, time);
745                 return TRUE;
746         }
747
748         // The reset checks that the destination is a valid position
749         // in the list.  Can not move above any finished or running items
750         gtk_tree_view_get_dest_row_at_pos (tv, x, y, &path, &pos);
751         if (path == NULL)
752         {
753                 gdk_drag_status(ctx, GDK_ACTION_MOVE, time);
754                 return TRUE;
755         }
756         // Don't allow *drop into*
757         if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
758                 pos = GTK_TREE_VIEW_DROP_BEFORE;
759         if (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
760                 pos = GTK_TREE_VIEW_DROP_AFTER;
761         // Don't allow droping int child items
762         if (gtk_tree_path_get_depth(path) > 1)
763         {
764                 gtk_tree_path_up(path);
765                 pos = GTK_TREE_VIEW_DROP_AFTER;
766         }
767         indices = gtk_tree_path_get_indices(path);
768         row = indices[0];
769         js = ghb_array_get_nth(ud->queue, row);
770
771         finished = find_last_finished(ud->queue);
772         if (row < finished)
773         {
774                 gtk_tree_path_free(path);
775                 gdk_drag_status(ctx, 0, time);
776                 return TRUE;
777         }
778         if (pos != GTK_TREE_VIEW_DROP_AFTER && 
779                 row == finished)
780         {
781                 gtk_tree_path_free(path);
782                 gdk_drag_status(ctx, 0, time);
783                 return TRUE;
784         }
785         gtk_tree_view_set_drag_dest_row(tv, path, pos);
786         gtk_tree_path_free(path);
787         gdk_drag_status(ctx, GDK_ACTION_MOVE, time);
788         return TRUE;
789 }
790
791 void 
792 queue_drag_cb(
793         GtkTreeView *dstwidget, 
794         GdkDragContext *dc, 
795         gint x, gint y, 
796         GtkSelectionData *selection_data, 
797         guint info, guint t, 
798         signal_user_data_t *ud)
799 {
800         GtkTreePath *path = NULL;
801         //GtkTreeModel *model;
802         GtkTreeViewDropPosition pos;
803         GtkTreeIter dstiter, srciter;
804         gint *indices, row;
805         GValue *js;
806         
807         GtkTreeModel *dstmodel = gtk_tree_view_get_model(dstwidget);
808                         
809         g_debug("queue_drag_cb ()");
810         // This doesn't work here for some reason...
811         // gtk_tree_view_get_drag_dest_row(dstwidget, &path, &pos);
812         gtk_tree_view_get_dest_row_at_pos (dstwidget, x, y, &path, &pos);
813         // This little hack is needed because attempting to drop after
814         // the last item gives us no path or pos.
815         if (path == NULL)
816         {
817                 gint n_children;
818
819                 n_children = gtk_tree_model_iter_n_children(dstmodel, NULL);
820                 if (n_children)
821                 {
822                         pos = GTK_TREE_VIEW_DROP_AFTER;
823                         path = gtk_tree_path_new_from_indices(n_children-1, -1);
824                 }
825                 else
826                 {
827                         pos = GTK_TREE_VIEW_DROP_BEFORE;
828                         path = gtk_tree_path_new_from_indices(0, -1);
829                 }
830         }
831         if (path)
832         {
833                 if (gtk_tree_path_get_depth(path) > 1)
834                         gtk_tree_path_up(path);
835                 if (gtk_tree_model_get_iter (dstmodel, &dstiter, path))
836                 {
837                         GtkTreeIter iter;
838                         GtkTreeView *srcwidget;
839                         GtkTreeModel *srcmodel;
840                         GtkTreeSelection *select;
841                         GtkTreePath *srcpath = NULL;
842                         GtkTreePath *dstpath = NULL;
843
844                         srcwidget = GTK_TREE_VIEW(gtk_drag_get_source_widget(dc));
845                         //srcmodel = gtk_tree_view_get_model(srcwidget);
846                         select = gtk_tree_view_get_selection (srcwidget);
847                         gtk_tree_selection_get_selected (select, &srcmodel, &srciter);
848
849                         srcpath = gtk_tree_model_get_path (srcmodel, &srciter);
850                         indices = gtk_tree_path_get_indices(srcpath);
851                         row = indices[0];
852                         gtk_tree_path_free(srcpath);
853                         js = ghb_array_get_nth(ud->queue, row);
854
855                         switch (pos)
856                         {
857                                 case GTK_TREE_VIEW_DROP_BEFORE:
858                                 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
859                                         gtk_tree_store_insert_before (GTK_TREE_STORE (dstmodel), 
860                                                                                                         &iter, NULL, &dstiter);
861                                         break;
862
863                                 case GTK_TREE_VIEW_DROP_AFTER:
864                                 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
865                                         gtk_tree_store_insert_after (GTK_TREE_STORE (dstmodel), 
866                                                                                                         &iter, NULL, &dstiter);
867                                         break;
868
869                                 default:
870                                         break;
871                         }
872                         // Reset job to pending
873                         ghb_settings_set_int(js, "job_status", GHB_QUEUE_PENDING);
874                         add_to_queue_list(ud, js, &iter);
875
876                         dstpath = gtk_tree_model_get_path (dstmodel, &iter);
877                         indices = gtk_tree_path_get_indices(dstpath);
878                         row = indices[0];
879                         gtk_tree_path_free(dstpath);
880                         ghb_array_insert(ud->queue, row, js);
881
882                         srcpath = gtk_tree_model_get_path (srcmodel, &srciter);
883                         indices = gtk_tree_path_get_indices(srcpath);
884                         row = indices[0];
885                         gtk_tree_path_free(srcpath);
886                         ghb_array_remove(ud->queue, row);
887                         gtk_tree_store_remove (GTK_TREE_STORE (srcmodel), &srciter);
888                         ghb_save_queue(ud->queue);
889                 }
890                 gtk_tree_path_free(path);
891         }
892 }
893
894 void
895 ghb_queue_buttons_grey(signal_user_data_t *ud, gboolean working)
896 {
897         GtkWidget *widget;
898         GtkAction *action;
899         gint queue_count;
900         gint titleindex;
901         gboolean title_ok;
902
903         queue_count = ghb_array_len(ud->queue);
904         titleindex = ghb_settings_combo_int(ud->settings, "title");
905         title_ok = (titleindex >= 0);
906
907         widget = GHB_WIDGET (ud->builder, "queue_start1");
908         gtk_widget_set_sensitive (widget, !working && (title_ok || queue_count));
909         widget = GHB_WIDGET (ud->builder, "queue_start2");
910         gtk_widget_set_sensitive (widget, !working && (title_ok || queue_count));
911         action = GHB_ACTION (ud->builder, "queue_start_menu");
912         gtk_action_set_sensitive (action, !working && (title_ok || queue_count));
913         widget = GHB_WIDGET (ud->builder, "queue_pause1");
914         gtk_widget_set_sensitive (widget, working);
915         widget = GHB_WIDGET (ud->builder, "queue_pause2");
916         gtk_widget_set_sensitive (widget, working);
917         action = GHB_ACTION (ud->builder, "queue_pause_menu");
918         gtk_action_set_sensitive (action, working);
919         widget = GHB_WIDGET (ud->builder, "queue_stop");
920         gtk_widget_set_sensitive (widget, working);
921         action = GHB_ACTION (ud->builder, "queue_stop_menu");
922         gtk_action_set_sensitive (action, working);
923 }
924
925 void
926 queue_list_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, GtkCellRenderer *cell)
927 {
928         GtkTreeViewColumn *column;
929         gint width;
930         
931         column = gtk_tree_view_get_column (GTK_TREE_VIEW(widget), 0);
932         width = gtk_tree_view_column_get_width(column);
933         g_debug("col width %d alloc width %d", width, allocation->width);
934         // Set new wrap-width.  Shave a little off to accomidate the icons
935         // that share this column.
936         if (width >= 564) // Don't allow below a certain size
937                 g_object_set(cell, "wrap-width", width-70, NULL);
938 }
939
940 void
941 queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
942 {
943         GValue *js;
944         gboolean running = FALSE;
945         gint count, ii;
946         gint status;
947         gint state;
948
949         count = ghb_array_len(ud->queue);
950         for (ii = 0; ii < count; ii++)
951         {
952                 js = ghb_array_get_nth(ud->queue, ii);
953                 status = ghb_settings_get_int(js, "job_status");
954                 if ((status == GHB_QUEUE_RUNNING) || 
955                         (status == GHB_QUEUE_PENDING))
956                 {
957                         running = TRUE;
958                         break;
959                 }
960         }
961         if (!running)
962         {
963                 // The queue has no running or pending jobs.
964                 // Add current settings to the queue, then run.
965                 if (!queue_add(ud))
966                         return;
967         }
968         state = ghb_get_queue_state();
969         if (state == GHB_STATE_IDLE)
970         {
971                 // Add the first pending queue item and start
972                 ud->current_job = ghb_start_next_job(ud, TRUE);
973         }
974 }
975
976 void
977 queue_stop_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
978 {
979         ud->cancel_encode = TRUE;
980         ghb_cancel_encode(NULL);
981 }
982
983 void
984 queue_pause_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
985 {
986         ghb_pause_queue();
987 }
988
989 gboolean
990 ghb_reload_queue(signal_user_data_t *ud)
991 {
992         GValue *queue;
993         gint unfinished = 0;
994         gint count, ii;
995         gint status;
996         GValue *settings;
997         gchar *message;
998
999         g_debug("ghb_reload_queue");
1000
1001         // I really shouldn't have to do this, but at startup the
1002         // initial window size is larger than it should be.  This
1003         // make it adjust to the proper size.
1004         GtkWindow *hb_window;
1005         hb_window = GTK_WINDOW(GHB_WIDGET (ud->builder, "hb_window"));
1006         gtk_window_resize(hb_window, 16, 16);
1007
1008         queue = ghb_load_queue();
1009         // Look for unfinished entries
1010         count = ghb_array_len(queue);
1011         for (ii = 0; ii < count; ii++)
1012         {
1013                 settings = ghb_array_get_nth(queue, ii);
1014                 status = ghb_settings_get_int(settings, "job_status");
1015                 if (status != GHB_QUEUE_DONE && status != GHB_QUEUE_CANCELED)
1016                 {
1017                         unfinished++;
1018                 }
1019         }
1020         if (unfinished)
1021         {
1022                 message = g_strdup_printf(
1023                                         "You have %d unfinished job%s in a saved queue.\n\n"
1024                                         "Would you like to reload %s?",
1025                                         unfinished, 
1026                                         (unfinished > 1) ? "s" : "",
1027                                         (unfinished > 1) ? "them" : "it");
1028                 if (ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "No", "Yes"))
1029                 {
1030                         GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
1031                         gtk_widget_show (widget);
1032
1033                         ud->queue = queue;
1034                         // First get rid of any old items we don't want
1035                         for (ii = count-1; ii >= 0; ii--)
1036                         {
1037                                 settings = ghb_array_get_nth(queue, ii);
1038                                 status = ghb_settings_get_int(settings, "job_status");
1039                                 if (status == GHB_QUEUE_DONE || status == GHB_QUEUE_CANCELED)
1040                                 {
1041                                         GValue *old = ghb_array_get_nth(queue, ii);
1042                                         ghb_value_free(old);
1043                                         ghb_array_remove(queue, ii);
1044                                 }
1045                         }
1046                         count = ghb_array_len(queue);
1047                         for (ii = 0; ii < count; ii++)
1048                         {
1049                                 settings = ghb_array_get_nth(queue, ii);
1050                                 ghb_settings_set_int(settings, "job_unique_id", 0);
1051                                 ghb_settings_set_int(settings, "job_status", GHB_QUEUE_PENDING);
1052                                 add_to_queue_list(ud, settings, NULL);
1053                         }
1054                         ghb_queue_buttons_grey(ud, FALSE);
1055                 }
1056                 else
1057                 {
1058                         ghb_value_free(queue);
1059                         ghb_remove_queue_file();
1060                 }
1061                 g_free(message);
1062         }
1063         return FALSE;
1064 }
1065
1066 gboolean 
1067 queue_key_press_cb(
1068         GtkWidget *widget, 
1069         GdkEventKey *event,
1070         signal_user_data_t *ud)
1071 {
1072         GtkTreeView *treeview;
1073         GtkTreeSelection *selection;
1074         GtkTreeModel *store;
1075         GtkTreeIter iter;
1076         gint row;
1077         gint *indices;
1078         gint unique_id;
1079         GValue *settings;
1080         gint status;
1081
1082         g_debug("queue_key_press_cb ()");
1083         if (event->keyval != GDK_Delete)
1084                 return FALSE;
1085         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
1086         store = gtk_tree_view_get_model(treeview);
1087
1088         selection = gtk_tree_view_get_selection (treeview);
1089         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1090         {
1091                 GtkTreePath *treepath;
1092
1093                 treepath = gtk_tree_model_get_path (store, &iter);
1094                 // Find the entry in the queue
1095                 indices = gtk_tree_path_get_indices (treepath);
1096                 row = indices[0];
1097                 // Can only free the treepath After getting what I need from
1098                 // indices since this points into treepath somewhere.
1099                 gtk_tree_path_free (treepath);
1100                 if (row < 0) return FALSE;
1101                 if (row >= ghb_array_len(ud->queue))
1102                         return FALSE;
1103                 settings = ghb_array_get_nth(ud->queue, row);
1104                 status = ghb_settings_get_int(settings, "job_status");
1105                 if (status == GHB_QUEUE_RUNNING)
1106                 {
1107                         // Ask if wants to stop encode.
1108                         if (!ghb_cancel_encode(NULL))
1109                         {
1110                                 return TRUE;
1111                         }
1112                         unique_id = ghb_settings_get_int(settings, "job_unique_id");
1113                         ghb_remove_job(unique_id);
1114                 }
1115                 // Remove the selected item
1116                 gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
1117                 // Remove the corresponding item from the queue list
1118                 GValue *old = ghb_array_get_nth(ud->queue, row);
1119                 ghb_value_free(old);
1120                 ghb_array_remove(ud->queue, row);
1121                 ghb_save_queue(ud->queue);
1122                 return TRUE;
1123         }
1124         return FALSE;
1125 }
1126
1127 GValue *ghb_queue_edit_settings = NULL;
1128
1129 void
1130 queue_edit_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1131 {
1132         GtkTreeView *treeview;
1133         GtkTreeSelection *selection;
1134         GtkTreeModel *store;
1135         GtkTreeIter iter;
1136         gint row;
1137         gint *indices;
1138         gint status;
1139
1140         g_debug("queue_key_press_cb ()");
1141         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
1142         store = gtk_tree_view_get_model(treeview);
1143
1144         selection = gtk_tree_view_get_selection (treeview);
1145         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1146         {
1147                 GtkTreePath *treepath;
1148
1149                 treepath = gtk_tree_model_get_path (store, &iter);
1150                 // Find the entry in the queue
1151                 indices = gtk_tree_path_get_indices (treepath);
1152                 row = indices[0];
1153                 // Can only free the treepath After getting what I need from
1154                 // indices since this points into treepath somewhere.
1155                 gtk_tree_path_free (treepath);
1156                 if (row < 0) return;
1157                 if (row >= ghb_array_len(ud->queue))
1158                         return;
1159                 ghb_queue_edit_settings = ghb_array_get_nth(ud->queue, row);
1160                 status = ghb_settings_get_int(ghb_queue_edit_settings, "job_status");
1161                 if (status == GHB_QUEUE_PENDING)
1162                 {
1163                         // Remove the selected item
1164                         gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
1165                         // Remove the corresponding item from the queue list
1166                         ghb_array_remove(ud->queue, row);
1167                 }
1168                 gchar *source;
1169                 source = ghb_settings_get_string(ghb_queue_edit_settings, "source");
1170                 ghb_do_scan(ud, source, FALSE);
1171                 g_free(source);
1172         }
1173 }
1174