diff options
author | John Stebbins <[email protected]> | 2019-06-25 15:55:59 -0700 |
---|---|---|
committer | John Stebbins <[email protected]> | 2019-06-25 16:06:10 -0700 |
commit | 25e1f04a63dc07e944522a10e9f9733e027cb9f5 (patch) | |
tree | 8e4eb686468ce9e86b6a8a704d4fb135310bd213 /gtk | |
parent | a8b2607e4bb59445f76d6b3d1733595bb856070c (diff) |
LinGui: add queue statistics
and tweak the layout per BradleyS suggestions
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/src/callbacks.c | 26 | ||||
-rw-r--r-- | gtk/src/callbacks.h | 1 | ||||
-rw-r--r-- | gtk/src/ghb.m4 | 302 | ||||
-rw-r--r-- | gtk/src/hb-backend.c | 120 | ||||
-rw-r--r-- | gtk/src/hb-backend.h | 18 | ||||
-rw-r--r-- | gtk/src/queuehandler.c | 447 | ||||
-rw-r--r-- | gtk/src/queuehandler.h | 3 |
7 files changed, 799 insertions, 118 deletions
diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c index 6e0373bfd..7c661c415 100644 --- a/gtk/src/callbacks.c +++ b/gtk/src/callbacks.c @@ -1382,7 +1382,7 @@ source_dialog_extra_widgets( gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0); } -static void break_duration(gint64 duration, gint *hh, gint *mm, gint *ss) +void ghb_break_duration(gint64 duration, gint *hh, gint *mm, gint *ss) { *hh = duration / (60*60); *mm = (duration / 60) % 60; @@ -1415,7 +1415,7 @@ update_title_duration(signal_user_data_t *ud) start = ghb_dict_get_int(ud->settings, "start_point"); end = ghb_dict_get_int(ud->settings, "end_point"); duration = end - start; - break_duration(duration, &hh, &mm, &ss); + ghb_break_duration(duration, &hh, &mm, &ss); } else if (ghb_settings_combo_int(ud->settings, "PtoPType") == 2) { @@ -1428,7 +1428,7 @@ update_title_duration(signal_user_data_t *ud) end = ghb_dict_get_int(ud->settings, "end_point"); frames = end - start + 1; duration = frames * title->vrate.den / title->vrate.num; - break_duration(duration, &hh, &mm, &ss); + ghb_break_duration(duration, &hh, &mm, &ss); } else { @@ -3767,6 +3767,8 @@ submit_job(signal_user_data_t *ud, GhbValue *queueDict) GhbValue *job_dict = ghb_dict_get(queueDict, "Job"); int unique_id = ghb_add_job(ghb_queue_handle(), job_dict); ghb_dict_set_int(uiDict, "job_unique_id", unique_id); + time_t now = time(NULL); + ghb_dict_set_int(uiDict, "job_start_time", now); ghb_start_queue(); // Show queue progress bar @@ -3899,7 +3901,7 @@ ghb_start_next_job(signal_user_data_t *ud) ghb_dict_set_bool(ud->globals, "SkipDiskFreeCheck", FALSE); } -gchar* +static gchar* working_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) { gchar *task_str, *job_str, *status_str; @@ -3967,7 +3969,7 @@ working_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) return status_str; } -gchar* +static gchar* searching_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) { gchar *task_str, *job_str, *status_str; @@ -4142,8 +4144,8 @@ ghb_backend_events(signal_user_data_t *ud) // This needs to be in scanning and working since scanning // happens fast enough that it can be missed gtk_label_set_text(work_status, _("Scanning ...")); - gtk_progress_bar_set_fraction(progress, 0); - ghb_queue_progress_set_fraction(ud, index, 0); + gtk_progress_bar_set_fraction(progress, status.queue.progress); + ghb_queue_progress_set_fraction(ud, index, status.queue.progress); } else if (status.queue.state & GHB_STATE_SCANDONE) { @@ -4152,6 +4154,7 @@ ghb_backend_events(signal_user_data_t *ud) else if (status.queue.state & GHB_STATE_PAUSED) { gtk_label_set_text (work_status, _("Paused")); + ghb_queue_update_live_stats(ud, index, &status.queue); } else if (status.queue.state & GHB_STATE_SEARCHING) { @@ -4170,6 +4173,7 @@ ghb_backend_events(signal_user_data_t *ud) status_str = working_status_string(ud, &status.queue); gtk_label_set_text (work_status, status_str); gtk_progress_bar_set_fraction (progress, status.queue.progress); + ghb_queue_update_live_stats(ud, index, &status.queue); ghb_queue_progress_set_fraction(ud, index, status.queue.progress); g_free(status_str); } @@ -4196,8 +4200,12 @@ ghb_backend_events(signal_user_data_t *ud) { GhbValue *uiDict = ghb_dict_get(queueDict, "uiSettings"); ghb_dict_set_int(uiDict, "job_status", qstatus); + time_t now = time(NULL); + ghb_dict_set_int(uiDict, "job_finish_time", now); + ghb_dict_set_int(uiDict, "job_pause_time_ms", status.queue.paused); } ghb_queue_update_status_icon(ud, index); + ghb_queue_update_live_stats(ud, index, &status.queue); gtk_progress_bar_set_fraction(progress, 1.0); ghb_queue_progress_set_fraction(ud, index, 1.0); @@ -4607,10 +4615,10 @@ chapter_refresh_list_row_ui( g_debug("Updating chapter row ui"); chapter = ghb_dict_get_string(ghb_array_get(chapter_list, index), "Name"); duration = ghb_get_chapter_duration(title, index) / 90000; - break_duration(duration, &hh, &mm, &ss); + ghb_break_duration(duration, &hh, &mm, &ss); s_duration = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); start = ghb_get_chapter_start(title, index) / 90000; - break_duration(start, &hh, &mm, &ss); + ghb_break_duration(start, &hh, &mm, &ss); s_start = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); gtk_list_store_set(GTK_LIST_STORE(tm), ti, 0, index+1, diff --git a/gtk/src/callbacks.h b/gtk/src/callbacks.h index 09d67ad04..6e025f0a6 100644 --- a/gtk/src/callbacks.h +++ b/gtk/src/callbacks.h @@ -90,6 +90,7 @@ void ghb_scale_configure(signal_user_data_t *ud, char *name, double val, void ghb_update_summary_info(signal_user_data_t *ud); void ghb_set_title_settings(signal_user_data_t *ud, GhbValue *settings); void ghb_browse_uri(signal_user_data_t *ud, const gchar *uri); +void ghb_break_duration(gint64 duration, gint *hh, gint *mm, gint *ss); #endif // _CALLBACKS_H_ diff --git a/gtk/src/ghb.m4 b/gtk/src/ghb.m4 index 0e2c21ecb..f3a4e6e4e 100644 --- a/gtk/src/ghb.m4 +++ b/gtk/src/ghb.m4 @@ -115,21 +115,21 @@ conjunction with the "Forced" option.</property> <attribute name="action">app.queue-reset-all</attribute> </item> <item> - <attribute name="label" translatable="yes">Delete Completed Jobs</attribute> + <attribute name="label" translatable="yes">Clear Completed Jobs</attribute> <attribute name="action">app.queue-delete-complete</attribute> </item> <item> - <attribute name="label" translatable="yes">Delete All Jobs</attribute> + <attribute name="label" translatable="yes">Clear All Jobs</attribute> <attribute name="action">app.queue-delete-all</attribute> </item> <item> - <attribute name="label" translatable="yes">Export Queue</attribute> - <attribute name="action">app.queue-export</attribute> - </item> - <item> <attribute name="label" translatable="yes">Import Queue</attribute> <attribute name="action">app.queue-import</attribute> </item> + <item> + <attribute name="label" translatable="yes">Export Queue</attribute> + <attribute name="action">app.queue-export</attribute> + </item> </section> </menu> @@ -345,6 +345,7 @@ conjunction with the "Forced" option.</property> <property name="hexpand">False</property> <property name="can_focus">False</property> <property name="halign">start</property> + <property name="valign">baseline</property> <property name="use_markup">True</property> <property name="margin-start">12</property> <property name="label" translatable="yes"><span size="x-large">Queue</span></property> @@ -359,6 +360,7 @@ conjunction with the "Forced" option.</property> <property name="hexpand">False</property> <property name="can_focus">False</property> <property name="halign">start</property> + <property name="valign">baseline</property> <property name="use_markup">True</property> <property name="margin-start">12</property> <property name="label" translatable="yes">0 jobs pending</property> @@ -514,6 +516,8 @@ conjunction with the "Forced" option.</property> <property name="activate_on_single_click">False</property> <signal name="row-selected" handler="queue_list_selection_changed_cb" swapped="no"/> <signal name="key-press-event" handler="queue_key_press_cb" swapped="no"/> + <signal name="drag-motion" handler="queue_drag_motion_cb" swapped="no"/> + <signal name="drag-data-received" handler="queue_drop_cb" swapped="no"/> </object> </child> </object> @@ -570,6 +574,7 @@ conjunction with the "Forced" option.</property> <property name="orientation">vertical</property> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="margin-top">4</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <child> <object class="GtkStackSwitcher" id="QueueStackSwitcher"> @@ -1007,6 +1012,291 @@ Resets the queue job to pending and ready to run again.</property> <property name="can_focus">False</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="spacing">3</property> + <child> + <object class="GtkScrolledWindow" id="queue_stats_scroll"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="shadow-type">GTK_SHADOW_NONE</property> + <property name="vexpand">True</property> + <property name="hscrollbar-policy">GTK_POLICY_NEVER</property> + <property name="valign">GTK_ALIGN_FILL</property> + <property name="margin-bottom">12</property> + <child> + <object class="GtkGrid" id="queue_stats_grid"> + <property name="visible">True</property> + <property name="vexpand">True</property> + <property name="hexpand">False</property> + <property name="can_focus">False</property> + <property name="column-spacing">12</property> + <property name="row-spacing">12</property> + <child> + <object class="GtkLabel" id="queue_stats_pass_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">Pass:</property> + </object> + <packing> + <property name="top_attach">0</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_pass"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + </object> + <packing> + <property name="top_attach">0</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_start_time_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">Start Time:</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_start_time"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_finish_time_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">End Time:</property> + </object> + <packing> + <property name="top_attach">2</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_finish_time"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + <property name="lines">2</property> + <property name="wrap_mode">word-char</property> + <property name="ellipsize">middle</property> + <property name="selectable">True</property> + </object> + <packing> + <property name="top_attach">2</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_paused_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">Paused Duration:</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_paused"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + <property name="lines">2</property> + <property name="wrap_mode">word-char</property> + <property name="ellipsize">middle</property> + <property name="selectable">True</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_encode_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">Encode Time:</property> + </object> + <packing> + <property name="top_attach">4</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_encode"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + </object> + <packing> + <property name="top_attach">4</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_file_size_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">File Size:</property> + </object> + <packing> + <property name="top_attach">5</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_file_size"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + </object> + <packing> + <property name="top_attach">5</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_result_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="halign">start</property> + <property name="use_markup">True</property> + <property name="label" translatable="yes">Status:</property> + </object> + <packing> + <property name="top_attach">6</property> + <property name="left_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="queue_stats_result"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="halign">start</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="hexpand">False</property> + <property name="label" translatable="yes"></property> + <property name="width-chars">50</property> + </object> + <packing> + <property name="top_attach">6</property> + <property name="left_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> </object> <packing> <property name="position">1</property> diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c index 139713e52..c79b821b7 100644 --- a/gtk/src/hb-backend.c +++ b/gtk/src/hb-backend.c @@ -3453,6 +3453,8 @@ ghb_get_status(ghb_status_t *status) static void update_status(hb_state_t *state, ghb_instance_status_t *status) { + status->unique_id = state->sequence_id; + #define p state->param.scanning if (state->state & HB_STATE_SCANNING) { @@ -3465,6 +3467,7 @@ update_status(hb_state_t *state, ghb_instance_status_t *status) } else { + // If last state seen was scanning, signal that scan id complete if (status->state & GHB_STATE_SCANNING) { status->state |= GHB_STATE_SCANDONE; @@ -3473,83 +3476,72 @@ update_status(hb_state_t *state, ghb_instance_status_t *status) } #undef p #define p state->param.working - if (state->state & HB_STATE_WORKING) - { - if (status->state & GHB_STATE_SCANNING) + if (state->state & (HB_STATE_WORKING | HB_STATE_WORKDONE | + HB_STATE_SEARCHING)) + { + status->pass = p.pass; + status->pass_count = p.pass_count; + status->pass_id = p.pass_id; + status->progress = p.progress; + status->rate_cur = p.rate_cur; + status->rate_avg = p.rate_avg; + status->eta_seconds = p.eta_seconds; + status->hours = p.hours; + status->minutes = p.minutes; + status->seconds = p.seconds; + status->paused = p.paused; + + if (state->state & HB_STATE_WORKING) { - status->state &= ~GHB_STATE_SCANNING; - status->state |= GHB_STATE_SCANDONE; + status->state |= GHB_STATE_WORKING; + status->state &= ~GHB_STATE_PAUSED; + status->state &= ~GHB_STATE_SEARCHING; } - status->state |= GHB_STATE_WORKING; - status->state &= ~GHB_STATE_PAUSED; - status->state &= ~GHB_STATE_SEARCHING; - status->pass = p.pass; - status->pass_count = p.pass_count; - status->pass_id = p.pass_id; - status->progress = p.progress; - status->rate_cur = p.rate_cur; - status->rate_avg = p.rate_avg; - status->hours = p.hours; - status->minutes = p.minutes; - status->seconds = p.seconds; - status->unique_id = p.sequence_id; - } - else - { - status->state &= ~GHB_STATE_WORKING; - } - if (state->state & HB_STATE_SEARCHING) - { - status->state |= GHB_STATE_SEARCHING; - status->state &= ~GHB_STATE_WORKING; - status->state &= ~GHB_STATE_PAUSED; - status->pass = p.pass; - status->pass_count = p.pass_count; - status->pass_id = p.pass_id; - status->progress = p.progress; - status->rate_cur = p.rate_cur; - status->rate_avg = p.rate_avg; - status->hours = p.hours; - status->minutes = p.minutes; - status->seconds = p.seconds; - status->unique_id = p.sequence_id; - } - else - { - status->state &= ~GHB_STATE_SEARCHING; - } -#undef p -#define p state->param.working - if (state->state & HB_STATE_WORKDONE) - { - status->state |= GHB_STATE_WORKDONE; - status->state &= ~GHB_STATE_MUXING; - status->state &= ~GHB_STATE_PAUSED; - status->state &= ~GHB_STATE_WORKING; - status->state &= ~GHB_STATE_SEARCHING; - status->unique_id = p.sequence_id; - switch (p.error) + else { - case HB_ERROR_NONE: - status->error = GHB_ERROR_NONE; - break; - case HB_ERROR_CANCELED: - status->error = GHB_ERROR_CANCELED; - break; - default: - status->error = GHB_ERROR_FAIL; - break; + status->state &= ~GHB_STATE_WORKING; + } + if (state->state & HB_STATE_SEARCHING) + { + status->state |= GHB_STATE_SEARCHING; + status->state &= ~GHB_STATE_WORKING; + status->state &= ~GHB_STATE_PAUSED; + } + else + { + status->state &= ~GHB_STATE_SEARCHING; + } + if (state->state & HB_STATE_WORKDONE) + { + status->state |= GHB_STATE_WORKDONE; + status->state &= ~GHB_STATE_MUXING; + status->state &= ~GHB_STATE_PAUSED; + status->state &= ~GHB_STATE_WORKING; + status->state &= ~GHB_STATE_SEARCHING; + switch (p.error) + { + case HB_ERROR_NONE: + status->error = GHB_ERROR_NONE; + break; + case HB_ERROR_CANCELED: + status->error = GHB_ERROR_CANCELED; + break; + default: + status->error = GHB_ERROR_FAIL; + break; + } } } -#undef p if (state->state & HB_STATE_PAUSED) { + status->paused = p.paused; status->state |= GHB_STATE_PAUSED; } else { status->state &= ~GHB_STATE_PAUSED; } +#undef p if (state->state & HB_STATE_MUXING) { status->state |= GHB_STATE_MUXING; diff --git a/gtk/src/hb-backend.h b/gtk/src/hb-backend.h index 592a759b6..4bcd41a59 100644 --- a/gtk/src/hb-backend.h +++ b/gtk/src/hb-backend.h @@ -47,17 +47,19 @@ typedef struct gint preview_cur; // WORKING - gint unique_id; - gint pass_id; - gint pass; - gint pass_count; + gint unique_id; + gint pass_id; + gint pass; + gint pass_count; gdouble progress; gdouble rate_cur; gdouble rate_avg; - gint hours; - gint minutes; - gint seconds; - gint error; + gint64 eta_seconds; + gint hours; + gint minutes; + gint seconds; + gint64 paused; + gint error; } ghb_instance_status_t; typedef struct diff --git a/gtk/src/queuehandler.c b/gtk/src/queuehandler.c index fba04a258..496bcfd92 100644 --- a/gtk/src/queuehandler.c +++ b/gtk/src/queuehandler.c @@ -36,6 +36,7 @@ #include "subtitlehandler.h" #include "ghb-dvd.h" #include "plist.h" +#include "queuehandler.h" void ghb_queue_buttons_grey(signal_user_data_t *ud); G_MODULE_EXPORT void @@ -70,6 +71,12 @@ static GtkWidget *find_widget(GtkWidget *widget, gchar *name) return result; } +void +ghb_queue_drag_n_drop_init(signal_user_data_t * ud) +{ + +} + static void queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) { @@ -116,7 +123,7 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) str = g_string_new(""); if (preset_modified) { - g_string_append_printf(str, _("Modified, %s"), name); + g_string_append_printf(str, _("%s (Modified)"), name); } else { @@ -156,22 +163,22 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) sep = "\n"; if (markers) { - g_string_append_printf(str, "%s%s", sep, "Chapter Markers"); + g_string_append_printf(str, "%s%s", sep, _("Chapter Markers")); sep = ", "; } if (av_align) { - g_string_append_printf(str, "%s%s", sep, "Align A/V"); + g_string_append_printf(str, "%s%s", sep, _("Align A/V")); sep = ", "; } if (http) { - g_string_append_printf(str, "%s%s", sep, "Web Optimized"); + g_string_append_printf(str, "%s%s", sep, _("Web Optimized")); sep = ", "; } if (ipod) { - g_string_append_printf(str, "%s%s", sep, "iPod 5G"); + g_string_append_printf(str, "%s%s", sep, _("iPod 5G")); sep = ", "; } @@ -203,10 +210,10 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) display_height); display_width = ghb_dict_get_int(uiDict, "PictureDisplayWidth"); - text = g_strdup_printf("%d:%d:%d:%d Crop\n" - "%dx%d storage, %dx%d display\n" - "%d:%d Pixel Aspect Ratio\n" - "%s Display Aspect Ratio", + text = g_strdup_printf(_("%d:%d:%d:%d Crop\n" + "%dx%d storage, %dx%d display\n" + "%d:%d Pixel Aspect Ratio\n" + "%s Display Aspect Ratio"), crop[0], crop[1], crop[2], crop[3], width, height, (int)display_width, display_height, par_width, par_height, display_aspect); @@ -234,19 +241,19 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) int br = ghb_dict_get_int(uiDict, "VideoAvgBitrate"); if (!two_pass) { - g_string_append_printf(str, "%s, Bitrate %dkbps", + g_string_append_printf(str, _("%s, Bitrate %dkbps"), video_encoder->name, br); } else { - g_string_append_printf(str, "%s, Bitrate %dkbps (2 Pass)", + g_string_append_printf(str, _("%s, Bitrate %dkbps (2 Pass)"), video_encoder->name, br); } } else { gdouble quality = ghb_dict_get_double(uiDict, "VideoQualitySlider"); - g_string_append_printf(str, "%s, Constant Quality %.4g(%s)", + g_string_append_printf(str, _("%s, Constant Quality %.4g(%s)"), video_encoder->name, quality, hb_video_quality_get_name(video_encoder->codec)); } @@ -279,22 +286,22 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) sep = "\n"; if (enc_preset != NULL) { - g_string_append_printf(str, "%sPreset %s", sep, enc_preset); + g_string_append_printf(str, _("%sPreset %s"), sep, enc_preset); sep = ", "; } if (enc_tune != NULL) { - g_string_append_printf(str, "%sTune %s", sep, enc_tune); + g_string_append_printf(str, _("%sTune %s"), sep, enc_tune); sep = ", "; } if (enc_profile != NULL) { - g_string_append_printf(str, "%sProfile %s", sep, enc_profile); + g_string_append_printf(str, _("%sProfile %s"), sep, enc_profile); sep = ", "; } if (enc_level != NULL) { - g_string_append_printf(str, "%sLevel %s", sep, enc_level); + g_string_append_printf(str, _("%sLevel %s"), sep, enc_level); sep = ", "; } @@ -311,16 +318,16 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) rate_str = g_strdup_printf("%.6g", (gdouble)vrate.num / vrate.den); if (ghb_dict_get_bool(uiDict, "VideoFramerateCFR")) { - g_string_append_printf(str, "\nConstant Framerate %s fps", rate_str); + g_string_append_printf(str, _("\nConstant Framerate %s fps"), rate_str); } else if (ghb_dict_get_bool(uiDict, "VideoFrameratePFR")) { - g_string_append_printf(str, "\nPeak Framerate %s fps (may be lower)", + g_string_append_printf(str, _("\nPeak Framerate %s fps (may be lower)"), rate_str); } else if (ghb_dict_get_bool(uiDict, "VideoFramerateVFR")) { - g_string_append_printf(str, "\nVariable Framerate %s fps", rate_str); + g_string_append_printf(str, _("\nVariable Framerate %s fps"), rate_str); } g_free(rate_str); @@ -483,18 +490,18 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) burn = ghb_dict_get_bool(searchDict, "Burn"); def = ghb_dict_get_bool(searchDict, "Default"); - g_string_append_printf(str, "Foreign Audio Scan"); + g_string_append_printf(str, _("Foreign Audio Scan")); if (force) { - g_string_append_printf(str, ", Forced Only"); + g_string_append_printf(str, _(", Forced Only")); } if (burn) { - g_string_append_printf(str, ", Burned"); + g_string_append_printf(str, _(", Burned")); } else if (def) { - g_string_append_printf(str, ", Default"); + g_string_append_printf(str, _(", Default")); } sep = "\n"; } @@ -516,15 +523,15 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) g_string_append_printf(str, "%s%s", sep, desc); if (force) { - g_string_append_printf(str, ", Forced Only"); + g_string_append_printf(str, _(", Forced Only")); } if (burn) { - g_string_append_printf(str, ", Burned"); + g_string_append_printf(str, _(", Burned")); } else if (def) { - g_string_append_printf(str, ", Default"); + g_string_append_printf(str, _(", Default")); } sep = "\n"; } @@ -535,6 +542,160 @@ queue_update_summary(GhbValue * queueDict, signal_user_data_t *ud) g_free(text); } +void +queue_update_stats(GhbValue * queueDict, signal_user_data_t *ud) +{ + GhbValue * uiDict; + + uiDict = ghb_dict_get(queueDict, "uiSettings"); + if (uiDict == NULL) // should never happen + { + return; + } + + const char * result = ""; + int status = ghb_dict_get_int(uiDict, "job_status"); + + switch (status) + { + case GHB_QUEUE_RUNNING: + // This job is running. + // ghb_queue_update_live_stats() will update stats + return; + + case GHB_QUEUE_DONE: + result = _("Completed"); + break; + + case GHB_QUEUE_CANCELED: + result = _("Canceled"); + break; + + case GHB_QUEUE_FAIL: + result = _("Failed"); + break; + + case GHB_QUEUE_PENDING: + default: + // Should never happen + result = _("Unknown"); + break; + } + + GtkLabel * label; + struct tm * tm; + char date[40] = ""; + char * str; + time_t start, finish, paused, duration; + + start = ghb_dict_get_int(uiDict, "job_start_time"); + finish = ghb_dict_get_int(uiDict, "job_finish_time"); + paused = ghb_dict_get_int(uiDict, "job_pause_time_ms") / 1000; + + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass_label")); + gtk_widget_set_visible(GTK_WIDGET(label), FALSE); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass")); + gtk_widget_set_visible(GTK_WIDGET(label), FALSE); + + tm = localtime( &start ); + strftime(date, 40, "%c", tm); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_start_time")); + gtk_label_set_text(label, date); + + tm = localtime( &finish ); + strftime(date, 40, "%c", tm); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_finish_time")); + gtk_label_set_text(label, date); + + int dd = 0, hh, mm, ss; + ghb_break_duration(paused, &hh, &mm, &ss); + if (hh >= 24) + { + dd = hh / 24; + hh = hh - dd * 24; + } + switch (dd) + { + case 0: + str = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); + break; + case 1: + str = g_strdup_printf(_("%d Day %02d:%02d:%02d"), dd, hh, mm, ss); + break; + default: + str = g_strdup_printf(_("%d Days %02d:%02d:%02d"), dd, hh, mm, ss); + break; + } + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_paused")); + gtk_label_set_text(label, str); + g_free(str); + + duration = finish - start; + if (duration < 0) + { + duration = 0; + } + dd = 0; + ghb_break_duration(duration, &hh, &mm, &ss); + if (hh >= 24) + { + dd = hh / 24; + hh = hh - dd * 24; + } + switch (dd) + { + case 0: + str = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); + break; + case 1: + str = g_strdup_printf(_("%d Day %02d:%02d:%02d"), dd, hh, mm, ss); + break; + default: + str = g_strdup_printf(_("%d Days %02d:%02d:%02d"), dd, hh, mm, ss); + break; + } + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_encode")); + gtk_label_set_text(label, str); + g_free(str); + + const char * path; + struct stat stbuf; + + path = ghb_dict_get_string(uiDict, "destination"); + if (g_stat(path, &stbuf) == 0) + { + const char * units = _("B"); + double size = stbuf.st_size; + if (size > 1024) + { + units = _("KB"); + size /= 1024.0; + } + if (size > 1024) + { + units = _("MB"); + size /= 1024.0; + } + if (size > 1024) + { + units = _("GB"); + size /= 1024.0; + } + str = g_strdup_printf("%.2f %s", size, units); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_file_size")); + gtk_label_set_text(label, str); + g_free(str); + } + else + { + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_file_size")); + gtk_label_set_text(label, _("Error")); + } + + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_result")); + gtk_label_set_text(label, result); +} + #define ACTIVITY_MAX_READ_SZ (1024*1024) static void read_log(signal_user_data_t * ud, const char * log_path) { @@ -592,11 +753,12 @@ void ghb_queue_select_log(signal_user_data_t * ud) GtkTextBuffer * current; gint index; GhbValue * queueDict, *uiDict; - GtkWidget * queue_log_tab; + GtkWidget * queue_log_tab, * queue_stats_tab; - queue_log_tab = GHB_WIDGET(ud->builder, "queue_log_tab"); - lb = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "queue_list")); - row = gtk_list_box_get_selected_row(lb); + queue_log_tab = GHB_WIDGET(ud->builder, "queue_log_tab"); + queue_stats_tab = GHB_WIDGET(ud->builder, "queue_stats_tab"); + lb = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "queue_list")); + row = gtk_list_box_get_selected_row(lb); if (row != NULL) { // There is a queue list row selected @@ -619,6 +781,7 @@ void ghb_queue_select_log(signal_user_data_t * ud) // Selected encode is running, enable display of log and // show the live buffer gtk_widget_set_visible(queue_log_tab, TRUE); + gtk_widget_set_visible(queue_stats_tab, TRUE); if (ud->queue_activity_buffer != current) { gtk_text_view_set_buffer(tv, ud->queue_activity_buffer); @@ -639,6 +802,7 @@ void ghb_queue_select_log(signal_user_data_t * ud) { // enable display of log and read log into display buffer gtk_widget_set_visible(queue_log_tab, TRUE); + gtk_widget_set_visible(queue_stats_tab, TRUE); ghb_ui_update(ud, "queue_activity_location", ghb_string_value(log_path)); read_log(ud, log_path); @@ -648,6 +812,7 @@ void ghb_queue_select_log(signal_user_data_t * ud) // No log file, encode is pending // disable display of log gtk_widget_set_visible(queue_log_tab, FALSE); + gtk_widget_set_visible(queue_stats_tab, FALSE); } } } @@ -655,6 +820,7 @@ void ghb_queue_select_log(signal_user_data_t * ud) { // No row selected, disable display of log gtk_widget_set_visible(queue_log_tab, FALSE); + gtk_widget_set_visible(queue_stats_tab, FALSE); } } @@ -692,6 +858,7 @@ queue_list_selection_changed_cb(GtkListBox *box, GtkListBoxRow *row, queueDict = ghb_array_get(ud->queue, index); } queue_update_summary(queueDict, ud); + queue_update_stats(queueDict, ud); ghb_queue_select_log(ud); ghb_queue_buttons_grey(ud); } @@ -867,6 +1034,224 @@ ghb_queue_progress_set_fraction(signal_user_data_t *ud, int index, gdouble frac) } void +ghb_queue_update_live_stats(signal_user_data_t * ud, int index, ghb_instance_status_t * status) +{ + int count = ghb_array_len(ud->queue); + if (index < 0 || index >= count) + { + // invalid index + return; + } + + GtkListBox * lb; + GtkListBoxRow * row; + + lb = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "queue_list")); + row = gtk_list_box_get_selected_row(lb); + if (row == NULL || index != gtk_list_box_row_get_index(row)) + { + return; + } + + GhbValue * queueDict, * uiDict; + queueDict = ghb_array_get(ud->queue, index); + if (queueDict == NULL) // should never happen + { + return; + } + uiDict = ghb_dict_get(queueDict, "uiSettings"); + if (uiDict == NULL) // should never happen + { + return; + } + + GtkLabel * label; + struct tm * tm; + char date[40] = ""; + char * str; + const char * pass = ""; + const char * result = ""; + time_t start, finish, paused, duration; + + start = ghb_dict_get_int(uiDict, "job_start_time"); + finish = time(NULL); + if (status->state & GHB_STATE_WORKING) + { + finish += status->eta_seconds; + } + paused = status->paused / 1000; + if ((status->state & GHB_STATE_WORKING) && status->pass_count > 1) + { + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass_label")); + gtk_widget_set_visible(GTK_WIDGET(label), TRUE); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass")); + gtk_widget_set_visible(GTK_WIDGET(label), TRUE); + switch (status->pass_id) + { + case HB_PASS_SUBTITLE: + pass = _("Foreign Audio Search"); + break; + + case HB_PASS_ENCODE_1ST: + pass = _("Encode First"); + break; + + case HB_PASS_ENCODE_2ND: + pass = _("Encode Second"); + break; + + default: + // Should never happen + pass = _("Error"); + break; + } + } + else + { + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass_label")); + gtk_widget_set_visible(GTK_WIDGET(label), FALSE); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass")); + gtk_widget_set_visible(GTK_WIDGET(label), FALSE); + } + + if (status->state & GHB_STATE_SCANNING) + { + result = _("Scanning Title"); + } + else if (status->state & GHB_STATE_SCANNING) + { + result = _("Encoding Paused"); + } + else if (status->state & GHB_STATE_WORKING) + { + result = _("Encoding In Progress"); + } + else if (status->state & GHB_STATE_WORKDONE) + { + switch (status->error) + { + case GHB_ERROR_NONE: + result = _("Completed"); + break; + + case GHB_ERROR_CANCELED: + result = _("Canceled"); + break; + + case GHB_ERROR_FAIL: + result = _("Failed"); + break; + + default: + // Should never happen + result = _("Unknown"); + break; + } + } + + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_pass")); + gtk_label_set_text(label, pass); + + tm = localtime( &start ); + strftime(date, 40, "%c", tm); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_start_time")); + gtk_label_set_text(label, date); + + tm = localtime( &finish ); + strftime(date, 40, "%c", tm); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_finish_time")); + gtk_label_set_text(label, date); + + int dd = 0, hh, mm, ss; + ghb_break_duration(paused, &hh, &mm, &ss); + if (hh >= 24) + { + dd = hh / 24; + hh = hh - dd * 24; + } + switch (dd) + { + case 0: + str = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); + break; + case 1: + str = g_strdup_printf(_("%d Day %02d:%02d:%02d"), dd, hh, mm, ss); + break; + default: + str = g_strdup_printf(_("%d Days %02d:%02d:%02d"), dd, hh, mm, ss); + break; + } + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_paused")); + gtk_label_set_text(label, str); + g_free(str); + + duration = finish - start; + if (duration < 0) + { + duration = 0; + } + dd = 0; + ghb_break_duration(duration, &hh, &mm, &ss); + if (hh >= 24) + { + dd = hh / 24; + hh = hh - dd * 24; + } + switch (dd) + { + case 0: + str = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); + break; + case 1: + str = g_strdup_printf(_("%d Day %02d:%02d:%02d"), dd, hh, mm, ss); + break; + default: + str = g_strdup_printf(_("%d Days %02d:%02d:%02d"), dd, hh, mm, ss); + break; + } + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_encode")); + gtk_label_set_text(label, str); + g_free(str); + + const char * path; + struct stat stbuf; + + path = ghb_dict_get_string(uiDict, "destination"); + if (g_stat(path, &stbuf) == 0) + { + const char * units = _("B"); + double size = stbuf.st_size; + if (size > 1024) + { + units = _("KB"); + size /= 1024.0; + } + if (size > 1024) + { + units = _("MB"); + size /= 1024.0; + } + if (size > 1024) + { + units = _("GB"); + size /= 1024.0; + } + str = g_strdup_printf("%.2f %s", size, units); + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_file_size")); + gtk_label_set_text(label, str); + g_free(str); + } + else + { + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_file_size")); + gtk_label_set_text(label, _("Error")); + } + + label = GTK_LABEL(GHB_WIDGET(ud->builder, "queue_stats_result")); + gtk_label_set_text(label, result); +} + +void ghb_queue_update_status_icon(signal_user_data_t *ud, int index) { int count = ghb_array_len(ud->queue); @@ -2376,7 +2761,7 @@ queue_drag_motion_cb( } G_MODULE_EXPORT void -queue_drag_cb( +queue_drop_cb( GtkListBox * lb, GdkDragContext * ctx, gint x, diff --git a/gtk/src/queuehandler.h b/gtk/src/queuehandler.h index 55a6a6e88..0814209f0 100644 --- a/gtk/src/queuehandler.h +++ b/gtk/src/queuehandler.h @@ -27,6 +27,7 @@ #include <gtk/gtk.h> #include "settings.h" +#include "hb-backend.h" void ghb_queue_buttons_grey(signal_user_data_t *ud); gboolean ghb_reload_queue(signal_user_data_t *ud); @@ -41,5 +42,7 @@ void ghb_queue_progress_set_fraction(signal_user_data_t *ud, int index, void ghb_queue_update_status(signal_user_data_t *ud, int index, int status); void ghb_queue_update_status_icon(signal_user_data_t *ud, int index); void ghb_queue_select_log(signal_user_data_t * ud); +void ghb_queue_update_live_stats(signal_user_data_t * ud, int index, + ghb_instance_status_t * status); #endif // _QUEUEHANDLER_H_ |