/* Subtitles.cs $ This file is part of the HandBrake source code. Homepage: . It may be used under the terms of the GNU General Public License. */ namespace Handbrake.Controls { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Windows.Forms; using Functions; using HandBrake.ApplicationServices.Model; using Model; /// /// The Subtitles Tab /// public partial class Subtitles : UserControl { #region Priavate Variables and Collections /// /// Map of languages to language codes /// private readonly IDictionary langMap = new Dictionary(); /// /// A List of SRT Files /// private readonly IDictionary srtFiles = new Dictionary(); /// /// The Subtitle List /// private readonly List subList = new List(); #endregion /// /// Initializes a new instance of the class. /// public Subtitles() { InitializeComponent(); langMap = Main.MapLanguages(); foreach (string key in langMap.Keys) srt_lang.Items.Add(key); srt_charcode.SelectedIndex = 28; srt_lang.SelectedIndex = 40; } #region Public Methods /// /// Gets the CLI Query for this panel /// /// A CliQuery string public string GetCliQuery { get { string query = string.Empty; if (lv_subList.Items.Count != 0) // If we have subtitle tracks { // BitMap and CC's string subtitleTracks = String.Empty; string subtitleForced = String.Empty; string subtitleBurn = String.Empty; string subtitleDefault = String.Empty; // SRT string srtFile = String.Empty; string srtCodeset = String.Empty; string srtOffset = String.Empty; string srtLang = String.Empty; string srtDefault = String.Empty; int srtCount = 0; int subCount = 0; foreach (SubtitleInfo item in subList) { string itemToAdd; if (item.IsSrtSubtitle) // We have an SRT file { srtCount++; // SRT track id. srtLang += srtLang == string.Empty ? langMap[item.SrtLang] : "," + langMap[item.SrtLang]; srtCodeset += srtCodeset == string.Empty ? item.SrtCharCode : "," + item.SrtCharCode; if (item.Default) srtDefault = srtCount.ToString(); itemToAdd = item.SrtPath; srtFile += srtFile == string.Empty ? itemToAdd : "," + itemToAdd; itemToAdd = item.SrtOffset.ToString(); srtOffset += srtOffset == string.Empty ? itemToAdd : "," + itemToAdd; } else // We have Bitmap or CC { subCount++; // Find --subtitle if (item.Track.Contains("Foreign Audio Search")) itemToAdd = "scan"; else { string[] tempSub = item.Track.Split(' '); itemToAdd = tempSub[0]; } subtitleTracks += subtitleTracks == string.Empty ? itemToAdd : "," + itemToAdd; // Find --subtitle-forced if (item.Forced) subtitleForced += subtitleForced == string.Empty ? subCount.ToString() : "," + subCount; // Find --subtitle-burn if (item.Burned) subtitleBurn = subCount.ToString(); // Find --subtitle-default if (item.Default) subtitleDefault = subCount.ToString(); } } // Build The CLI Subtitles Query if (subtitleTracks != string.Empty) { query += " --subtitle " + subtitleTracks; if (subtitleForced != string.Empty) query += " --subtitle-forced=" + subtitleForced; if (subtitleBurn != string.Empty) query += " --subtitle-burn=" + subtitleBurn; if (subtitleDefault != string.Empty) query += " --subtitle-default=" + subtitleDefault; } if (srtFile != string.Empty) // SRTs { query += " --srt-file " + "\"" + srtFile + "\""; if (srtCodeset != string.Empty) query += " --srt-codeset " + srtCodeset; if (srtOffset != string.Empty) query += " --srt-offset " + srtOffset; if (srtLang != string.Empty) query += " --srt-lang " + srtLang; if (srtDefault != string.Empty) query += " --srt-default=" + srtDefault; } } return query; } } /// /// Checks of the current settings will require the m4v file extension /// /// True if Yes public bool RequiresM4V() { return this.subList.Any(track => track.SubtitleType != SubtitleType.VobSub); } /// /// Automatically setup the subtitle tracks. /// This handles the automatic setup of subitles which the user can control from the program options /// /// List of Subtitles public void SetSubtitleTrackAuto(object[] subs) { drp_subtitleTracks.Items.Clear(); drp_subtitleTracks.Items.Add("Foreign Audio Search (Bitmap)"); drp_subtitleTracks.Items.AddRange(subs); drp_subtitleTracks.SelectedIndex = 0; Clear(); this.AutomaticSubtitleSelection(); } /// /// Automatic Subtitle Selection based on user preferences. /// public void AutomaticSubtitleSelection() { // Handle Native Language and "Dub Foreign language audio" and "Use Foreign language audio and Subtitles" Options if (Properties.Settings.Default.NativeLanguage != "Any") { if (Properties.Settings.Default.DubMode != 1) // We need to add a subtitle track if this is false. { foreach (object item in drp_subtitleTracks.Items) { if (item.ToString().Contains(Properties.Settings.Default.NativeLanguage)) { drp_subtitleTracks.SelectedItem = item; BtnAddSubTrackClick(this, new EventArgs()); } } if (drp_subtitleTracks.SelectedIndex == 0 && Properties.Settings.Default.useClosedCaption) { foreach (object item in drp_subtitleTracks.Items) { if (item.ToString().Contains("Closed")) { drp_subtitleTracks.SelectedItem = item; BtnAddSubTrackClick(this, new EventArgs()); } } } } } } /// /// Clear the Subtitle List /// public void Clear() { lv_subList.Items.Clear(); subList.Clear(); } #endregion #region Primary Controls /// /// Add a Subtitle track. /// /// /// The sender. /// /// /// The e. /// private void BtnAddSubTrackClick(object sender, EventArgs e) { // Logic string forcedVal = check_forced.CheckState == CheckState.Checked ? "Yes" : "No"; string defaultSub = check_default.CheckState == CheckState.Checked ? "Yes" : "No"; string burnedVal = check_burned.CheckState == CheckState.Checked && (drp_subtitleTracks.Text.Contains("(VOBSUB)") || drp_subtitleTracks.Text.Contains("(SSA)")) ? "Yes" : "No"; string srtCode = "-", srtLangVal = "-", srtPath = "-", srtFile = "-"; int srtOffsetMs = 0; if (drp_subtitleTracks.SelectedItem.ToString().Contains(".srt")) { srtFiles.TryGetValue(drp_subtitleTracks.SelectedItem.ToString(), out srtPath); srtFile = drp_subtitleTracks.SelectedItem.ToString(); srtLangVal = srt_lang.SelectedItem.ToString(); srtCode = srt_charcode.SelectedItem.ToString(); srtOffsetMs = (int)srt_offset.Value; if (defaultSub == "Yes") this.SetDefaultToOffForAllSRTTracks(); } else { if (defaultSub == "Yes") this.SetDefaultToOffForAllTracks(); if (burnedVal == "Yes") this.SetBurnedToOffForAllTracks(); } string trackName = (drp_subtitleTracks.SelectedItem.ToString().Contains(".srt")) ? srtLangVal + " (" + srtFile + ")" : drp_subtitleTracks.SelectedItem.ToString(); SubtitleInfo track = new SubtitleInfo { Track = trackName, Forced = check_forced.Checked, Burned = check_burned.Checked, Default = check_default.Checked, SrtLang = srtLangVal, SrtCharCode = srtCode, SrtOffset = srtOffsetMs, SrtPath = srtPath, SrtFileName = srtFile }; lv_subList.Items.Add(track.ListView); subList.Add(track); } /// /// Import an SRT Subtitle Track /// /// /// The sender. /// /// /// The e. /// private void BtnSrtAddClick(object sender, EventArgs e) { if (openFileDialog.ShowDialog() != DialogResult.OK) return; if (srtFiles.ContainsKey(Path.GetFileName(openFileDialog.FileName))) { MessageBox.Show( "A Subtitle track with the same name has already been imported.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } drp_subtitleTracks.Items.Add(Path.GetFileName(openFileDialog.FileName)); drp_subtitleTracks.SelectedItem = Path.GetFileName(openFileDialog.FileName); srtFiles.Add(Path.GetFileName(openFileDialog.FileName), openFileDialog.FileName); } /// /// Remove a subtitle track /// /// /// The sender. /// /// /// The e. /// private void BtnRemoveSubTrackClick(object sender, EventArgs e) { this.RemoveSelectedTrack(); } /// /// The Subtitle List selected index has changed /// /// /// The sender. /// /// /// The e. /// private void LbSubListSelectedIndexChanged(object sender, EventArgs e) { // Set the dropdown controls based on the selected item in the List. if (lv_subList.Items.Count != 0 && lv_subList.SelectedIndices.Count != 0) { SubtitleInfo track = subList[lv_subList.SelectedIndices[0]]; int c = 0; if (lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[0].Text.ToLower().Contains(".srt")) // We have an SRT { foreach (var item in drp_subtitleTracks.Items) { if (item.ToString() == track.SrtFileName) drp_subtitleTracks.SelectedIndex = c; c++; } srt_lang.SelectedItem = track.SrtLang; srt_offset.Value = track.SrtOffset; srt_charcode.SelectedItem = track.SrtCharCode; check_default.CheckState = track.Default ? CheckState.Checked : CheckState.Unchecked; SubGroupBox.Text = "Selected Track: " + track.Track; } else // We have Bitmap/CC { foreach (var item in drp_subtitleTracks.Items) { if (item.ToString() == track.Track) drp_subtitleTracks.SelectedIndex = c; c++; } check_forced.CheckState = track.Forced ? CheckState.Checked : CheckState.Unchecked; check_burned.CheckState = track.Burned ? CheckState.Checked : CheckState.Unchecked; check_default.CheckState = track.Default ? CheckState.Checked : CheckState.Unchecked; SubGroupBox.Text = "Selected Track: " + lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[0].Text; } } else SubGroupBox.Text = "Selected Track: None (Click \"Add\" to add another track to the list)"; } #endregion #region Subtitle Controls /// /// Handle the Subtitle track dropdown changed event /// /// /// The sender. /// /// /// The e. /// private void DrpSubtitleTracksSelectedIndexChanged(object sender, EventArgs e) { if (drp_subtitleTracks.SelectedItem.ToString().Contains(".srt")) { check_forced.Enabled = false; check_burned.Enabled = false; srt_lang.Enabled = true; srt_charcode.Enabled = true; srt_offset.Enabled = true; } else { check_forced.Enabled = true; check_burned.Enabled = true; srt_lang.Enabled = false; srt_charcode.Enabled = false; srt_offset.Enabled = false; } // Update an item in the list if required. if (lv_subList.Items.Count == 0 || lv_subList.SelectedIndices.Count == 0) return; if (drp_subtitleTracks.SelectedItem.ToString().Contains(".srt")) { lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[0].Text = srt_lang.SelectedItem + "(" + drp_subtitleTracks.SelectedItem + ")"; lv_subList.Select(); string srtPath; srtFiles.TryGetValue(drp_subtitleTracks.SelectedItem.ToString(), out srtPath); subList[lv_subList.SelectedIndices[0]].SrtPath = srtPath; } else { lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[0].Text = drp_subtitleTracks.SelectedItem.ToString(); lv_subList.Select(); } subList[lv_subList.SelectedIndices[0]].Track = drp_subtitleTracks.SelectedItem.ToString(); } /// /// Foreced Subtitles checkbox changed /// /// /// The sender. /// /// /// The e. /// private void CheckForcedCheckedChanged(object sender, EventArgs e) { if (lv_subList.Items.Count == 0 || lv_subList.SelectedIndices.Count == 0) return; lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[1].Text = check_forced.Checked ? "Yes" : "No"; lv_subList.Select(); subList[lv_subList.SelectedIndices[0]].Forced = check_forced.Checked; // Update SubList List } /// /// Burned in subtitles checkbox changed /// /// /// The sender. /// /// /// The e. /// private void CheckBurnedCheckedChanged(object sender, EventArgs e) { if (lv_subList.Items.Count == 0 || lv_subList.SelectedIndices.Count == 0) return; if (check_burned.Checked) // Make sure we only have 1 burned track this.SetBurnedToOffForAllTracks(); lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[2].Text = check_burned.Checked ? "Yes" : "No"; lv_subList.Select(); subList[lv_subList.SelectedIndices[0]].Burned = check_burned.Checked; // Update SubList List } /// /// Default Subitle track check changed /// /// /// The sender. /// /// /// The e. /// private void CheckDefaultCheckedChanged(object sender, EventArgs e) { if (lv_subList.Items.Count == 0 || lv_subList.SelectedIndices.Count == 0) return; if (check_default.Checked) // Make sure we only have 1 default track if (lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[0].Text.Contains(".srt")) this.SetDefaultToOffForAllSRTTracks(); else this.SetDefaultToOffForAllTracks(); lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[3].Text = check_default.Checked ? "Yes" : "No"; lv_subList.Select(); subList[lv_subList.SelectedIndices[0]].Default = check_default.Checked; // Update SubList List } /// /// Srt Offset Numeric Control Changed /// /// /// The sender. /// /// /// The e. /// private void SrtOffsetValueChanged(object sender, EventArgs e) { // Update an item in the list if required. if (lv_subList.Items.Count == 0 || lv_subList.SelectedIndices.Count == 0) return; lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[6].Text = srt_offset.Value.ToString(); lv_subList.Select(); subList[lv_subList.SelectedIndices[0]].SrtOffset = (int)srt_offset.Value; // Update SubList List } /// /// The SRT Charcode changed /// /// /// The sender. /// /// /// The e. /// private void SrtCharcodeSelectedIndexChanged(object sender, EventArgs e) { if (lv_subList.Items.Count == 0 || lv_subList.SelectedIndices.Count == 0) return; lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[5].Text = srt_charcode.SelectedItem.ToString(); lv_subList.Select(); subList[lv_subList.SelectedIndices[0]].SrtCharCode = srt_charcode.SelectedItem.ToString(); // Update SubList List } /// /// The Srt Language code changed /// /// /// The sender. /// /// /// The e. /// private void SrtLangSelectedIndexChanged(object sender, EventArgs e) { if (lv_subList.Items.Count == 0 || lv_subList.SelectedIndices.Count == 0) return; lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[4].Text = srt_lang.SelectedItem.ToString(); lv_subList.Select(); subList[lv_subList.SelectedIndices[0]].SrtLang = srt_lang.SelectedItem.ToString(); // Update SubList List } #endregion #region Right Click Menu /// /// Move an item in the subtitle list up /// /// /// The sender. /// /// /// The e. /// private void MnuMoveupClick(object sender, EventArgs e) { if (lv_subList.SelectedIndices.Count != 0) { ListViewItem item = lv_subList.SelectedItems[0]; int index = item.Index; index--; if (lv_subList.Items.Count > index && index >= 0) { lv_subList.Items.Remove(item); lv_subList.Items.Insert(index, item); item.Selected = true; lv_subList.Focus(); } } } /// /// Move an item in the subtitle list down /// /// /// The sender. /// /// /// The e. /// private void MnuMovedownClick(object sender, EventArgs e) { if (lv_subList.SelectedIndices.Count != 0) { ListViewItem item = lv_subList.SelectedItems[0]; int index = item.Index; index++; if (index < lv_subList.Items.Count) { lv_subList.Items.Remove(item); lv_subList.Items.Insert(index, item); item.Selected = true; lv_subList.Focus(); } } } /// /// Remove a selected subtitle track. /// /// /// The sender. /// /// /// The e. /// private void MnuRemoveClick(object sender, EventArgs e) { this.RemoveSelectedTrack(); } #endregion #region Helpers /// /// Set all Non SRT tracks to Default = NO /// private void SetDefaultToOffForAllTracks() { int c = 0; foreach (ListViewItem item in lv_subList.Items) { if (subList[c].SrtPath == "-") { if (item.SubItems[3].Text == "Yes") { item.SubItems[3].Text = "No"; subList[c].Default = false; } } c++; } } /// /// Set all subtitle tracks so that they have no default. /// private void SetDefaultToOffForAllSRTTracks() { int c = 0; foreach (ListViewItem item in lv_subList.Items) { if (!subList[c].IsSrtSubtitle) { if (item.SubItems[3].Text == "Yes") { item.SubItems[3].Text = "No"; subList[c].Default = false; } } c++; } } /// /// Set all tracks to Burned = No /// private void SetBurnedToOffForAllTracks() { int c = 0; foreach (ListViewItem item in lv_subList.Items) { if (item.SubItems[2].Text == "Yes") { item.SubItems[2].Text = "No"; subList[c].Burned = false; } c++; } } /// /// Remove a selected track /// private void RemoveSelectedTrack() { // Remove the Item and reselect the control if the following conditions are met. if (lv_subList.SelectedItems.Count != 0) { // Record the current selected index. int currentPosition = lv_subList.SelectedIndices[0]; int selectedInd = lv_subList.SelectedIndices[0]; lv_subList.Items.RemoveAt(selectedInd); subList.RemoveAt(selectedInd); // Now reslect the correct item and give focus to the list. if (lv_subList.Items.Count != 0) { if (currentPosition <= (lv_subList.Items.Count - 1)) lv_subList.Items[currentPosition].Selected = true; else if (currentPosition > (lv_subList.Items.Count - 1)) lv_subList.Items[lv_subList.Items.Count - 1].Selected = true; lv_subList.Select(); } } } #endregion } }