2 This file is part of the HandBrake source code.
\r
3 Homepage: <http://handbrake.fr/>.
\r
4 It may be used under the terms of the GNU General Public License. */
\r
9 using System.Collections.Generic;
\r
10 using System.ComponentModel;
\r
11 using System.Diagnostics;
\r
12 using System.Drawing;
\r
13 using System.Globalization;
\r
15 using System.Reflection;
\r
16 using System.Threading;
\r
17 using System.Windows.Forms;
\r
25 public partial class frmMain : Form
\r
27 // Objects which may be used by one or more other objects *************
\r
28 private Queue encodeQueue = new Queue();
\r
29 private PresetsHandler presetHandler = new PresetsHandler();
\r
31 // Globals: Mainly used for tracking. *********************************
\r
32 public Title selectedTitle;
\r
33 private frmQueue queueWindow;
\r
34 private frmPreview qtpreview;
\r
35 private frmActivityWindow ActivityWindow;
\r
36 private Form splash;
\r
37 public string sourcePath;
\r
38 private ActivityLogMode lastAction;
\r
39 private SourceType selectedSourceType;
\r
40 private string dvdDrivePath;
\r
41 private string dvdDriveLabel;
\r
42 private Preset CurrentlySelectedPreset;
\r
43 private DVD currentSource;
\r
44 private Scan SourceScan = new Scan();
\r
45 private List<DriveInformation> drives;
\r
47 // Delegates **********************************************************
\r
48 private delegate void UpdateWindowHandler();
\r
50 // Applicaiton Startup ************************************************
\r
52 #region Application Startup
\r
56 // Load and setup the splash screen in this thread
\r
57 splash = new frmSplashScreen();
\r
59 Label lblStatus = new Label { Size = new Size(150, 20), Location = new Point(182, 102) };
\r
60 splash.Controls.Add(lblStatus);
\r
62 InitializeComponent();
\r
64 // Update the users config file with the CLI version data.
\r
65 lblStatus.Text = "Checking CLI Version Data ...";
\r
66 Application.DoEvents();
\r
67 Main.SetCliVersionData();
\r
68 Main.CheckForValidCliVersion();
\r
69 Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
\r
70 this.Text += " " + v.ToString(4);
\r
72 // Show the form, but leave disabled until preloading is complete then show the main form)
\r
73 this.Enabled = false;
\r
75 Application.DoEvents(); // Forces frmMain to draw
\r
77 // Check for new versions, if update checking is enabled
\r
78 if (Properties.Settings.Default.updateStatus)
\r
80 DateTime now = DateTime.Now;
\r
81 DateTime lastCheck = Properties.Settings.Default.lastUpdateCheckDate;
\r
82 TimeSpan elapsed = now.Subtract(lastCheck);
\r
83 if (elapsed.TotalDays > Properties.Settings.Default.daysBetweenUpdateCheck)
\r
85 lblStatus.Text = "Checking for updates ...";
\r
86 Application.DoEvents();
\r
88 Main.BeginCheckForUpdates(new AsyncCallback(UpdateCheckDone), false);
\r
92 // Clear the log files in the background
\r
93 if (Properties.Settings.Default.clearOldLogs)
\r
95 lblStatus.Text = "Clearing Old Log Files ...";
\r
96 Application.DoEvents();
\r
97 Thread clearLog = new Thread(Main.ClearOldLogs);
\r
101 // Setup the GUI components
\r
102 lblStatus.Text = "Setting up the GUI ...";
\r
103 Application.DoEvents();
\r
104 LoadPresetPanel(); // Load the Preset Panel
\r
105 treeView_presets.ExpandAll();
\r
106 lbl_encode.Text = string.Empty;
\r
107 drop_mode.SelectedIndex = 0;
\r
108 queueWindow = new frmQueue(encodeQueue, this); // Prepare the Queue
\r
109 if (!Properties.Settings.Default.QueryEditorTab)
\r
110 tabs_panel.TabPages.RemoveAt(7); // Remove the query editor tab if the user does not want it enabled.
\r
112 // Load the user's default settings or Normal Preset
\r
113 if (Properties.Settings.Default.defaultPreset != string.Empty)
\r
115 if (presetHandler.GetPreset(Properties.Settings.Default.defaultPreset) != null)
\r
117 string query = presetHandler.GetPreset(Properties.Settings.Default.defaultPreset).Query;
\r
118 bool loadPictureSettings =
\r
119 presetHandler.GetPreset(Properties.Settings.Default.defaultPreset).PictureSettings;
\r
123 x264Panel.Reset2Defaults();
\r
125 QueryParser presetQuery = QueryParser.Parse(query);
\r
126 PresetLoader.LoadPreset(this, presetQuery, Properties.Settings.Default.defaultPreset,
\r
127 loadPictureSettings);
\r
129 x264Panel.X264_StandardizeOptString();
\r
130 x264Panel.X264_SetCurrentSettingsInPanel();
\r
134 loadNormalPreset();
\r
137 loadNormalPreset();
\r
139 // Enabled GUI tooltip's if Required
\r
140 if (Properties.Settings.Default.tooltipEnable)
\r
141 ToolTip.Active = true;
\r
143 // Register with Growl (if not using Growl for the encoding completion action, this wont hurt anything)
\r
144 GrowlCommunicator.Register();
\r
146 // Finished Loading
\r
147 lblStatus.Text = "Loading Complete!";
\r
148 Application.DoEvents();
\r
151 this.Enabled = true;
\r
153 // Event Handlers and Queue Recovery
\r
158 private void UpdateCheckDone(IAsyncResult result)
\r
160 if (InvokeRequired)
\r
162 Invoke(new MethodInvoker(() => UpdateCheckDone(result)));
\r
166 UpdateCheckInformation info;
\r
170 info = Main.EndCheckForUpdates(result);
\r
172 if (info.NewVersionAvailable)
\r
174 frmUpdater updateWindow = new frmUpdater(info.BuildInformation);
\r
175 updateWindow.ShowDialog();
\r
178 catch (Exception ex)
\r
180 if ((bool)result.AsyncState)
\r
182 "Unable to check for updates, Please try again later.\n\nDetailed Error Information:\n" + ex,
\r
183 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
187 // Startup Functions
\r
188 private void queueRecovery()
\r
190 if (Main.CheckQueueRecovery())
\r
192 DialogResult result =
\r
194 "HandBrake has detected unfinished items on the queue from the last time the application was launched. Would you like to recover these?",
\r
195 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
197 if (result == DialogResult.Yes)
\r
198 encodeQueue.LoadQueueFromFile("hb_queue_recovery.xml"); // Start Recovery
\r
201 // Remove the Queue recovery file if the user doesn't want to recovery the last queue.
\r
202 string queuePath = Path.Combine(Path.GetTempPath(), "hb_queue_recovery.xml");
\r
203 if (File.Exists(queuePath))
\r
204 File.Delete(queuePath);
\r
213 public string SourceName
\r
217 if (this.selectedSourceType == SourceType.DvdDrive)
\r
219 return this.dvdDriveLabel;
\r
222 if (Path.GetFileNameWithoutExtension(this.sourcePath) != "VIDEO_TS")
\r
223 return Path.GetFileNameWithoutExtension(this.sourcePath);
\r
225 return Path.GetFileNameWithoutExtension(Path.GetDirectoryName(this.sourcePath));
\r
233 // Encoding Events for setting up the GUI
\r
234 private void events()
\r
236 // Handle Widget changes when preset is selected.
\r
237 RegisterPresetEventHandler();
\r
239 // Handle Window Resize
\r
240 if (Properties.Settings.Default.MainWindowMinimize)
\r
241 this.Resize += new EventHandler(frmMain_Resize);
\r
243 // Handle Encode Start / Finish / Pause
\r
245 encodeQueue.QueuePauseRequested += new EventHandler(encodePaused);
\r
246 encodeQueue.EncodeStarted += new EventHandler(encodeStarted);
\r
247 encodeQueue.EncodeEnded += new EventHandler(encodeEnded);
\r
249 // Handle a file being draged onto the GUI.
\r
250 this.DragEnter += new DragEventHandler(frmMain_DragEnter);
\r
251 this.DragDrop += new DragEventHandler(frmMain_DragDrop);
\r
254 // Change the preset label to custom when a user changes a setting. Don't want to give the impression that users can change settings and still be using a preset
\r
255 private void RegisterPresetEventHandler()
\r
258 drop_format.SelectedIndexChanged += new EventHandler(changePresetLabel);
\r
259 check_largeFile.CheckedChanged += new EventHandler(changePresetLabel);
\r
260 check_iPodAtom.CheckedChanged += new EventHandler(changePresetLabel);
\r
261 check_optimiseMP4.CheckedChanged += new EventHandler(changePresetLabel);
\r
263 // Picture Settings
\r
264 // PictureSettings.PictureSettingsChanged += new EventHandler(changePresetLabel);
\r
267 Filters.FilterSettingsChanged += new EventHandler(changePresetLabel);
\r
270 drp_videoEncoder.SelectedIndexChanged += new EventHandler(changePresetLabel);
\r
271 check_2PassEncode.CheckedChanged += new EventHandler(changePresetLabel);
\r
272 check_turbo.CheckedChanged += new EventHandler(changePresetLabel);
\r
273 text_filesize.TextChanged += new EventHandler(changePresetLabel);
\r
274 text_bitrate.TextChanged += new EventHandler(changePresetLabel);
\r
275 slider_videoQuality.ValueChanged += new EventHandler(changePresetLabel);
\r
278 AudioSettings.AudioListChanged += new EventHandler(changePresetLabel);
\r
281 x264Panel.rtf_x264Query.TextChanged += new EventHandler(changePresetLabel);
\r
284 private void UnRegisterPresetEventHandler()
\r
286 // Output Settings
\r
287 drop_format.SelectedIndexChanged -= new EventHandler(changePresetLabel);
\r
288 check_largeFile.CheckedChanged -= new EventHandler(changePresetLabel);
\r
289 check_iPodAtom.CheckedChanged -= new EventHandler(changePresetLabel);
\r
290 check_optimiseMP4.CheckedChanged -= new EventHandler(changePresetLabel);
\r
292 // Picture Settings
\r
293 // PictureSettings.PictureSettingsChanged -= new EventHandler(changePresetLabel);
\r
296 Filters.FilterSettingsChanged -= new EventHandler(changePresetLabel);
\r
299 drp_videoEncoder.SelectedIndexChanged -= new EventHandler(changePresetLabel);
\r
300 check_2PassEncode.CheckedChanged -= new EventHandler(changePresetLabel);
\r
301 check_turbo.CheckedChanged -= new EventHandler(changePresetLabel);
\r
302 text_filesize.TextChanged -= new EventHandler(changePresetLabel);
\r
303 text_bitrate.TextChanged -= new EventHandler(changePresetLabel);
\r
304 slider_videoQuality.ValueChanged -= new EventHandler(changePresetLabel);
\r
307 AudioSettings.AudioListChanged -= new EventHandler(changePresetLabel);
\r
310 x264Panel.rtf_x264Query.TextChanged -= new EventHandler(changePresetLabel);
\r
313 private void changePresetLabel(object sender, EventArgs e)
\r
315 labelPreset.Text = "Output Settings (Preset: Custom)";
\r
316 CurrentlySelectedPreset = null;
\r
319 private static void frmMain_DragEnter(object sender, DragEventArgs e)
\r
321 if (e.Data.GetDataPresent(DataFormats.FileDrop, false))
\r
322 e.Effect = DragDropEffects.All;
\r
325 private void frmMain_DragDrop(object sender, DragEventArgs e)
\r
327 string[] fileList = e.Data.GetData(DataFormats.FileDrop) as string[];
\r
328 sourcePath = string.Empty;
\r
330 if (fileList != null)
\r
332 if (fileList[0] != string.Empty)
\r
334 this.selectedSourceType = SourceType.VideoFile;
\r
335 StartScan(fileList[0], 0);
\r
338 UpdateSourceLabel();
\r
341 UpdateSourceLabel();
\r
344 private void encodeStarted(object sender, EventArgs e)
\r
346 lastAction = ActivityLogMode.Encode;
\r
347 SetEncodeStarted();
\r
349 // Experimental HBProc Process Monitoring.
\r
350 if (Properties.Settings.Default.enocdeStatusInGui)
\r
352 Thread encodeMon = new Thread(EncodeMonitorThread);
\r
357 private void encodeEnded(object sender, EventArgs e)
\r
359 SetEncodeFinished();
\r
362 private void encodePaused(object sender, EventArgs e)
\r
364 SetEncodeFinished();
\r
369 // User Interface Menus / Tool Strips *********************************
\r
373 private void mnu_killCLI_Click(object sender, EventArgs e)
\r
378 private void mnu_exit_Click(object sender, EventArgs e)
\r
380 Application.Exit();
\r
387 private void mnu_encode_Click(object sender, EventArgs e)
\r
389 queueWindow.Show();
\r
392 private void mnu_encodeLog_Click(object sender, EventArgs e)
\r
394 frmActivityWindow dvdInfoWindow = new frmActivityWindow(lastAction, encodeQueue, SourceScan);
\r
395 dvdInfoWindow.Show();
\r
398 private void mnu_options_Click(object sender, EventArgs e)
\r
400 Form options = new frmOptions(this);
\r
401 options.ShowDialog();
\r
406 #region Presets Menu
\r
408 private void mnu_presetReset_Click(object sender, EventArgs e)
\r
410 presetHandler.UpdateBuiltInPresets();
\r
412 if (treeView_presets.Nodes.Count == 0)
\r
414 "Unable to load the presets.xml file. Please select \"Update Built-in Presets\" from the Presets Menu. \nMake sure you are running the program in Admin mode if running on Vista. See Windows FAQ for details!",
\r
415 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
417 MessageBox.Show("Presets have been updated!", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
419 treeView_presets.ExpandAll();
\r
422 private void mnu_delete_preset_Click(object sender, EventArgs e)
\r
424 presetHandler.RemoveBuiltInPresets();
\r
425 LoadPresetPanel(); // Reload the preset panel
\r
428 private void mnu_SelectDefault_Click(object sender, EventArgs e)
\r
430 loadNormalPreset();
\r
433 private void mnu_importMacPreset_Click(object sender, EventArgs e)
\r
438 private void btn_new_preset_Click(object sender, EventArgs e)
\r
440 Form preset = new frmAddPreset(this, QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
442 preset.ShowDialog();
\r
449 private void mnu_user_guide_Click(object sender, EventArgs e)
\r
451 Process.Start("http://trac.handbrake.fr/wiki/HandBrakeGuide");
\r
454 private void mnu_handbrake_home_Click(object sender, EventArgs e)
\r
456 Process.Start("http://handbrake.fr");
\r
459 private void mnu_UpdateCheck_Click(object sender, EventArgs e)
\r
461 lbl_updateCheck.Visible = true;
\r
462 Main.BeginCheckForUpdates(new AsyncCallback(updateCheckDoneMenu), false);
\r
465 private void updateCheckDoneMenu(IAsyncResult result)
\r
467 // Make sure it's running on the calling thread
\r
468 if (InvokeRequired)
\r
470 Invoke(new MethodInvoker(() => updateCheckDoneMenu(result)));
\r
473 UpdateCheckInformation info;
\r
476 // Get the information about the new build, if any, and close the window
\r
477 info = Main.EndCheckForUpdates(result);
\r
479 if (info.NewVersionAvailable && info.BuildInformation != null)
\r
481 frmUpdater updateWindow = new frmUpdater(info.BuildInformation);
\r
482 updateWindow.ShowDialog();
\r
485 MessageBox.Show("There are no new updates at this time.", "Update Check", MessageBoxButtons.OK,
\r
486 MessageBoxIcon.Information);
\r
487 lbl_updateCheck.Visible = false;
\r
490 catch (Exception ex)
\r
492 if ((bool)result.AsyncState)
\r
494 "Unable to check for updates, Please try again later.\n\nDetailed Error Information:\n" + ex,
\r
495 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
499 private void mnu_about_Click(object sender, EventArgs e)
\r
501 using (frmAbout About = new frmAbout())
\r
503 About.ShowDialog();
\r
511 // Right Click Menu Code
\r
512 private void pmnu_expandAll_Click(object sender, EventArgs e)
\r
514 treeView_presets.ExpandAll();
\r
517 private void pmnu_collapse_Click(object sender, EventArgs e)
\r
519 treeView_presets.CollapseAll();
\r
522 private void pmnu_import_Click(object sender, EventArgs e)
\r
527 private void pmnu_saveChanges_Click(object sender, EventArgs e)
\r
529 DialogResult result =
\r
531 "Do you wish to include picture settings when updating the preset: " +
\r
532 treeView_presets.SelectedNode.Text, "Update Preset", MessageBoxButtons.YesNoCancel,
\r
533 MessageBoxIcon.Question);
\r
534 if (result == DialogResult.Yes)
\r
535 presetHandler.Update(treeView_presets.SelectedNode.Text,
\r
536 QueryGenerator.GenerateTabbedComponentsQuery(this), true);
\r
537 else if (result == DialogResult.No)
\r
538 presetHandler.Update(treeView_presets.SelectedNode.Text,
\r
539 QueryGenerator.GenerateTabbedComponentsQuery(this), false);
\r
542 private void pmnu_delete_click(object sender, EventArgs e)
\r
544 if (treeView_presets.SelectedNode != null)
\r
546 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
547 treeView_presets.Nodes.Remove(treeView_presets.SelectedNode);
\r
549 treeView_presets.Select();
\r
552 private void presets_menu_Opening(object sender, CancelEventArgs e)
\r
554 // Make sure that the save menu is always disabled by default
\r
555 pmnu_saveChanges.Enabled = false;
\r
557 // Now enable the save menu if the selected preset is a user preset
\r
558 if (treeView_presets.SelectedNode != null)
\r
559 if (presetHandler.CheckIfUserPresetExists(treeView_presets.SelectedNode.Text))
\r
560 pmnu_saveChanges.Enabled = true;
\r
562 treeView_presets.Select();
\r
565 // Presets Management
\r
566 private void btn_addPreset_Click(object sender, EventArgs e)
\r
568 Form preset = new frmAddPreset(this, QueryGenerator.GenerateTabbedComponentsQuery(this), presetHandler);
\r
569 preset.ShowDialog();
\r
572 private void btn_removePreset_Click(object sender, EventArgs e)
\r
574 DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected preset?", "Preset",
\r
575 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
576 if (result == DialogResult.Yes)
\r
578 if (treeView_presets.SelectedNode != null)
\r
580 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
581 treeView_presets.Nodes.Remove(treeView_presets.SelectedNode);
\r
584 treeView_presets.Select();
\r
587 private void btn_setDefault_Click(object sender, EventArgs e)
\r
589 if (treeView_presets.SelectedNode != null)
\r
591 DialogResult result = MessageBox.Show("Are you sure you wish to set this preset as the default?",
\r
592 "Preset", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
593 if (result == DialogResult.Yes)
\r
595 Properties.Settings.Default.defaultPreset = treeView_presets.SelectedNode.Text;
\r
596 Properties.Settings.Default.Save();
\r
597 MessageBox.Show("New default preset set.", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
601 MessageBox.Show("Please select a preset first.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
604 private void treeview_presets_mouseUp(object sender, MouseEventArgs e)
\r
606 if (e.Button == MouseButtons.Right)
\r
607 treeView_presets.SelectedNode = treeView_presets.GetNodeAt(e.Location);
\r
608 else if (e.Button == MouseButtons.Left)
\r
610 if (treeView_presets.GetNodeAt(e.Location) != null)
\r
612 if (labelPreset.Text.Contains(treeView_presets.GetNodeAt(e.Location).Text))
\r
617 treeView_presets.Select();
\r
620 private void treeView_presets_AfterSelect(object sender, TreeViewEventArgs e)
\r
625 private void treeView_presets_deleteKey(object sender, KeyEventArgs e)
\r
627 if (e.KeyCode == Keys.Delete)
\r
629 DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected preset?", "Preset",
\r
630 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
631 if (result == DialogResult.Yes)
\r
633 if (treeView_presets.SelectedNode != null)
\r
634 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
636 // Remember each nodes expanded status so we can reload it
\r
637 List<bool> nodeStatus = new List<bool>();
\r
638 foreach (TreeNode node in treeView_presets.Nodes)
\r
639 nodeStatus.Add(node.IsExpanded);
\r
641 // Now reload the preset panel
\r
644 // And finally, re-expand any of the nodes if required
\r
646 foreach (TreeNode node in treeView_presets.Nodes)
\r
657 private void selectPreset()
\r
659 if (treeView_presets.SelectedNode != null)
\r
661 // Ok, so, we've selected a preset. Now we want to load it.
\r
662 string presetName = treeView_presets.SelectedNode.Text;
\r
663 Preset preset = presetHandler.GetPreset(presetName);
\r
664 if (preset != null)
\r
666 string query = presetHandler.GetPreset(presetName).Query;
\r
667 bool loadPictureSettings = presetHandler.GetPreset(presetName).PictureSettings;
\r
671 // Ok, Reset all the H264 widgets before changing the preset
\r
672 x264Panel.Reset2Defaults();
\r
674 // Send the query from the file to the Query Parser class
\r
675 QueryParser presetQuery = QueryParser.Parse(query);
\r
677 // Now load the preset
\r
678 PresetLoader.LoadPreset(this, presetQuery, presetName, loadPictureSettings);
\r
680 // The x264 widgets will need updated, so do this now:
\r
681 x264Panel.X264_StandardizeOptString();
\r
682 x264Panel.X264_SetCurrentSettingsInPanel();
\r
684 // Finally, let this window have a copy of the preset settings.
\r
685 CurrentlySelectedPreset = preset;
\r
686 PictureSettings.SetPresetCropWarningLabel(preset);
\r
692 private void loadNormalPreset()
\r
694 foreach (TreeNode treenode in treeView_presets.Nodes)
\r
696 foreach (TreeNode node in treenode.Nodes)
\r
698 if (node.Text.Equals("Normal"))
\r
699 treeView_presets.SelectedNode = treeView_presets.Nodes[treenode.Index].Nodes[0];
\r
704 private void ImportPreset()
\r
706 if (openPreset.ShowDialog() == DialogResult.OK)
\r
708 QueryParser parsed = PlistPresetHandler.Import(openPreset.FileName);
\r
709 if (presetHandler.CheckIfUserPresetExists(parsed.PresetName + " (Imported)"))
\r
711 DialogResult result =
\r
712 MessageBox.Show("This preset appears to already exist. Would you like to overwrite it?",
\r
713 "Overwrite preset?",
\r
714 MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
\r
715 if (result == DialogResult.Yes)
\r
717 PresetLoader.LoadPreset(this, parsed, parsed.PresetName, parsed.UsesPictureSettings);
\r
718 presetHandler.Update(parsed.PresetName + " (Imported)",
\r
719 QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
720 parsed.UsesPictureSettings);
\r
725 PresetLoader.LoadPreset(this, parsed, parsed.PresetName, parsed.UsesPictureSettings);
\r
726 if (presetHandler.Add(parsed.PresetName + " (Imported)",
\r
727 QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
728 parsed.UsesPictureSettings))
\r
730 TreeNode preset_treeview = new TreeNode(parsed.PresetName + " (Imported)")
\r
732 ForeColor = Color.Black
\r
734 treeView_presets.Nodes.Add(preset_treeview);
\r
744 private void btn_source_Click(object sender, EventArgs e)
\r
746 // Remove old Drive Menu Items.
\r
747 List<ToolStripMenuItem> itemsToRemove = new List<ToolStripMenuItem>();
\r
748 foreach (var item in btn_source.DropDownItems)
\r
750 if (item.GetType() == typeof(ToolStripMenuItem))
\r
752 ToolStripMenuItem menuItem = (ToolStripMenuItem)item;
\r
753 if (menuItem.Name.StartsWith("Drive"))
\r
755 itemsToRemove.Add(menuItem);
\r
760 foreach (ToolStripMenuItem item in itemsToRemove)
\r
761 btn_source.DropDownItems.Remove(item);
\r
763 Thread driveInfoThread = new Thread(SetDriveSelectionMenuItem);
\r
764 driveInfoThread.Start();
\r
767 private void btn_start_Click(object sender, EventArgs e)
\r
769 if (btn_start.Text == "Stop")
\r
771 DialogResult result;
\r
772 if (Properties.Settings.Default.enocdeStatusInGui &&
\r
773 !Properties.Settings.Default.showCliForInGuiEncodeStatus)
\r
775 result = MessageBox.Show(
\r
776 "Are you sure you wish to cancel the encode?\n\nPlease note, when 'Enable in-GUI encode status' is enabled, stopping this encode will render the file unplayable. ",
\r
777 "Cancel Encode?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
781 result = MessageBox.Show("Are you sure you wish to cancel the encode?", "Cancel Encode?",
\r
782 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
785 if (result == DialogResult.Yes)
\r
788 encodeQueue.Pause();
\r
790 if (Properties.Settings.Default.enocdeStatusInGui &&
\r
791 !Properties.Settings.Default.showCliForInGuiEncodeStatus)
\r
793 encodeQueue.Stop();
\r
794 if (encodeQueue.HbProcess != null)
\r
795 encodeQueue.HbProcess.WaitForExit();
\r
799 encodeQueue.SafelyClose();
\r
803 SetEncodeFinished();
\r
808 if (encodeQueue.Count != 0 ||
\r
809 (!string.IsNullOrEmpty(sourcePath) && !string.IsNullOrEmpty(text_destination.Text)))
\r
811 string generatedQuery = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
812 string specifiedQuery = rtf_query.Text != string.Empty
\r
814 : QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
815 string query = string.Empty;
\r
817 // Check to make sure the generated query matches the GUI settings
\r
818 if (Properties.Settings.Default.PromptOnUnmatchingQueries && !string.IsNullOrEmpty(specifiedQuery) &&
\r
819 generatedQuery != specifiedQuery)
\r
821 DialogResult result = MessageBox.Show("The query under the \"Query Editor\" tab " +
\r
822 "does not match the current GUI settings.\n\nBecause the manual query takes " +
\r
823 "priority over the GUI, your recently updated settings will not be taken " +
\r
824 "into account when encoding this job." +
\r
825 Environment.NewLine + Environment.NewLine +
\r
826 "Do you want to replace the manual query with the updated GUI-generated query?",
\r
827 "Manual Query does not Match GUI",
\r
828 MessageBoxButtons.YesNoCancel, MessageBoxIcon.Asterisk,
\r
829 MessageBoxDefaultButton.Button3);
\r
833 case DialogResult.Yes:
\r
834 // Replace the manual query with the generated one
\r
835 query = generatedQuery;
\r
836 rtf_query.Text = generatedQuery;
\r
838 case DialogResult.No:
\r
839 // Use the manual query
\r
840 query = specifiedQuery;
\r
842 case DialogResult.Cancel:
\r
843 // Don't start the encode
\r
849 query = specifiedQuery;
\r
852 DialogResult overwrite = DialogResult.Yes;
\r
853 if (text_destination.Text != string.Empty)
\r
854 if (File.Exists(text_destination.Text))
\r
857 "The destination file already exists. Are you sure you want to overwrite it?",
\r
858 "Overwrite File?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
860 if (overwrite == DialogResult.Yes)
\r
862 if (encodeQueue.Count == 0)
\r
863 encodeQueue.Add(query, getTitle(), sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
865 queueWindow.SetQueue();
\r
866 if (encodeQueue.Count > 1)
\r
867 queueWindow.Show(false);
\r
869 SetEncodeStarted(); // Encode is running, so setup the GUI appropriately
\r
870 encodeQueue.Start(); // Start The Queue Encoding Process
\r
871 lastAction = ActivityLogMode.Encode; // Set the last action to encode - Used for activity window.
\r
873 if (ActivityWindow != null)
\r
874 ActivityWindow.SetMode(ActivityLogMode.Encode);
\r
878 else if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
879 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
880 MessageBoxIcon.Warning);
\r
884 private void btn_add2Queue_Click(object sender, EventArgs e)
\r
886 if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
887 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
888 MessageBoxIcon.Warning);
\r
891 string query = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
892 if (rtf_query.Text != string.Empty)
\r
893 query = rtf_query.Text;
\r
895 if (encodeQueue.CheckForDestinationDuplicate(text_destination.Text))
\r
897 DialogResult result =
\r
899 "There is already a queue item for this destination path. \n\n If you continue, the encode will be overwritten. Do you wish to continue?",
\r
900 "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
\r
901 if (result == DialogResult.Yes)
\r
902 encodeQueue.Add(query, getTitle(), sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
905 encodeQueue.Add(query, getTitle(), sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
907 lbl_encode.Text = encodeQueue.Count + " encode(s) pending in the queue";
\r
909 queueWindow.Show();
\r
913 private void btn_showQueue_Click(object sender, EventArgs e)
\r
915 queueWindow.Show();
\r
916 queueWindow.Activate();
\r
919 private void tb_preview_Click(object sender, EventArgs e)
\r
921 if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
922 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
923 MessageBoxIcon.Warning);
\r
926 if (qtpreview == null)
\r
928 qtpreview = new frmPreview(this);
\r
931 else if (qtpreview.IsDisposed)
\r
933 qtpreview = new frmPreview(this);
\r
937 MessageBox.Show(qtpreview, "The preview window is already open!", "Warning", MessageBoxButtons.OK,
\r
938 MessageBoxIcon.Warning);
\r
942 private void btn_ActivityWindow_Click(object sender, EventArgs e)
\r
944 if (ActivityWindow == null || !ActivityWindow.IsHandleCreated)
\r
945 ActivityWindow = new frmActivityWindow(lastAction, encodeQueue, SourceScan);
\r
947 switch (lastAction)
\r
949 case ActivityLogMode.Scan:
\r
950 ActivityWindow.SetMode(ActivityLogMode.Scan);
\r
952 case ActivityLogMode.Encode:
\r
953 ActivityWindow.SetMode(ActivityLogMode.Encode);
\r
956 ActivityWindow.SetMode(ActivityLogMode.Encode);
\r
960 ActivityWindow.Show();
\r
961 ActivityWindow.Activate();
\r
966 #region System Tray Icon
\r
968 private void frmMain_Resize(object sender, EventArgs e)
\r
970 if (FormWindowState.Minimized == this.WindowState)
\r
972 notifyIcon.Visible = true;
\r
975 else if (FormWindowState.Normal == this.WindowState)
\r
976 notifyIcon.Visible = false;
\r
979 private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
\r
981 this.Visible = true;
\r
983 this.WindowState = FormWindowState.Normal;
\r
984 notifyIcon.Visible = false;
\r
987 private void btn_restore_Click(object sender, EventArgs e)
\r
989 this.Visible = true;
\r
991 this.WindowState = FormWindowState.Normal;
\r
992 notifyIcon.Visible = false;
\r
994 this.StartScan(null, 2);
\r
999 #region Tab Control
\r
1002 private void btn_dvd_source_Click(object sender, EventArgs e)
\r
1004 if (DVD_Open.ShowDialog() == DialogResult.OK)
\r
1006 this.selectedSourceType = SourceType.Folder;
\r
1007 SelectSource(DVD_Open.SelectedPath);
\r
1010 UpdateSourceLabel();
\r
1013 private void btn_file_source_Click(object sender, EventArgs e)
\r
1015 if (ISO_Open.ShowDialog() == DialogResult.OK)
\r
1017 this.selectedSourceType = SourceType.VideoFile;
\r
1018 SelectSource(ISO_Open.FileName);
\r
1021 UpdateSourceLabel();
\r
1024 private void mnu_dvd_drive_Click(object sender, EventArgs e)
\r
1026 ToolStripMenuItem item = sender as ToolStripMenuItem;
\r
1029 string driveId = item.Name.Replace("Drive", string.Empty);
\r
1031 if (int.TryParse(driveId, out id))
\r
1034 this.dvdDrivePath = drives[id].RootDirectory;
\r
1035 this.dvdDriveLabel = drives[id].VolumeLabel;
\r
1037 if (this.dvdDrivePath == null) return;
\r
1038 this.selectedSourceType = SourceType.DvdDrive;
\r
1039 SelectSource(this.dvdDrivePath);
\r
1044 private void SelectSource(string file)
\r
1046 Check_ChapterMarkers.Enabled = true;
\r
1047 lastAction = ActivityLogMode.Scan;
\r
1048 sourcePath = string.Empty;
\r
1050 if (file == string.Empty) // Must have a file or path
\r
1052 UpdateSourceLabel();
\r
1056 sourcePath = Path.GetFileName(file);
\r
1057 StartScan(file, 0);
\r
1060 private void drp_dvdtitle_Click(object sender, EventArgs e)
\r
1062 if ((drp_dvdtitle.Items.Count == 1) && (drp_dvdtitle.Items[0].ToString() == "Automatic"))
\r
1064 "There are no titles to select. Please load a source file by clicking the 'Source' button above before trying to select a title.",
\r
1065 "Alert", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
\r
1068 private void drp_dvdtitle_SelectedIndexChanged(object sender, EventArgs e)
\r
1070 UnRegisterPresetEventHandler();
\r
1071 drop_mode.SelectedIndex = 0;
\r
1073 drop_chapterStart.Items.Clear();
\r
1074 drop_chapterFinish.Items.Clear();
\r
1076 // If the dropdown is set to automatic nothing else needs to be done.
\r
1077 // Otheriwse if its not, title data has to be loaded from parsing.
\r
1078 if (drp_dvdtitle.Text != "Automatic")
\r
1080 selectedTitle = drp_dvdtitle.SelectedItem as Title;
\r
1081 lbl_duration.Text = selectedTitle.Duration.ToString();
\r
1082 PictureSettings.CurrentlySelectedPreset = CurrentlySelectedPreset;
\r
1083 PictureSettings.Source = selectedTitle; // Setup Picture Settings Tab Control
\r
1085 // Populate the Angles dropdown
\r
1086 drop_angle.Items.Clear();
\r
1087 if (!Properties.Settings.Default.noDvdNav)
\r
1089 drop_angle.Visible = true;
\r
1090 lbl_angle.Visible = true;
\r
1091 drop_angle.Items.AddRange(selectedTitle.Angles.ToArray());
\r
1092 if (drop_angle.Items.Count != 0)
\r
1093 drop_angle.SelectedIndex = 0;
\r
1097 drop_angle.Visible = false;
\r
1098 lbl_angle.Visible = false;
\r
1101 // Populate the Start chapter Dropdown
\r
1102 drop_chapterStart.Items.Clear();
\r
1103 drop_chapterStart.Items.AddRange(selectedTitle.Chapters.ToArray());
\r
1104 if (drop_chapterStart.Items.Count > 0)
\r
1105 drop_chapterStart.Text = drop_chapterStart.Items[0].ToString();
\r
1107 // Populate the Final Chapter Dropdown
\r
1108 drop_chapterFinish.Items.Clear();
\r
1109 drop_chapterFinish.Items.AddRange(selectedTitle.Chapters.ToArray());
\r
1110 if (drop_chapterFinish.Items.Count > 0)
\r
1111 drop_chapterFinish.Text = drop_chapterFinish.Items[drop_chapterFinish.Items.Count - 1].ToString();
\r
1113 // Populate the Audio Channels Dropdown
\r
1114 AudioSettings.SetTrackList(selectedTitle, CurrentlySelectedPreset);
\r
1116 // Populate the Subtitles dropdown
\r
1117 Subtitles.SetSubtitleTrackAuto(selectedTitle.Subtitles.ToArray());
\r
1119 // Update the source label if we have multiple streams
\r
1120 if (selectedTitle != null)
\r
1121 if (!string.IsNullOrEmpty(selectedTitle.SourceName))
\r
1122 labelSource.Text = labelSource.Text = Path.GetFileName(selectedTitle.SourceName);
\r
1124 // Run the AutoName & ChapterNaming functions
\r
1125 if (Properties.Settings.Default.autoNaming)
\r
1127 string autoPath = Main.AutoName(this);
\r
1128 if (autoPath != null)
\r
1129 text_destination.Text = autoPath;
\r
1132 "You currently have \"Automatically name output files\" enabled for the destination file box, but you do not have a default directory set.\n\nYou should set a \"Default Path\" in HandBrakes preferences. (See 'Tools' menu -> 'Options' -> 'General' Tab -> 'Default Path')",
\r
1133 "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
1136 data_chpt.Rows.Clear();
\r
1137 if (selectedTitle.Chapters.Count != 1)
\r
1139 DataGridView chapterGridView = Main.ChapterNaming(data_chpt, drop_chapterFinish.Text);
\r
1140 if (chapterGridView != null)
\r
1141 data_chpt = chapterGridView;
\r
1145 Check_ChapterMarkers.Checked = false;
\r
1146 Check_ChapterMarkers.Enabled = false;
\r
1149 // Hack to force the redraw of the scrollbars which don't resize properly when the control is disabled.
\r
1150 data_chpt.Columns[0].Width = 166;
\r
1151 data_chpt.Columns[0].Width = 165;
\r
1153 RegisterPresetEventHandler();
\r
1156 private void chapersChanged(object sender, EventArgs e)
\r
1158 if (drop_mode.SelectedIndex != 0) // Function is not used if we are not in chapters mode.
\r
1161 Control ctl = (Control)sender;
\r
1162 int chapterStart, chapterEnd;
\r
1163 int.TryParse(drop_chapterStart.Text, out chapterStart);
\r
1164 int.TryParse(drop_chapterFinish.Text, out chapterEnd);
\r
1168 case "drop_chapterStart":
\r
1169 if (drop_chapterFinish.SelectedIndex == -1 && drop_chapterFinish.Items.Count != 0)
\r
1170 drop_chapterFinish.SelectedIndex = drop_chapterFinish.Items.Count - 1;
\r
1172 if (chapterEnd != 0)
\r
1173 if (chapterStart > chapterEnd)
\r
1174 drop_chapterFinish.Text = chapterStart.ToString();
\r
1176 case "drop_chapterFinish":
\r
1177 if (drop_chapterStart.Items.Count >= 1 && drop_chapterStart.SelectedIndex == -1)
\r
1178 drop_chapterStart.SelectedIndex = 0;
\r
1180 if (chapterStart != 0)
\r
1181 if (chapterEnd < chapterStart)
\r
1182 drop_chapterFinish.Text = chapterStart.ToString();
\r
1184 // Add more rows to the Chapter menu if needed.
\r
1185 if (Check_ChapterMarkers.Checked)
\r
1187 int i = data_chpt.Rows.Count, finish = 0;
\r
1188 int.TryParse(drop_chapterFinish.Text, out finish);
\r
1190 while (i < finish)
\r
1192 int n = data_chpt.Rows.Add();
\r
1193 data_chpt.Rows[n].Cells[0].Value = (i + 1);
\r
1194 data_chpt.Rows[n].Cells[1].Value = "Chapter " + (i + 1);
\r
1195 data_chpt.Rows[n].Cells[0].ValueType = typeof(int);
\r
1196 data_chpt.Rows[n].Cells[1].ValueType = typeof(string);
\r
1203 // Update the Duration
\r
1204 lbl_duration.Text =
\r
1205 Main.CalculateDuration(drop_chapterStart.SelectedIndex, drop_chapterFinish.SelectedIndex, selectedTitle)
\r
1208 // Run the Autonaming function
\r
1209 if (Properties.Settings.Default.autoNaming)
\r
1210 text_destination.Text = Main.AutoName(this);
\r
1212 // Disable chapter markers if only 1 chapter is selected.
\r
1213 if (chapterStart == chapterEnd)
\r
1215 Check_ChapterMarkers.Enabled = false;
\r
1216 btn_importChapters.Enabled = false;
\r
1217 data_chpt.Enabled = false;
\r
1221 Check_ChapterMarkers.Enabled = true;
\r
1222 if (Check_ChapterMarkers.Checked)
\r
1224 btn_importChapters.Enabled = true;
\r
1225 data_chpt.Enabled = true;
\r
1230 private void SecondsOrFramesChanged(object sender, EventArgs e)
\r
1233 int.TryParse(drop_chapterStart.Text, out start);
\r
1234 int.TryParse(drop_chapterFinish.Text, out end);
\r
1235 double duration = end - start;
\r
1237 switch (drop_mode.SelectedIndex)
\r
1240 lbl_duration.Text = TimeSpan.FromSeconds(duration).ToString();
\r
1243 if (selectedTitle != null)
\r
1245 duration = duration / selectedTitle.Fps;
\r
1246 lbl_duration.Text = TimeSpan.FromSeconds(duration).ToString();
\r
1249 lbl_duration.Text = "--:--:--";
\r
1255 private void drop_mode_SelectedIndexChanged(object sender, EventArgs e)
\r
1258 this.drop_chapterFinish.TextChanged -= new EventHandler(this.SecondsOrFramesChanged);
\r
1259 this.drop_chapterStart.TextChanged -= new EventHandler(this.SecondsOrFramesChanged);
\r
1262 switch (drop_mode.SelectedIndex)
\r
1265 drop_chapterStart.DropDownStyle = ComboBoxStyle.DropDownList;
\r
1266 drop_chapterFinish.DropDownStyle = ComboBoxStyle.DropDownList;
\r
1267 if (drop_chapterStart.Items.Count != 0)
\r
1269 drop_chapterStart.SelectedIndex = 0;
\r
1270 drop_chapterFinish.SelectedIndex = drop_chapterFinish.Items.Count - 1;
\r
1273 lbl_duration.Text = "--:--:--";
\r
1276 this.drop_chapterStart.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1277 this.drop_chapterFinish.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1278 drop_chapterStart.DropDownStyle = ComboBoxStyle.Simple;
\r
1279 drop_chapterFinish.DropDownStyle = ComboBoxStyle.Simple;
\r
1280 if (selectedTitle != null)
\r
1282 drop_chapterStart.Text = "0";
\r
1283 drop_chapterFinish.Text = selectedTitle.Duration.TotalSeconds.ToString();
\r
1287 this.drop_chapterStart.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1288 this.drop_chapterFinish.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1289 drop_chapterStart.DropDownStyle = ComboBoxStyle.Simple;
\r
1290 drop_chapterFinish.DropDownStyle = ComboBoxStyle.Simple;
\r
1291 if (selectedTitle != null)
\r
1293 drop_chapterStart.Text = "0";
\r
1294 drop_chapterFinish.Text = (selectedTitle.Fps * selectedTitle.Duration.TotalSeconds).ToString();
\r
1301 private void btn_destBrowse_Click(object sender, EventArgs e)
\r
1303 // This removes the file extension from the filename box on the save file dialog.
\r
1304 // It's daft but some users don't realise that typing an extension overrides the dropdown extension selected.
\r
1305 DVD_Save.FileName = Path.GetFileNameWithoutExtension(text_destination.Text);
\r
1307 if (Path.IsPathRooted(text_destination.Text))
\r
1308 DVD_Save.InitialDirectory = Path.GetDirectoryName(text_destination.Text);
\r
1310 // Show the dialog and set the main form file path
\r
1311 if (drop_format.SelectedIndex.Equals(0))
\r
1312 DVD_Save.FilterIndex = 1;
\r
1313 else if (drop_format.SelectedIndex.Equals(1))
\r
1314 DVD_Save.FilterIndex = 2;
\r
1316 if (DVD_Save.ShowDialog() == DialogResult.OK)
\r
1318 // Add a file extension manually, as FileDialog.AddExtension has issues with dots in filenames
\r
1319 switch (DVD_Save.FilterIndex)
\r
1323 !Path.GetExtension(DVD_Save.FileName).Equals(".mp4",
\r
1324 StringComparison.InvariantCultureIgnoreCase))
\r
1325 if (Properties.Settings.Default.useM4v)
\r
1326 DVD_Save.FileName = DVD_Save.FileName.Replace(".mp4", ".m4v").Replace(".mkv", ".m4v");
\r
1328 DVD_Save.FileName = DVD_Save.FileName.Replace(".m4v", ".mp4").Replace(".mkv", ".mp4");
\r
1332 !Path.GetExtension(DVD_Save.FileName).Equals(".mkv", StringComparison.InvariantCultureIgnoreCase))
\r
1333 DVD_Save.FileName = DVD_Save.FileName.Replace(".mp4", ".mkv").Replace(".m4v", ".mkv");
\r
1339 text_destination.Text = DVD_Save.FileName;
\r
1341 // Quicktime requires .m4v file for chapter markers to work. If checked, change the extension to .m4v (mp4 and m4v are the same thing)
\r
1342 if (Check_ChapterMarkers.Checked && DVD_Save.FilterIndex != 2)
\r
1343 SetExtension(".m4v");
\r
1347 private void text_destination_TextChanged(object sender, EventArgs e)
\r
1349 string path = text_destination.Text;
\r
1350 if (path.EndsWith(".mp4") || path.EndsWith(".m4v"))
\r
1351 drop_format.SelectedIndex = 0;
\r
1352 else if (path.EndsWith(".mkv"))
\r
1353 drop_format.SelectedIndex = 1;
\r
1356 // Output Settings
\r
1357 private void drop_format_SelectedIndexChanged(object sender, EventArgs e)
\r
1359 switch (drop_format.SelectedIndex)
\r
1362 if (Properties.Settings.Default.useM4v || Check_ChapterMarkers.Checked ||
\r
1363 AudioSettings.RequiresM4V() || Subtitles.RequiresM4V())
\r
1364 SetExtension(".m4v");
\r
1366 SetExtension(".mp4");
\r
1369 SetExtension(".mkv");
\r
1373 AudioSettings.SetContainer(drop_format.Text);
\r
1374 Subtitles.SetContainer(drop_format.SelectedIndex);
\r
1376 if (drop_format.Text.Contains("MP4"))
\r
1378 if (drp_videoEncoder.Items.Contains("VP3 (Theora)"))
\r
1380 drp_videoEncoder.Items.Remove("VP3 (Theora)");
\r
1381 drp_videoEncoder.SelectedIndex = 1;
\r
1384 else if (drop_format.Text.Contains("MKV"))
\r
1385 drp_videoEncoder.Items.Add("VP3 (Theora)");
\r
1388 public void SetExtension(string newExtension)
\r
1390 if (newExtension == ".mp4" || newExtension == ".m4v")
\r
1391 if (Properties.Settings.Default.useM4v || Check_ChapterMarkers.Checked || AudioSettings.RequiresM4V() ||
\r
1392 Subtitles.RequiresM4V())
\r
1393 newExtension = ".m4v";
\r
1395 newExtension = ".mp4";
\r
1397 if (Path.HasExtension(newExtension))
\r
1398 text_destination.Text = Path.ChangeExtension(text_destination.Text, newExtension);
\r
1402 private void drp_videoEncoder_SelectedIndexChanged(object sender, EventArgs e)
\r
1404 setContainerOpts();
\r
1406 // Turn off some options which are H.264 only when the user selects a non h.264 encoder
\r
1407 if (drp_videoEncoder.Text.Contains("H.264"))
\r
1409 if (check_2PassEncode.CheckState == CheckState.Checked)
\r
1410 check_turbo.Enabled = true;
\r
1412 tab_advanced.Enabled = true;
\r
1413 if ((drop_format.Text.Contains("MP4")) || (drop_format.Text.Contains("M4V")))
\r
1414 check_iPodAtom.Enabled = true;
\r
1416 check_iPodAtom.Enabled = false;
\r
1420 check_turbo.CheckState = CheckState.Unchecked;
\r
1421 check_turbo.Enabled = false;
\r
1422 tab_advanced.Enabled = false;
\r
1423 x264Panel.X264Query = string.Empty;
\r
1424 check_iPodAtom.Enabled = false;
\r
1425 check_iPodAtom.Checked = false;
\r
1428 // Setup the CQ Slider
\r
1429 switch (drp_videoEncoder.Text)
\r
1431 case "MPEG-4 (FFmpeg)":
\r
1432 if (slider_videoQuality.Value > 31)
\r
1433 slider_videoQuality.Value = 20; // Just reset to 70% QP 10 on encode change.
\r
1434 slider_videoQuality.Minimum = 1;
\r
1435 slider_videoQuality.Maximum = 31;
\r
1437 case "H.264 (x264)":
\r
1438 slider_videoQuality.Minimum = 0;
\r
1439 slider_videoQuality.TickFrequency = 1;
\r
1441 CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
\r
1442 double cqStep = Properties.Settings.Default.x264cqstep;
\r
1443 double multiplier = 1.0 / cqStep;
\r
1444 double value = slider_videoQuality.Value * multiplier;
\r
1446 slider_videoQuality.Maximum = (int)(51 / Properties.Settings.Default.x264cqstep);
\r
1448 if (value < slider_videoQuality.Maximum)
\r
1449 slider_videoQuality.Value = slider_videoQuality.Maximum - (int)value;
\r
1452 case "VP3 (Theora)":
\r
1453 if (slider_videoQuality.Value > 63)
\r
1454 slider_videoQuality.Value = 45; // Just reset to 70% QP 45 on encode change.
\r
1455 slider_videoQuality.Minimum = 0;
\r
1456 slider_videoQuality.Maximum = 63;
\r
1462 /// Set the container format options
\r
1464 public void setContainerOpts()
\r
1466 if ((drop_format.Text.Contains("MP4")) || (drop_format.Text.Contains("M4V")))
\r
1468 check_largeFile.Enabled = true;
\r
1469 check_optimiseMP4.Enabled = true;
\r
1470 check_iPodAtom.Enabled = true;
\r
1474 check_largeFile.Enabled = false;
\r
1475 check_optimiseMP4.Enabled = false;
\r
1476 check_iPodAtom.Enabled = false;
\r
1477 check_largeFile.Checked = false;
\r
1478 check_optimiseMP4.Checked = false;
\r
1479 check_iPodAtom.Checked = false;
\r
1483 private double _cachedCqStep = Properties.Settings.Default.x264cqstep;
\r
1486 /// Update the CQ slider for x264 for a new CQ step. This is set from option
\r
1488 public void setQualityFromSlider()
\r
1490 // Work out the current RF value.
\r
1491 double cqStep = _cachedCqStep;
\r
1492 double rfValue = 51.0 - slider_videoQuality.Value * cqStep;
\r
1494 // Change the maximum value for the slider
\r
1495 slider_videoQuality.Maximum = (int)(51 / Properties.Settings.Default.x264cqstep);
\r
1497 // Reset the CQ slider to RF0
\r
1498 slider_videoQuality.Value = slider_videoQuality.Maximum;
\r
1500 // Reset the CQ slider back to the previous value as close as possible
\r
1501 double cqStepNew = Properties.Settings.Default.x264cqstep;
\r
1502 double rfValueCurrent = 51.0 - slider_videoQuality.Value * cqStepNew;
\r
1503 while (rfValueCurrent < rfValue)
\r
1505 slider_videoQuality.Value--;
\r
1506 rfValueCurrent = 51.0 - slider_videoQuality.Value * cqStepNew;
\r
1509 // Cache the CQ step for the next calculation
\r
1510 _cachedCqStep = Properties.Settings.Default.x264cqstep;
\r
1513 private void slider_videoQuality_Scroll(object sender, EventArgs e)
\r
1515 double cqStep = Properties.Settings.Default.x264cqstep;
\r
1516 switch (drp_videoEncoder.Text)
\r
1518 case "MPEG-4 (FFmpeg)":
\r
1519 lbl_SliderValue.Text = "QP:" + (32 - slider_videoQuality.Value);
\r
1521 case "H.264 (x264)":
\r
1522 double rfValue = 51.0 - slider_videoQuality.Value * cqStep;
\r
1523 rfValue = Math.Round(rfValue, 2);
\r
1524 lbl_SliderValue.Text = "RF:" + rfValue.ToString(new CultureInfo("en-US"));
\r
1526 case "VP3 (Theora)":
\r
1527 lbl_SliderValue.Text = "QP:" + slider_videoQuality.Value;
\r
1532 private void radio_targetFilesize_CheckedChanged(object sender, EventArgs e)
\r
1534 text_bitrate.Enabled = false;
\r
1535 text_filesize.Enabled = true;
\r
1536 slider_videoQuality.Enabled = false;
\r
1538 check_2PassEncode.Enabled = true;
\r
1541 private void radio_avgBitrate_CheckedChanged(object sender, EventArgs e)
\r
1543 text_bitrate.Enabled = true;
\r
1544 text_filesize.Enabled = false;
\r
1545 slider_videoQuality.Enabled = false;
\r
1547 check_2PassEncode.Enabled = true;
\r
1550 private void radio_cq_CheckedChanged(object sender, EventArgs e)
\r
1552 text_bitrate.Enabled = false;
\r
1553 text_filesize.Enabled = false;
\r
1554 slider_videoQuality.Enabled = true;
\r
1556 check_2PassEncode.Enabled = false;
\r
1557 check_2PassEncode.CheckState = CheckState.Unchecked;
\r
1560 private void check_2PassEncode_CheckedChanged(object sender, EventArgs e)
\r
1562 if (check_2PassEncode.CheckState.ToString() == "Checked")
\r
1564 if (drp_videoEncoder.Text.Contains("H.264"))
\r
1565 check_turbo.Enabled = true;
\r
1569 check_turbo.Enabled = false;
\r
1570 check_turbo.CheckState = CheckState.Unchecked;
\r
1574 // Chapter Marker Tab
\r
1575 private void Check_ChapterMarkers_CheckedChanged(object sender, EventArgs e)
\r
1577 if (Check_ChapterMarkers.Checked)
\r
1579 if (drop_format.SelectedIndex != 1)
\r
1580 SetExtension(".m4v");
\r
1581 data_chpt.Enabled = true;
\r
1582 btn_importChapters.Enabled = true;
\r
1586 if (drop_format.SelectedIndex != 1 && !Properties.Settings.Default.useM4v)
\r
1587 SetExtension(".mp4");
\r
1588 data_chpt.Enabled = false;
\r
1589 btn_importChapters.Enabled = false;
\r
1593 private void btn_importChapters_Click(object sender, EventArgs e)
\r
1595 if (File_ChapterImport.ShowDialog() == DialogResult.OK)
\r
1597 string filename = File_ChapterImport.FileName;
\r
1598 DataGridView imported = Main.ImportChapterNames(data_chpt, filename);
\r
1599 if (imported != null)
\r
1600 data_chpt = imported;
\r
1604 private void mnu_resetChapters_Click(object sender, EventArgs e)
\r
1606 data_chpt.Rows.Clear();
\r
1607 DataGridView chapterGridView = Main.ChapterNaming(data_chpt, drop_chapterFinish.Text);
\r
1608 if (chapterGridView != null)
\r
1610 data_chpt = chapterGridView;
\r
1614 // Query Editor Tab
\r
1615 private void btn_generate_Query_Click(object sender, EventArgs e)
\r
1617 rtf_query.Text = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
1620 private void btn_clear_Click(object sender, EventArgs e)
\r
1622 rtf_query.Clear();
\r
1627 // MainWindow Components, Actions and Functions ***********************
\r
1629 #region Source Scan
\r
1631 public bool isScanning { get; set; }
\r
1633 private void StartScan(string filename, int title)
\r
1635 // Setup the GUI components for the scan.
\r
1636 sourcePath = filename;
\r
1638 this.DisableGUI();
\r
1640 if (ActivityWindow != null)
\r
1641 ActivityWindow.SetMode(ActivityLogMode.Scan);
\r
1646 isScanning = true;
\r
1647 SourceScan = new Scan();
\r
1648 SourceScan.ScanSource(sourcePath, title);
\r
1649 SourceScan.ScanStatusChanged += new EventHandler(SourceScan_ScanStatusChanged);
\r
1650 SourceScan.ScanCompleted += new EventHandler(SourceScan_ScanCompleted);
\r
1652 catch (Exception exc)
\r
1654 MessageBox.Show("frmMain.cs - StartScan " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1658 private void SourceScan_ScanStatusChanged(object sender, EventArgs e)
\r
1660 UpdateScanStatusLabel();
\r
1663 private void SourceScan_ScanCompleted(object sender, EventArgs e)
\r
1665 UpdateGuiAfterScan();
\r
1668 private void UpdateScanStatusLabel()
\r
1670 if (InvokeRequired)
\r
1672 BeginInvoke(new UpdateWindowHandler(UpdateScanStatusLabel));
\r
1675 lbl_encode.Text = SourceScan.ScanStatus();
\r
1678 private void UpdateGuiAfterScan()
\r
1680 if (InvokeRequired)
\r
1682 BeginInvoke(new UpdateWindowHandler(UpdateGuiAfterScan));
\r
1688 currentSource = SourceScan.SouceData();
\r
1690 // Setup some GUI components
\r
1691 drp_dvdtitle.Items.Clear();
\r
1692 if (currentSource.Titles.Count != 0)
\r
1693 drp_dvdtitle.Items.AddRange(currentSource.Titles.ToArray());
\r
1695 foreach (Title title in currentSource.Titles)
\r
1697 if (title.MainTitle)
\r
1699 drp_dvdtitle.SelectedItem = title;
\r
1703 // Enable the creation of chapter markers if the file is an image of a dvd.
\r
1705 int.TryParse(drop_chapterStart.Items[0].ToString(), out start);
\r
1706 int.TryParse(drop_chapterFinish.Items[drop_chapterFinish.Items.Count - 1].ToString(), out end);
\r
1708 Check_ChapterMarkers.Enabled = true;
\r
1711 Check_ChapterMarkers.Enabled = false;
\r
1712 Check_ChapterMarkers.Checked = false;
\r
1713 data_chpt.Rows.Clear();
\r
1716 // If no titles were found, Display an error message
\r
1717 if (drp_dvdtitle.Items.Count == 0)
\r
1720 "No Title(s) found. \n\nYour Source may be copy protected, badly mastered or in a format which HandBrake does not support. \nPlease refer to the Documentation and FAQ (see Help Menu).",
\r
1721 "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
\r
1722 sourcePath = string.Empty;
\r
1724 UpdateSourceLabel();
\r
1726 // Enable the GUI components and enable any disabled components
\r
1729 catch (Exception exc)
\r
1731 MessageBox.Show("frmMain.cs - updateUIafterScan " + exc, "Error", MessageBoxButtons.OK,
\r
1732 MessageBoxIcon.Error);
\r
1737 private void EnableGUI()
\r
1741 if (InvokeRequired)
\r
1742 BeginInvoke(new UpdateWindowHandler(EnableGUI));
\r
1743 lbl_encode.Text = "Scan Completed";
\r
1744 foreach (Control ctrl in Controls)
\r
1745 ctrl.Enabled = true;
\r
1746 btn_start.Enabled = true;
\r
1747 btn_showQueue.Enabled = true;
\r
1748 btn_add2Queue.Enabled = true;
\r
1749 tb_preview.Enabled = true;
\r
1750 btn_source.Enabled = true;
\r
1751 mnu_killCLI.Visible = false;
\r
1753 catch (Exception exc)
\r
1755 MessageBox.Show("frmMain.cs - EnableGUI() " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1759 private void DisableGUI()
\r
1761 foreach (Control ctrl in Controls)
\r
1762 if (!(ctrl is StatusStrip || ctrl is MenuStrip || ctrl is ToolStrip))
\r
1763 ctrl.Enabled = false;
\r
1765 lbl_encode.Visible = true;
\r
1766 lbl_encode.Text = "Scanning ...";
\r
1767 btn_source.Enabled = false;
\r
1768 btn_start.Enabled = false;
\r
1769 btn_showQueue.Enabled = false;
\r
1770 btn_add2Queue.Enabled = false;
\r
1771 tb_preview.Enabled = false;
\r
1772 mnu_killCLI.Visible = true;
\r
1775 private void KillScan()
\r
1779 SourceScan.ScanCompleted -= new EventHandler(SourceScan_ScanCompleted);
\r
1783 if (SourceScan.ScanProcess() != null)
\r
1784 SourceScan.ScanProcess().Kill();
\r
1786 lbl_encode.Text = "Scan Cancelled!";
\r
1788 catch (Exception ex)
\r
1791 "Unable to kill HandBrakeCLI.exe \nYou may need to manually kill HandBrakeCLI.exe using the Windows Task Manager if it does not close automatically within the next few minutes. \n\nError Information: \n" +
\r
1792 ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1796 private void ResetGUI()
\r
1798 drp_dvdtitle.Items.Clear();
\r
1799 drop_chapterStart.Items.Clear();
\r
1800 drop_chapterFinish.Items.Clear();
\r
1801 lbl_duration.Text = "Select a Title";
\r
1802 PictureSettings.lbl_src_res.Text = "Select a Title";
\r
1803 sourcePath = String.Empty;
\r
1804 text_destination.Text = String.Empty;
\r
1805 selectedTitle = null;
\r
1806 isScanning = false;
\r
1809 private void UpdateSourceLabel()
\r
1811 labelSource.Text = string.IsNullOrEmpty(sourcePath) ? "Select \"Source\" to continue." : this.SourceName;
\r
1813 if (selectedTitle != null)
\r
1814 if (!string.IsNullOrEmpty(selectedTitle.SourceName))
\r
1815 // If it's one of multiple source files, make sure we don't use the folder name
\r
1816 labelSource.Text = Path.GetFileName(selectedTitle.SourceName);
\r
1819 public void RecievingJob(Job job)
\r
1821 string query = job.Query;
\r
1822 StartScan(job.Source, job.Title);
\r
1824 if (query != null)
\r
1826 // Ok, Reset all the H264 widgets before changing the preset
\r
1827 x264Panel.Reset2Defaults();
\r
1829 // Send the query from the file to the Query Parser class
\r
1830 QueryParser presetQuery = QueryParser.Parse(query);
\r
1832 // Now load the preset
\r
1833 PresetLoader.LoadPreset(this, presetQuery, "Load Back From Queue", true);
\r
1835 // The x264 widgets will need updated, so do this now:
\r
1836 x264Panel.X264_StandardizeOptString();
\r
1837 x264Panel.X264_SetCurrentSettingsInPanel();
\r
1839 // Finally, let this window have a copy of the preset settings.
\r
1840 CurrentlySelectedPreset = null;
\r
1841 PictureSettings.SetPresetCropWarningLabel(null);
\r
1847 #region GUI Functions and Actions
\r
1850 /// Set the GUI to it's finished encoding state.
\r
1852 private void SetEncodeFinished()
\r
1856 if (InvokeRequired)
\r
1858 BeginInvoke(new UpdateWindowHandler(SetEncodeFinished));
\r
1862 lbl_encode.Text = "Encoding Finished";
\r
1863 btn_start.Text = "Start";
\r
1864 btn_start.ToolTipText = "Start the encoding process";
\r
1865 btn_start.Image = Properties.Resources.Play;
\r
1867 // If the window is minimized, display the notification in a popup.
\r
1868 if (Properties.Settings.Default.trayIconAlerts)
\r
1869 if (FormWindowState.Minimized == this.WindowState)
\r
1871 notifyIcon.BalloonTipText = lbl_encode.Text;
\r
1872 notifyIcon.ShowBalloonTip(500);
\r
1875 catch (Exception exc)
\r
1877 MessageBox.Show(exc.ToString());
\r
1882 /// Set the GUI to it's started encoding state.
\r
1884 private void SetEncodeStarted()
\r
1888 if (InvokeRequired)
\r
1890 BeginInvoke(new UpdateWindowHandler(SetEncodeStarted));
\r
1894 lbl_encode.Visible = true;
\r
1895 lbl_encode.Text = "Encoding with " + encodeQueue.Count + " encode(s) pending";
\r
1896 btn_start.Text = "Stop";
\r
1897 btn_start.ToolTipText = "Stop the encoding process.";
\r
1898 btn_start.Image = Properties.Resources.stop;
\r
1900 catch (Exception exc)
\r
1902 MessageBox.Show(exc.ToString());
\r
1907 /// Set the DVD Drive selection in the "Source" Menu
\r
1909 private void SetDriveSelectionMenuItem()
\r
1913 if (InvokeRequired)
\r
1915 BeginInvoke(new UpdateWindowHandler(SetDriveSelectionMenuItem));
\r
1919 drives = Main.GetDrives();
\r
1921 List<ToolStripMenuItem> menuItems = new List<ToolStripMenuItem>();
\r
1922 foreach (DriveInformation drive in drives)
\r
1924 ToolStripMenuItem menuItem = new ToolStripMenuItem();
\r
1925 menuItem.Name = drive.ToString();
\r
1926 menuItem.Text = drive.RootDirectory + " (" + drive.VolumeLabel + ")";
\r
1927 menuItem.Image = Resources.disc_small;
\r
1928 menuItem.Click += new EventHandler(mnu_dvd_drive_Click);
\r
1929 menuItems.Add(menuItem);
\r
1932 foreach (ToolStripMenuItem item in menuItems)
\r
1933 btn_source.DropDownItems.Add(item);
\r
1935 catch (Exception exc)
\r
1937 MessageBox.Show("Error in SetDriveSelectionMenuItem" + exc);
\r
1942 /// Access the preset Handler and setup the preset panel.
\r
1944 private void LoadPresetPanel()
\r
1946 if (presetHandler.CheckIfPresetsAreOutOfDate())
\r
1947 if (!Properties.Settings.Default.presetNotification)
\r
1948 MessageBox.Show(splash,
\r
1949 "HandBrake has determined your built-in presets are out of date... These presets will now be updated.",
\r
1950 "Preset Update", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
1952 presetHandler.GetPresetPanel(ref treeView_presets);
\r
1953 treeView_presets.Update();
\r
1957 /// Get the title from the selected item in the title dropdown.
\r
1962 private int getTitle()
\r
1965 if (drp_dvdtitle.SelectedItem != null)
\r
1967 string[] titleInfo = drp_dvdtitle.SelectedItem.ToString().Split(' ');
\r
1968 int.TryParse(titleInfo[0], out title);
\r
1979 /// Handle GUI shortcuts
\r
1981 /// <param name="msg"></param>
\r
1982 /// <param name="keyData"></param>
\r
1983 /// <returns></returns>
\r
1984 protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
\r
1986 if (keyData == (Keys.Control | Keys.S))
\r
1988 btn_start_Click(this, new EventArgs());
\r
1992 if (keyData == (Keys.Control | Keys.A))
\r
1994 btn_add2Queue_Click(this, new EventArgs());
\r
1997 return base.ProcessCmdKey(ref msg, keyData);
\r
2001 /// If the queue is being processed, prompt the user to confirm application close.
\r
2003 /// <param name="e"></param>
\r
2004 protected override void OnFormClosing(FormClosingEventArgs e)
\r
2006 // If currently encoding, the queue isn't paused, and there are queue items to process, prompt to confirm close.
\r
2007 if ((encodeQueue.IsEncoding) && (!encodeQueue.PauseRequested) && (encodeQueue.Count > 0))
\r
2009 DialogResult result =
\r
2011 "HandBrake has queue items to process. Closing HandBrake will not stop the current encoding, but will stop processing the queue.\n\nDo you want to close HandBrake?",
\r
2012 "Close HandBrake?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
2013 if (result == DialogResult.No)
\r
2016 base.OnFormClosing(e);
\r
2021 #region In-GUI Encode Status (Experimental)
\r
2024 /// Starts a new thread to monitor and process the CLI encode status
\r
2026 private void EncodeMonitorThread()
\r
2030 Parser encode = new Parser(encodeQueue.HbProcess.StandardOutput.BaseStream);
\r
2031 encode.OnEncodeProgress += EncodeOnEncodeProgress;
\r
2032 while (!encode.EndOfStream)
\r
2033 encode.ReadEncodeStatus();
\r
2035 catch (Exception exc)
\r
2037 MessageBox.Show(exc.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
2042 /// Displays the Encode status in the GUI
\r
2044 /// <param name="Sender"></param>
\r
2045 /// <param name="CurrentTask"></param>
\r
2046 /// <param name="TaskCount"></param>
\r
2047 /// <param name="PercentComplete"></param>
\r
2048 /// <param name="CurrentFps"></param>
\r
2049 /// <param name="AverageFps"></param>
\r
2050 /// <param name="TimeRemaining"></param>
\r
2051 private void EncodeOnEncodeProgress(object Sender, int CurrentTask, int TaskCount, float PercentComplete, float CurrentFps, float AverageFps, TimeSpan TimeRemaining)
\r
2053 if (this.InvokeRequired)
\r
2056 new EncodeProgressEventHandler(EncodeOnEncodeProgress),
\r
2057 new[] { Sender, CurrentTask, TaskCount, PercentComplete, CurrentFps, AverageFps, TimeRemaining });
\r
2061 string.Format("Encode Progress: {0}%, FPS: {1}, Avg FPS: {2}, Time Remaining: {3} ", PercentComplete, CurrentFps, AverageFps, TimeRemaining);
\r
2066 // This is the END of the road ****************************************
\r