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.Threading;
\r
16 using System.Windows.Forms;
\r
24 public partial class frmMain : Form
\r
26 // Objects which may be used by one or more other objects *************
\r
27 private Queue encodeQueue = new Queue();
\r
28 private PresetsHandler presetHandler = new PresetsHandler();
\r
30 // Globals: Mainly used for tracking. *********************************
\r
31 public Title selectedTitle;
\r
32 private frmQueue queueWindow;
\r
33 private frmPreview qtpreview;
\r
34 private frmActivityWindow ActivityWindow;
\r
35 private Form splash;
\r
36 public string sourcePath;
\r
37 private ActivityLogMode lastAction;
\r
38 private SourceType selectedSourceType;
\r
39 private string dvdDrivePath;
\r
40 private string dvdDriveLabel;
\r
41 private Preset CurrentlySelectedPreset;
\r
42 private DVD currentSource;
\r
43 private Scan SourceScan = new Scan();
\r
44 private List<DriveInformation> drives;
\r
46 // Delegates **********************************************************
\r
47 private delegate void UpdateWindowHandler();
\r
49 // Applicaiton Startup ************************************************
\r
51 #region Application Startup
\r
55 // Load and setup the splash screen in this thread
\r
56 splash = new frmSplashScreen();
\r
58 Label lblStatus = new Label { Size = new Size(150, 20), Location = new Point(182, 102) };
\r
59 splash.Controls.Add(lblStatus);
\r
61 InitializeComponent();
\r
63 // Update the users config file with the CLI version data.
\r
64 lblStatus.Text = "Setting Version Data ...";
\r
65 Application.DoEvents();
\r
66 Main.SetCliVersionData();
\r
68 // Show the form, but leave disabled until preloading is complete then show the main form
\r
69 this.Enabled = false;
\r
71 Application.DoEvents(); // Forces frmMain to draw
\r
73 // Check for new versions, if update checking is enabled
\r
74 if (Properties.Settings.Default.updateStatus)
\r
76 DateTime now = DateTime.Now;
\r
77 DateTime lastCheck = Properties.Settings.Default.lastUpdateCheckDate;
\r
78 TimeSpan elapsed = now.Subtract(lastCheck);
\r
79 if (elapsed.TotalDays > Properties.Settings.Default.daysBetweenUpdateCheck)
\r
81 lblStatus.Text = "Checking for updates ...";
\r
82 Application.DoEvents();
\r
84 Main.BeginCheckForUpdates(new AsyncCallback(UpdateCheckDone), false);
\r
88 // Clear the log files in the background
\r
89 if (Properties.Settings.Default.clearOldLogs)
\r
91 lblStatus.Text = "Clearing Old Log Files ...";
\r
92 Application.DoEvents();
\r
93 Thread clearLog = new Thread(Main.ClearOldLogs);
\r
97 // Setup the GUI components
\r
98 lblStatus.Text = "Setting up the GUI ...";
\r
99 Application.DoEvents();
\r
100 LoadPresetPanel(); // Load the Preset Panel
\r
101 treeView_presets.ExpandAll();
\r
102 lbl_encode.Text = string.Empty;
\r
103 drop_mode.SelectedIndex = 0;
\r
104 queueWindow = new frmQueue(encodeQueue, this); // Prepare the Queue
\r
105 if (!Properties.Settings.Default.QueryEditorTab)
\r
106 tabs_panel.TabPages.RemoveAt(7); // Remove the query editor tab if the user does not want it enabled.
\r
108 // Load the user's default settings or Normal Preset
\r
109 if (Properties.Settings.Default.defaultPreset != string.Empty)
\r
111 if (presetHandler.GetPreset(Properties.Settings.Default.defaultPreset) != null)
\r
113 string query = presetHandler.GetPreset(Properties.Settings.Default.defaultPreset).Query;
\r
114 bool loadPictureSettings =
\r
115 presetHandler.GetPreset(Properties.Settings.Default.defaultPreset).PictureSettings;
\r
119 x264Panel.Reset2Defaults();
\r
121 QueryParser presetQuery = QueryParser.Parse(query);
\r
122 PresetLoader.LoadPreset(this, presetQuery, Properties.Settings.Default.defaultPreset,
\r
123 loadPictureSettings);
\r
125 x264Panel.X264_StandardizeOptString();
\r
126 x264Panel.X264_SetCurrentSettingsInPanel();
\r
130 loadNormalPreset();
\r
133 loadNormalPreset();
\r
135 // Enabled GUI tooltip's if Required
\r
136 if (Properties.Settings.Default.tooltipEnable)
\r
137 ToolTip.Active = true;
\r
139 // Register with Growl (if not using Growl for the encoding completion action, this wont hurt anything)
\r
140 GrowlCommunicator.Register();
\r
142 // Finished Loading
\r
143 lblStatus.Text = "Loading Complete!";
\r
144 Application.DoEvents();
\r
147 this.Enabled = true;
\r
149 // Event Handlers and Queue Recovery
\r
154 private void UpdateCheckDone(IAsyncResult result)
\r
156 if (InvokeRequired)
\r
158 Invoke(new MethodInvoker(() => UpdateCheckDone(result)));
\r
162 UpdateCheckInformation info;
\r
166 info = Main.EndCheckForUpdates(result);
\r
168 if (info.NewVersionAvailable)
\r
170 frmUpdater updateWindow = new frmUpdater(info.BuildInformation);
\r
171 updateWindow.ShowDialog();
\r
174 catch (Exception ex)
\r
176 if ((bool)result.AsyncState)
\r
178 "Unable to check for updates, Please try again later.\n\nDetailed Error Information:\n" + ex,
\r
179 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
183 // Startup Functions
\r
184 private void queueRecovery()
\r
186 if (Main.CheckQueueRecovery())
\r
188 DialogResult result =
\r
190 "HandBrake has detected unfinished items on the queue from the last time the application was launched. Would you like to recover these?",
\r
191 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
193 if (result == DialogResult.Yes)
\r
194 encodeQueue.LoadQueueFromFile("hb_queue_recovery.xml"); // Start Recovery
\r
197 // Remove the Queue recovery file if the user doesn't want to recovery the last queue.
\r
198 string queuePath = Path.Combine(Path.GetTempPath(), "hb_queue_recovery.xml");
\r
199 if (File.Exists(queuePath))
\r
200 File.Delete(queuePath);
\r
209 public string SourceName
\r
213 if (this.selectedSourceType == SourceType.DvdDrive)
\r
215 return this.dvdDriveLabel;
\r
218 if (Path.GetFileNameWithoutExtension(this.sourcePath) != "VIDEO_TS")
\r
219 return Path.GetFileNameWithoutExtension(this.sourcePath);
\r
221 return Path.GetFileNameWithoutExtension(Path.GetDirectoryName(this.sourcePath));
\r
229 // Encoding Events for setting up the GUI
\r
230 private void events()
\r
232 // Handle Widget changes when preset is selected.
\r
233 RegisterPresetEventHandler();
\r
235 // Handle Window Resize
\r
236 if (Properties.Settings.Default.MainWindowMinimize)
\r
237 this.Resize += new EventHandler(frmMain_Resize);
\r
239 // Handle Encode Start / Finish / Pause
\r
241 encodeQueue.QueuePauseRequested += new EventHandler(encodePaused);
\r
242 encodeQueue.EncodeStarted += new EventHandler(encodeStarted);
\r
243 encodeQueue.EncodeEnded += new EventHandler(encodeEnded);
\r
245 // Handle a file being draged onto the GUI.
\r
246 this.DragEnter += new DragEventHandler(frmMain_DragEnter);
\r
247 this.DragDrop += new DragEventHandler(frmMain_DragDrop);
\r
250 // 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
251 private void RegisterPresetEventHandler()
\r
254 drop_format.SelectedIndexChanged += new EventHandler(changePresetLabel);
\r
255 check_largeFile.CheckedChanged += new EventHandler(changePresetLabel);
\r
256 check_iPodAtom.CheckedChanged += new EventHandler(changePresetLabel);
\r
257 check_optimiseMP4.CheckedChanged += new EventHandler(changePresetLabel);
\r
259 // Picture Settings
\r
260 // PictureSettings.PictureSettingsChanged += new EventHandler(changePresetLabel);
\r
263 Filters.FilterSettingsChanged += new EventHandler(changePresetLabel);
\r
266 drp_videoEncoder.SelectedIndexChanged += new EventHandler(changePresetLabel);
\r
267 check_2PassEncode.CheckedChanged += new EventHandler(changePresetLabel);
\r
268 check_turbo.CheckedChanged += new EventHandler(changePresetLabel);
\r
269 text_filesize.TextChanged += new EventHandler(changePresetLabel);
\r
270 text_bitrate.TextChanged += new EventHandler(changePresetLabel);
\r
271 slider_videoQuality.ValueChanged += new EventHandler(changePresetLabel);
\r
274 AudioSettings.AudioListChanged += new EventHandler(changePresetLabel);
\r
277 x264Panel.rtf_x264Query.TextChanged += new EventHandler(changePresetLabel);
\r
280 private void UnRegisterPresetEventHandler()
\r
282 // Output Settings
\r
283 drop_format.SelectedIndexChanged -= new EventHandler(changePresetLabel);
\r
284 check_largeFile.CheckedChanged -= new EventHandler(changePresetLabel);
\r
285 check_iPodAtom.CheckedChanged -= new EventHandler(changePresetLabel);
\r
286 check_optimiseMP4.CheckedChanged -= new EventHandler(changePresetLabel);
\r
288 // Picture Settings
\r
289 // PictureSettings.PictureSettingsChanged -= new EventHandler(changePresetLabel);
\r
292 Filters.FilterSettingsChanged -= new EventHandler(changePresetLabel);
\r
295 drp_videoEncoder.SelectedIndexChanged -= new EventHandler(changePresetLabel);
\r
296 check_2PassEncode.CheckedChanged -= new EventHandler(changePresetLabel);
\r
297 check_turbo.CheckedChanged -= new EventHandler(changePresetLabel);
\r
298 text_filesize.TextChanged -= new EventHandler(changePresetLabel);
\r
299 text_bitrate.TextChanged -= new EventHandler(changePresetLabel);
\r
300 slider_videoQuality.ValueChanged -= new EventHandler(changePresetLabel);
\r
303 AudioSettings.AudioListChanged -= new EventHandler(changePresetLabel);
\r
306 x264Panel.rtf_x264Query.TextChanged -= new EventHandler(changePresetLabel);
\r
309 private void changePresetLabel(object sender, EventArgs e)
\r
311 labelPreset.Text = "Output Settings (Preset: Custom)";
\r
312 CurrentlySelectedPreset = null;
\r
315 private static void frmMain_DragEnter(object sender, DragEventArgs e)
\r
317 if (e.Data.GetDataPresent(DataFormats.FileDrop, false))
\r
318 e.Effect = DragDropEffects.All;
\r
321 private void frmMain_DragDrop(object sender, DragEventArgs e)
\r
323 string[] fileList = e.Data.GetData(DataFormats.FileDrop) as string[];
\r
324 sourcePath = string.Empty;
\r
326 if (fileList != null)
\r
328 if (fileList[0] != string.Empty)
\r
330 this.selectedSourceType = SourceType.VideoFile;
\r
331 StartScan(fileList[0], 0);
\r
334 UpdateSourceLabel();
\r
337 UpdateSourceLabel();
\r
340 private void encodeStarted(object sender, EventArgs e)
\r
342 lastAction = ActivityLogMode.Encode;
\r
343 SetEncodeStarted();
\r
345 // Experimental HBProc Process Monitoring.
\r
346 if (Properties.Settings.Default.enocdeStatusInGui)
\r
348 Thread encodeMon = new Thread(EncodeMonitorThread);
\r
353 private void encodeEnded(object sender, EventArgs e)
\r
355 SetEncodeFinished();
\r
358 private void encodePaused(object sender, EventArgs e)
\r
360 SetEncodeFinished();
\r
365 // User Interface Menus / Tool Strips *********************************
\r
369 private void mnu_killCLI_Click(object sender, EventArgs e)
\r
374 private void mnu_exit_Click(object sender, EventArgs e)
\r
376 Application.Exit();
\r
383 private void mnu_encode_Click(object sender, EventArgs e)
\r
385 queueWindow.Show();
\r
388 private void mnu_encodeLog_Click(object sender, EventArgs e)
\r
390 frmActivityWindow dvdInfoWindow = new frmActivityWindow(lastAction, encodeQueue, SourceScan);
\r
391 dvdInfoWindow.Show();
\r
394 private void mnu_options_Click(object sender, EventArgs e)
\r
396 Form options = new frmOptions(this);
\r
397 options.ShowDialog();
\r
402 #region Presets Menu
\r
404 private void mnu_presetReset_Click(object sender, EventArgs e)
\r
406 presetHandler.UpdateBuiltInPresets();
\r
408 if (treeView_presets.Nodes.Count == 0)
\r
410 "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
411 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
413 MessageBox.Show("Presets have been updated!", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
415 treeView_presets.ExpandAll();
\r
418 private void mnu_delete_preset_Click(object sender, EventArgs e)
\r
420 presetHandler.RemoveBuiltInPresets();
\r
421 LoadPresetPanel(); // Reload the preset panel
\r
424 private void mnu_SelectDefault_Click(object sender, EventArgs e)
\r
426 loadNormalPreset();
\r
429 private void mnu_importMacPreset_Click(object sender, EventArgs e)
\r
434 private void btn_new_preset_Click(object sender, EventArgs e)
\r
436 Form preset = new frmAddPreset(this, QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
438 preset.ShowDialog();
\r
445 private void mnu_user_guide_Click(object sender, EventArgs e)
\r
447 Process.Start("http://trac.handbrake.fr/wiki/HandBrakeGuide");
\r
450 private void mnu_handbrake_home_Click(object sender, EventArgs e)
\r
452 Process.Start("http://handbrake.fr");
\r
455 private void mnu_UpdateCheck_Click(object sender, EventArgs e)
\r
457 lbl_updateCheck.Visible = true;
\r
458 Main.BeginCheckForUpdates(new AsyncCallback(updateCheckDoneMenu), false);
\r
461 private void updateCheckDoneMenu(IAsyncResult result)
\r
463 // Make sure it's running on the calling thread
\r
464 if (InvokeRequired)
\r
466 Invoke(new MethodInvoker(() => updateCheckDoneMenu(result)));
\r
469 UpdateCheckInformation info;
\r
472 // Get the information about the new build, if any, and close the window
\r
473 info = Main.EndCheckForUpdates(result);
\r
475 if (info.NewVersionAvailable && info.BuildInformation != null)
\r
477 frmUpdater updateWindow = new frmUpdater(info.BuildInformation);
\r
478 updateWindow.ShowDialog();
\r
481 MessageBox.Show("There are no new updates at this time.", "Update Check", MessageBoxButtons.OK,
\r
482 MessageBoxIcon.Information);
\r
483 lbl_updateCheck.Visible = false;
\r
486 catch (Exception ex)
\r
488 if ((bool)result.AsyncState)
\r
490 "Unable to check for updates, Please try again later.\n\nDetailed Error Information:\n" + ex,
\r
491 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
495 private void mnu_about_Click(object sender, EventArgs e)
\r
497 using (frmAbout About = new frmAbout())
\r
499 About.ShowDialog();
\r
507 // Right Click Menu Code
\r
508 private void pmnu_expandAll_Click(object sender, EventArgs e)
\r
510 treeView_presets.ExpandAll();
\r
513 private void pmnu_collapse_Click(object sender, EventArgs e)
\r
515 treeView_presets.CollapseAll();
\r
518 private void pmnu_import_Click(object sender, EventArgs e)
\r
523 private void pmnu_saveChanges_Click(object sender, EventArgs e)
\r
525 DialogResult result =
\r
527 "Do you wish to include picture settings when updating the preset: " +
\r
528 treeView_presets.SelectedNode.Text, "Update Preset", MessageBoxButtons.YesNoCancel,
\r
529 MessageBoxIcon.Question);
\r
530 if (result == DialogResult.Yes)
\r
531 presetHandler.Update(treeView_presets.SelectedNode.Text,
\r
532 QueryGenerator.GenerateTabbedComponentsQuery(this), true);
\r
533 else if (result == DialogResult.No)
\r
534 presetHandler.Update(treeView_presets.SelectedNode.Text,
\r
535 QueryGenerator.GenerateTabbedComponentsQuery(this), false);
\r
538 private void pmnu_delete_click(object sender, EventArgs e)
\r
540 if (treeView_presets.SelectedNode != null)
\r
542 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
543 treeView_presets.Nodes.Remove(treeView_presets.SelectedNode);
\r
545 treeView_presets.Select();
\r
548 private void presets_menu_Opening(object sender, CancelEventArgs e)
\r
550 // Make sure that the save menu is always disabled by default
\r
551 pmnu_saveChanges.Enabled = false;
\r
553 // Now enable the save menu if the selected preset is a user preset
\r
554 if (treeView_presets.SelectedNode != null)
\r
555 if (presetHandler.CheckIfUserPresetExists(treeView_presets.SelectedNode.Text))
\r
556 pmnu_saveChanges.Enabled = true;
\r
558 treeView_presets.Select();
\r
561 // Presets Management
\r
562 private void btn_addPreset_Click(object sender, EventArgs e)
\r
564 Form preset = new frmAddPreset(this, QueryGenerator.GenerateTabbedComponentsQuery(this), presetHandler);
\r
565 preset.ShowDialog();
\r
568 private void btn_removePreset_Click(object sender, EventArgs e)
\r
570 DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected preset?", "Preset",
\r
571 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
572 if (result == DialogResult.Yes)
\r
574 if (treeView_presets.SelectedNode != null)
\r
576 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
577 treeView_presets.Nodes.Remove(treeView_presets.SelectedNode);
\r
580 treeView_presets.Select();
\r
583 private void btn_setDefault_Click(object sender, EventArgs e)
\r
585 if (treeView_presets.SelectedNode != null)
\r
587 DialogResult result = MessageBox.Show("Are you sure you wish to set this preset as the default?",
\r
588 "Preset", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
589 if (result == DialogResult.Yes)
\r
591 Properties.Settings.Default.defaultPreset = treeView_presets.SelectedNode.Text;
\r
592 Properties.Settings.Default.Save();
\r
593 MessageBox.Show("New default preset set.", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
597 MessageBox.Show("Please select a preset first.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
600 private void treeview_presets_mouseUp(object sender, MouseEventArgs e)
\r
602 if (e.Button == MouseButtons.Right)
\r
603 treeView_presets.SelectedNode = treeView_presets.GetNodeAt(e.Location);
\r
604 else if (e.Button == MouseButtons.Left)
\r
606 if (treeView_presets.GetNodeAt(e.Location) != null)
\r
608 if (labelPreset.Text.Contains(treeView_presets.GetNodeAt(e.Location).Text))
\r
613 treeView_presets.Select();
\r
616 private void treeView_presets_AfterSelect(object sender, TreeViewEventArgs e)
\r
621 private void treeView_presets_deleteKey(object sender, KeyEventArgs e)
\r
623 if (e.KeyCode == Keys.Delete)
\r
625 DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected preset?", "Preset",
\r
626 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
627 if (result == DialogResult.Yes)
\r
629 if (treeView_presets.SelectedNode != null)
\r
630 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
632 // Remember each nodes expanded status so we can reload it
\r
633 List<bool> nodeStatus = new List<bool>();
\r
634 foreach (TreeNode node in treeView_presets.Nodes)
\r
635 nodeStatus.Add(node.IsExpanded);
\r
637 // Now reload the preset panel
\r
640 // And finally, re-expand any of the nodes if required
\r
642 foreach (TreeNode node in treeView_presets.Nodes)
\r
653 private void selectPreset()
\r
655 if (treeView_presets.SelectedNode != null)
\r
657 // Ok, so, we've selected a preset. Now we want to load it.
\r
658 string presetName = treeView_presets.SelectedNode.Text;
\r
659 Preset preset = presetHandler.GetPreset(presetName);
\r
660 if (preset != null)
\r
662 string query = presetHandler.GetPreset(presetName).Query;
\r
663 bool loadPictureSettings = presetHandler.GetPreset(presetName).PictureSettings;
\r
667 // Ok, Reset all the H264 widgets before changing the preset
\r
668 x264Panel.Reset2Defaults();
\r
670 // Send the query from the file to the Query Parser class
\r
671 QueryParser presetQuery = QueryParser.Parse(query);
\r
673 // Now load the preset
\r
674 PresetLoader.LoadPreset(this, presetQuery, presetName, loadPictureSettings);
\r
676 // The x264 widgets will need updated, so do this now:
\r
677 x264Panel.X264_StandardizeOptString();
\r
678 x264Panel.X264_SetCurrentSettingsInPanel();
\r
680 // Finally, let this window have a copy of the preset settings.
\r
681 CurrentlySelectedPreset = preset;
\r
682 PictureSettings.SetPresetCropWarningLabel(preset);
\r
688 private void loadNormalPreset()
\r
690 foreach (TreeNode treenode in treeView_presets.Nodes)
\r
692 foreach (TreeNode node in treenode.Nodes)
\r
694 if (node.Text.Equals("Normal"))
\r
695 treeView_presets.SelectedNode = treeView_presets.Nodes[treenode.Index].Nodes[0];
\r
700 private void ImportPreset()
\r
702 if (openPreset.ShowDialog() == DialogResult.OK)
\r
704 QueryParser parsed = PlistPresetHandler.Import(openPreset.FileName);
\r
705 if (presetHandler.CheckIfUserPresetExists(parsed.PresetName + " (Imported)"))
\r
707 DialogResult result =
\r
708 MessageBox.Show("This preset appears to already exist. Would you like to overwrite it?",
\r
709 "Overwrite preset?",
\r
710 MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
\r
711 if (result == DialogResult.Yes)
\r
713 PresetLoader.LoadPreset(this, parsed, parsed.PresetName, parsed.UsesPictureSettings);
\r
714 presetHandler.Update(parsed.PresetName + " (Imported)",
\r
715 QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
716 parsed.UsesPictureSettings);
\r
721 PresetLoader.LoadPreset(this, parsed, parsed.PresetName, parsed.UsesPictureSettings);
\r
722 if (presetHandler.Add(parsed.PresetName + " (Imported)",
\r
723 QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
724 parsed.UsesPictureSettings))
\r
726 TreeNode preset_treeview = new TreeNode(parsed.PresetName + " (Imported)")
\r
728 ForeColor = Color.Black
\r
730 treeView_presets.Nodes.Add(preset_treeview);
\r
740 private void btn_source_Click(object sender, EventArgs e)
\r
742 // Remove old Drive Menu Items.
\r
743 List<ToolStripMenuItem> itemsToRemove = new List<ToolStripMenuItem>();
\r
744 foreach (var item in btn_source.DropDownItems)
\r
746 if (item.GetType() == typeof(ToolStripMenuItem))
\r
748 ToolStripMenuItem menuItem = (ToolStripMenuItem)item;
\r
749 if (menuItem.Name.StartsWith("Drive"))
\r
751 itemsToRemove.Add(menuItem);
\r
756 foreach (ToolStripMenuItem item in itemsToRemove)
\r
757 btn_source.DropDownItems.Remove(item);
\r
759 Thread driveInfoThread = new Thread(SetDriveSelectionMenuItem);
\r
760 driveInfoThread.Start();
\r
763 private void btn_start_Click(object sender, EventArgs e)
\r
765 if (btn_start.Text == "Stop")
\r
767 DialogResult result;
\r
768 if (Properties.Settings.Default.enocdeStatusInGui &&
\r
769 !Properties.Settings.Default.showCliForInGuiEncodeStatus)
\r
771 result = MessageBox.Show(
\r
772 "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
773 "Cancel Encode?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
777 result = MessageBox.Show("Are you sure you wish to cancel the encode?", "Cancel Encode?",
\r
778 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
781 if (result == DialogResult.Yes)
\r
784 encodeQueue.Pause();
\r
786 if (Properties.Settings.Default.enocdeStatusInGui &&
\r
787 !Properties.Settings.Default.showCliForInGuiEncodeStatus)
\r
789 encodeQueue.Stop();
\r
790 if (encodeQueue.HbProcess != null)
\r
791 encodeQueue.HbProcess.WaitForExit();
\r
795 encodeQueue.SafelyClose();
\r
799 SetEncodeFinished();
\r
804 if (encodeQueue.Count != 0 ||
\r
805 (!string.IsNullOrEmpty(sourcePath) && !string.IsNullOrEmpty(text_destination.Text)))
\r
807 string generatedQuery = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
808 string specifiedQuery = rtf_query.Text != string.Empty
\r
810 : QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
811 string query = string.Empty;
\r
813 // Check to make sure the generated query matches the GUI settings
\r
814 if (Properties.Settings.Default.PromptOnUnmatchingQueries && !string.IsNullOrEmpty(specifiedQuery) &&
\r
815 generatedQuery != specifiedQuery)
\r
817 DialogResult result = MessageBox.Show("The query under the \"Query Editor\" tab " +
\r
818 "does not match the current GUI settings.\n\nBecause the manual query takes " +
\r
819 "priority over the GUI, your recently updated settings will not be taken " +
\r
820 "into account when encoding this job." +
\r
821 Environment.NewLine + Environment.NewLine +
\r
822 "Do you want to replace the manual query with the updated GUI-generated query?",
\r
823 "Manual Query does not Match GUI",
\r
824 MessageBoxButtons.YesNoCancel, MessageBoxIcon.Asterisk,
\r
825 MessageBoxDefaultButton.Button3);
\r
829 case DialogResult.Yes:
\r
830 // Replace the manual query with the generated one
\r
831 query = generatedQuery;
\r
832 rtf_query.Text = generatedQuery;
\r
834 case DialogResult.No:
\r
835 // Use the manual query
\r
836 query = specifiedQuery;
\r
838 case DialogResult.Cancel:
\r
839 // Don't start the encode
\r
845 query = specifiedQuery;
\r
848 DialogResult overwrite = DialogResult.Yes;
\r
849 if (text_destination.Text != string.Empty)
\r
850 if (File.Exists(text_destination.Text))
\r
853 "The destination file already exists. Are you sure you want to overwrite it?",
\r
854 "Overwrite File?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
856 if (overwrite == DialogResult.Yes)
\r
858 if (encodeQueue.Count == 0)
\r
859 encodeQueue.Add(query, getTitle(), sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
861 queueWindow.SetQueue();
\r
862 if (encodeQueue.Count > 1)
\r
863 queueWindow.Show(false);
\r
865 SetEncodeStarted(); // Encode is running, so setup the GUI appropriately
\r
866 encodeQueue.Start(); // Start The Queue Encoding Process
\r
867 lastAction = ActivityLogMode.Encode; // Set the last action to encode - Used for activity window.
\r
869 if (ActivityWindow != null)
\r
870 ActivityWindow.SetMode(ActivityLogMode.Encode);
\r
874 else if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
875 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
876 MessageBoxIcon.Warning);
\r
880 private void btn_add2Queue_Click(object sender, EventArgs e)
\r
882 if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
883 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
884 MessageBoxIcon.Warning);
\r
887 string query = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
888 if (rtf_query.Text != string.Empty)
\r
889 query = rtf_query.Text;
\r
891 if (encodeQueue.CheckForDestinationDuplicate(text_destination.Text))
\r
893 DialogResult result =
\r
895 "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
896 "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
\r
897 if (result == DialogResult.Yes)
\r
898 encodeQueue.Add(query, getTitle(), sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
901 encodeQueue.Add(query, getTitle(), sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
903 lbl_encode.Text = encodeQueue.Count + " encode(s) pending in the queue";
\r
905 queueWindow.Show();
\r
909 private void btn_showQueue_Click(object sender, EventArgs e)
\r
911 queueWindow.Show();
\r
912 queueWindow.Activate();
\r
915 private void tb_preview_Click(object sender, EventArgs e)
\r
917 if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
918 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
919 MessageBoxIcon.Warning);
\r
922 if (qtpreview == null)
\r
924 qtpreview = new frmPreview(this);
\r
927 else if (qtpreview.IsDisposed)
\r
929 qtpreview = new frmPreview(this);
\r
933 MessageBox.Show(qtpreview, "The preview window is already open!", "Warning", MessageBoxButtons.OK,
\r
934 MessageBoxIcon.Warning);
\r
938 private void btn_ActivityWindow_Click(object sender, EventArgs e)
\r
940 if (ActivityWindow == null || !ActivityWindow.IsHandleCreated)
\r
941 ActivityWindow = new frmActivityWindow(lastAction, encodeQueue, SourceScan);
\r
943 switch (lastAction)
\r
945 case ActivityLogMode.Scan:
\r
946 ActivityWindow.SetMode(ActivityLogMode.Scan);
\r
948 case ActivityLogMode.Encode:
\r
949 ActivityWindow.SetMode(ActivityLogMode.Encode);
\r
952 ActivityWindow.SetMode(ActivityLogMode.Encode);
\r
956 ActivityWindow.Show();
\r
957 ActivityWindow.Activate();
\r
962 #region System Tray Icon
\r
964 private void frmMain_Resize(object sender, EventArgs e)
\r
966 if (FormWindowState.Minimized == this.WindowState)
\r
968 notifyIcon.Visible = true;
\r
971 else if (FormWindowState.Normal == this.WindowState)
\r
972 notifyIcon.Visible = false;
\r
975 private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
\r
977 this.Visible = true;
\r
979 this.WindowState = FormWindowState.Normal;
\r
980 notifyIcon.Visible = false;
\r
983 private void btn_restore_Click(object sender, EventArgs e)
\r
985 this.Visible = true;
\r
987 this.WindowState = FormWindowState.Normal;
\r
988 notifyIcon.Visible = false;
\r
993 #region Tab Control
\r
996 private void btn_dvd_source_Click(object sender, EventArgs e)
\r
998 if (DVD_Open.ShowDialog() == DialogResult.OK)
\r
1000 this.selectedSourceType = SourceType.Folder;
\r
1001 SelectSource(DVD_Open.SelectedPath);
\r
1004 UpdateSourceLabel();
\r
1007 private void btn_file_source_Click(object sender, EventArgs e)
\r
1009 if (ISO_Open.ShowDialog() == DialogResult.OK)
\r
1011 this.selectedSourceType = SourceType.VideoFile;
\r
1012 SelectSource(ISO_Open.FileName);
\r
1015 UpdateSourceLabel();
\r
1018 private void mnu_dvd_drive_Click(object sender, EventArgs e)
\r
1020 ToolStripMenuItem item = sender as ToolStripMenuItem;
\r
1023 string driveId = item.Name.Replace("Drive", string.Empty);
\r
1025 if (int.TryParse(driveId, out id))
\r
1028 this.dvdDrivePath = drives[id].RootDirectory;
\r
1029 this.dvdDriveLabel = drives[id].VolumeLabel;
\r
1031 if (this.dvdDrivePath == null) return;
\r
1032 this.selectedSourceType = SourceType.DvdDrive;
\r
1033 SelectSource(this.dvdDrivePath);
\r
1038 private void SelectSource(string file)
\r
1040 Check_ChapterMarkers.Enabled = true;
\r
1041 lastAction = ActivityLogMode.Scan;
\r
1042 sourcePath = string.Empty;
\r
1044 if (file == string.Empty) // Must have a file or path
\r
1046 UpdateSourceLabel();
\r
1050 sourcePath = Path.GetFileName(file);
\r
1051 StartScan(file, 0);
\r
1054 private void drp_dvdtitle_Click(object sender, EventArgs e)
\r
1056 if ((drp_dvdtitle.Items.Count == 1) && (drp_dvdtitle.Items[0].ToString() == "Automatic"))
\r
1058 "There are no titles to select. Please load a source file by clicking the 'Source' button above before trying to select a title.",
\r
1059 "Alert", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
\r
1062 private void drp_dvdtitle_SelectedIndexChanged(object sender, EventArgs e)
\r
1064 UnRegisterPresetEventHandler();
\r
1065 drop_mode.SelectedIndex = 0;
\r
1067 drop_chapterStart.Items.Clear();
\r
1068 drop_chapterFinish.Items.Clear();
\r
1070 // If the dropdown is set to automatic nothing else needs to be done.
\r
1071 // Otheriwse if its not, title data has to be loaded from parsing.
\r
1072 if (drp_dvdtitle.Text != "Automatic")
\r
1074 selectedTitle = drp_dvdtitle.SelectedItem as Title;
\r
1075 lbl_duration.Text = selectedTitle.Duration.ToString();
\r
1076 PictureSettings.CurrentlySelectedPreset = CurrentlySelectedPreset;
\r
1077 PictureSettings.Source = selectedTitle; // Setup Picture Settings Tab Control
\r
1079 // Populate the Angles dropdown
\r
1080 drop_angle.Items.Clear();
\r
1081 if (!Properties.Settings.Default.noDvdNav)
\r
1083 drop_angle.Visible = true;
\r
1084 lbl_angle.Visible = true;
\r
1085 drop_angle.Items.AddRange(selectedTitle.Angles.ToArray());
\r
1086 if (drop_angle.Items.Count != 0)
\r
1087 drop_angle.SelectedIndex = 0;
\r
1091 drop_angle.Visible = false;
\r
1092 lbl_angle.Visible = false;
\r
1095 // Populate the Start chapter Dropdown
\r
1096 drop_chapterStart.Items.Clear();
\r
1097 drop_chapterStart.Items.AddRange(selectedTitle.Chapters.ToArray());
\r
1098 if (drop_chapterStart.Items.Count > 0)
\r
1099 drop_chapterStart.Text = drop_chapterStart.Items[0].ToString();
\r
1101 // Populate the Final Chapter Dropdown
\r
1102 drop_chapterFinish.Items.Clear();
\r
1103 drop_chapterFinish.Items.AddRange(selectedTitle.Chapters.ToArray());
\r
1104 if (drop_chapterFinish.Items.Count > 0)
\r
1105 drop_chapterFinish.Text = drop_chapterFinish.Items[drop_chapterFinish.Items.Count - 1].ToString();
\r
1107 // Populate the Audio Channels Dropdown
\r
1108 AudioSettings.SetTrackList(selectedTitle, CurrentlySelectedPreset);
\r
1110 // Populate the Subtitles dropdown
\r
1111 Subtitles.SetSubtitleTrackAuto(selectedTitle.Subtitles.ToArray());
\r
1113 // Update the source label if we have multiple streams
\r
1114 if (selectedTitle != null)
\r
1115 if (!string.IsNullOrEmpty(selectedTitle.SourceName))
\r
1116 labelSource.Text = labelSource.Text = Path.GetFileName(selectedTitle.SourceName);
\r
1118 // Run the AutoName & ChapterNaming functions
\r
1119 if (Properties.Settings.Default.autoNaming)
\r
1121 string autoPath = Main.AutoName(this);
\r
1122 if (autoPath != null)
\r
1123 text_destination.Text = autoPath;
\r
1126 "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
1127 "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
1130 data_chpt.Rows.Clear();
\r
1131 if (selectedTitle.Chapters.Count != 1)
\r
1133 DataGridView chapterGridView = Main.ChapterNaming(data_chpt, drop_chapterFinish.Text);
\r
1134 if (chapterGridView != null)
\r
1135 data_chpt = chapterGridView;
\r
1139 Check_ChapterMarkers.Checked = false;
\r
1140 Check_ChapterMarkers.Enabled = false;
\r
1143 // Hack to force the redraw of the scrollbars which don't resize properly when the control is disabled.
\r
1144 data_chpt.Columns[0].Width = 166;
\r
1145 data_chpt.Columns[0].Width = 165;
\r
1147 RegisterPresetEventHandler();
\r
1150 private void chapersChanged(object sender, EventArgs e)
\r
1152 if (drop_mode.SelectedIndex != 0) // Function is not used if we are not in chapters mode.
\r
1155 Control ctl = (Control)sender;
\r
1156 int chapterStart, chapterEnd;
\r
1157 int.TryParse(drop_chapterStart.Text, out chapterStart);
\r
1158 int.TryParse(drop_chapterFinish.Text, out chapterEnd);
\r
1162 case "drop_chapterStart":
\r
1163 if (drop_chapterFinish.SelectedIndex == -1 && drop_chapterFinish.Items.Count != 0)
\r
1164 drop_chapterFinish.SelectedIndex = drop_chapterFinish.Items.Count - 1;
\r
1166 if (chapterEnd != 0)
\r
1167 if (chapterStart > chapterEnd)
\r
1168 drop_chapterFinish.Text = chapterStart.ToString();
\r
1170 case "drop_chapterFinish":
\r
1171 if (drop_chapterStart.Items.Count >= 1 && drop_chapterStart.SelectedIndex == -1)
\r
1172 drop_chapterStart.SelectedIndex = 0;
\r
1174 if (chapterStart != 0)
\r
1175 if (chapterEnd < chapterStart)
\r
1176 drop_chapterFinish.Text = chapterStart.ToString();
\r
1178 // Add more rows to the Chapter menu if needed.
\r
1179 if (Check_ChapterMarkers.Checked)
\r
1181 int i = data_chpt.Rows.Count, finish = 0;
\r
1182 int.TryParse(drop_chapterFinish.Text, out finish);
\r
1184 while (i < finish)
\r
1186 int n = data_chpt.Rows.Add();
\r
1187 data_chpt.Rows[n].Cells[0].Value = (i + 1);
\r
1188 data_chpt.Rows[n].Cells[1].Value = "Chapter " + (i + 1);
\r
1189 data_chpt.Rows[n].Cells[0].ValueType = typeof(int);
\r
1190 data_chpt.Rows[n].Cells[1].ValueType = typeof(string);
\r
1197 // Update the Duration
\r
1198 lbl_duration.Text =
\r
1199 Main.CalculateDuration(drop_chapterStart.SelectedIndex, drop_chapterFinish.SelectedIndex, selectedTitle)
\r
1202 // Run the Autonaming function
\r
1203 if (Properties.Settings.Default.autoNaming)
\r
1204 text_destination.Text = Main.AutoName(this);
\r
1206 // Disable chapter markers if only 1 chapter is selected.
\r
1207 if (chapterStart == chapterEnd)
\r
1209 Check_ChapterMarkers.Enabled = false;
\r
1210 btn_importChapters.Enabled = false;
\r
1211 data_chpt.Enabled = false;
\r
1215 Check_ChapterMarkers.Enabled = true;
\r
1216 if (Check_ChapterMarkers.Checked)
\r
1218 btn_importChapters.Enabled = true;
\r
1219 data_chpt.Enabled = true;
\r
1224 private void SecondsOrFramesChanged(object sender, EventArgs e)
\r
1227 int.TryParse(drop_chapterStart.Text, out start);
\r
1228 int.TryParse(drop_chapterFinish.Text, out end);
\r
1229 double duration = end - start;
\r
1231 switch (drop_mode.SelectedIndex)
\r
1234 lbl_duration.Text = TimeSpan.FromSeconds(duration).ToString();
\r
1237 if (selectedTitle != null)
\r
1239 duration = duration / selectedTitle.Fps;
\r
1240 lbl_duration.Text = TimeSpan.FromSeconds(duration).ToString();
\r
1243 lbl_duration.Text = "--:--:--";
\r
1249 private void drop_mode_SelectedIndexChanged(object sender, EventArgs e)
\r
1252 this.drop_chapterFinish.TextChanged -= new EventHandler(this.SecondsOrFramesChanged);
\r
1253 this.drop_chapterStart.TextChanged -= new EventHandler(this.SecondsOrFramesChanged);
\r
1256 switch (drop_mode.SelectedIndex)
\r
1259 drop_chapterStart.DropDownStyle = ComboBoxStyle.DropDownList;
\r
1260 drop_chapterFinish.DropDownStyle = ComboBoxStyle.DropDownList;
\r
1261 if (drop_chapterStart.Items.Count != 0)
\r
1263 drop_chapterStart.SelectedIndex = 0;
\r
1264 drop_chapterFinish.SelectedIndex = drop_chapterFinish.Items.Count - 1;
\r
1267 lbl_duration.Text = "--:--:--";
\r
1270 this.drop_chapterStart.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1271 this.drop_chapterFinish.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1272 drop_chapterStart.DropDownStyle = ComboBoxStyle.Simple;
\r
1273 drop_chapterFinish.DropDownStyle = ComboBoxStyle.Simple;
\r
1274 if (selectedTitle != null)
\r
1276 drop_chapterStart.Text = "0";
\r
1277 drop_chapterFinish.Text = selectedTitle.Duration.TotalSeconds.ToString();
\r
1281 this.drop_chapterStart.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1282 this.drop_chapterFinish.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1283 drop_chapterStart.DropDownStyle = ComboBoxStyle.Simple;
\r
1284 drop_chapterFinish.DropDownStyle = ComboBoxStyle.Simple;
\r
1285 if (selectedTitle != null)
\r
1287 drop_chapterStart.Text = "0";
\r
1288 drop_chapterFinish.Text = (selectedTitle.Fps * selectedTitle.Duration.TotalSeconds).ToString();
\r
1295 private void btn_destBrowse_Click(object sender, EventArgs e)
\r
1297 // This removes the file extension from the filename box on the save file dialog.
\r
1298 // It's daft but some users don't realise that typing an extension overrides the dropdown extension selected.
\r
1299 DVD_Save.FileName = Path.GetFileNameWithoutExtension(text_destination.Text);
\r
1301 if (Path.IsPathRooted(text_destination.Text))
\r
1302 DVD_Save.InitialDirectory = Path.GetDirectoryName(text_destination.Text);
\r
1304 // Show the dialog and set the main form file path
\r
1305 if (drop_format.SelectedIndex.Equals(0))
\r
1306 DVD_Save.FilterIndex = 1;
\r
1307 else if (drop_format.SelectedIndex.Equals(1))
\r
1308 DVD_Save.FilterIndex = 2;
\r
1310 if (DVD_Save.ShowDialog() == DialogResult.OK)
\r
1312 // Add a file extension manually, as FileDialog.AddExtension has issues with dots in filenames
\r
1313 switch (DVD_Save.FilterIndex)
\r
1317 !Path.GetExtension(DVD_Save.FileName).Equals(".mp4",
\r
1318 StringComparison.InvariantCultureIgnoreCase))
\r
1319 if (Properties.Settings.Default.useM4v)
\r
1320 DVD_Save.FileName = DVD_Save.FileName.Replace(".mp4", ".m4v").Replace(".mkv", ".m4v");
\r
1322 DVD_Save.FileName = DVD_Save.FileName.Replace(".m4v", ".mp4").Replace(".mkv", ".mp4");
\r
1326 !Path.GetExtension(DVD_Save.FileName).Equals(".mkv", StringComparison.InvariantCultureIgnoreCase))
\r
1327 DVD_Save.FileName = DVD_Save.FileName.Replace(".mp4", ".mkv").Replace(".m4v", ".mkv");
\r
1333 text_destination.Text = DVD_Save.FileName;
\r
1335 // Quicktime requires .m4v file for chapter markers to work. If checked, change the extension to .m4v (mp4 and m4v are the same thing)
\r
1336 if (Check_ChapterMarkers.Checked && DVD_Save.FilterIndex != 2)
\r
1337 SetExtension(".m4v");
\r
1341 private void text_destination_TextChanged(object sender, EventArgs e)
\r
1343 string path = text_destination.Text;
\r
1344 if (path.EndsWith(".mp4") || path.EndsWith(".m4v"))
\r
1345 drop_format.SelectedIndex = 0;
\r
1346 else if (path.EndsWith(".mkv"))
\r
1347 drop_format.SelectedIndex = 1;
\r
1350 // Output Settings
\r
1351 private void drop_format_SelectedIndexChanged(object sender, EventArgs e)
\r
1353 switch (drop_format.SelectedIndex)
\r
1356 if (Properties.Settings.Default.useM4v || Check_ChapterMarkers.Checked ||
\r
1357 AudioSettings.RequiresM4V() || Subtitles.RequiresM4V())
\r
1358 SetExtension(".m4v");
\r
1360 SetExtension(".mp4");
\r
1363 SetExtension(".mkv");
\r
1367 AudioSettings.SetContainer(drop_format.Text);
\r
1368 Subtitles.SetContainer(drop_format.SelectedIndex);
\r
1370 if (drop_format.Text.Contains("MP4"))
\r
1372 if (drp_videoEncoder.Items.Contains("VP3 (Theora)"))
\r
1374 drp_videoEncoder.Items.Remove("VP3 (Theora)");
\r
1375 drp_videoEncoder.SelectedIndex = 1;
\r
1378 else if (drop_format.Text.Contains("MKV"))
\r
1379 drp_videoEncoder.Items.Add("VP3 (Theora)");
\r
1382 public void SetExtension(string newExtension)
\r
1384 if (newExtension == ".mp4" || newExtension == ".m4v")
\r
1385 if (Properties.Settings.Default.useM4v || Check_ChapterMarkers.Checked || AudioSettings.RequiresM4V() ||
\r
1386 Subtitles.RequiresM4V())
\r
1387 newExtension = ".m4v";
\r
1389 newExtension = ".mp4";
\r
1391 if (Path.HasExtension(newExtension))
\r
1392 text_destination.Text = Path.ChangeExtension(text_destination.Text, newExtension);
\r
1396 private void drp_videoEncoder_SelectedIndexChanged(object sender, EventArgs e)
\r
1398 setContainerOpts();
\r
1400 // Turn off some options which are H.264 only when the user selects a non h.264 encoder
\r
1401 if (drp_videoEncoder.Text.Contains("H.264"))
\r
1403 if (check_2PassEncode.CheckState == CheckState.Checked)
\r
1404 check_turbo.Enabled = true;
\r
1406 tab_advanced.Enabled = true;
\r
1407 if ((drop_format.Text.Contains("MP4")) || (drop_format.Text.Contains("M4V")))
\r
1408 check_iPodAtom.Enabled = true;
\r
1410 check_iPodAtom.Enabled = false;
\r
1414 check_turbo.CheckState = CheckState.Unchecked;
\r
1415 check_turbo.Enabled = false;
\r
1416 tab_advanced.Enabled = false;
\r
1417 x264Panel.X264Query = string.Empty;
\r
1418 check_iPodAtom.Enabled = false;
\r
1419 check_iPodAtom.Checked = false;
\r
1422 // Setup the CQ Slider
\r
1423 switch (drp_videoEncoder.Text)
\r
1425 case "MPEG-4 (FFmpeg)":
\r
1426 if (slider_videoQuality.Value > 31)
\r
1427 slider_videoQuality.Value = 20; // Just reset to 70% QP 10 on encode change.
\r
1428 slider_videoQuality.Minimum = 1;
\r
1429 slider_videoQuality.Maximum = 31;
\r
1431 case "H.264 (x264)":
\r
1432 slider_videoQuality.Minimum = 0;
\r
1433 slider_videoQuality.TickFrequency = 1;
\r
1435 CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
\r
1436 double cqStep = Properties.Settings.Default.x264cqstep;
\r
1437 double multiplier = 1.0 / cqStep;
\r
1438 double value = slider_videoQuality.Value * multiplier;
\r
1440 slider_videoQuality.Maximum = (int)(51 / Properties.Settings.Default.x264cqstep);
\r
1442 if (value < slider_videoQuality.Maximum)
\r
1443 slider_videoQuality.Value = slider_videoQuality.Maximum - (int)value;
\r
1446 case "VP3 (Theora)":
\r
1447 if (slider_videoQuality.Value > 63)
\r
1448 slider_videoQuality.Value = 45; // Just reset to 70% QP 45 on encode change.
\r
1449 slider_videoQuality.Minimum = 0;
\r
1450 slider_videoQuality.Maximum = 63;
\r
1456 /// Set the container format options
\r
1458 public void setContainerOpts()
\r
1460 if ((drop_format.Text.Contains("MP4")) || (drop_format.Text.Contains("M4V")))
\r
1462 check_largeFile.Enabled = true;
\r
1463 check_optimiseMP4.Enabled = true;
\r
1464 check_iPodAtom.Enabled = true;
\r
1468 check_largeFile.Enabled = false;
\r
1469 check_optimiseMP4.Enabled = false;
\r
1470 check_iPodAtom.Enabled = false;
\r
1471 check_largeFile.Checked = false;
\r
1472 check_optimiseMP4.Checked = false;
\r
1473 check_iPodAtom.Checked = false;
\r
1477 private double _cachedCqStep = Properties.Settings.Default.x264cqstep;
\r
1480 /// Update the CQ slider for x264 for a new CQ step. This is set from option
\r
1482 public void setQualityFromSlider()
\r
1484 // Work out the current RF value.
\r
1485 double cqStep = _cachedCqStep;
\r
1486 double rfValue = 51.0 - slider_videoQuality.Value * cqStep;
\r
1488 // Change the maximum value for the slider
\r
1489 slider_videoQuality.Maximum = (int)(51 / Properties.Settings.Default.x264cqstep);
\r
1491 // Reset the CQ slider to RF0
\r
1492 slider_videoQuality.Value = slider_videoQuality.Maximum;
\r
1494 // Reset the CQ slider back to the previous value as close as possible
\r
1495 double cqStepNew = Properties.Settings.Default.x264cqstep;
\r
1496 double rfValueCurrent = 51.0 - slider_videoQuality.Value * cqStepNew;
\r
1497 while (rfValueCurrent < rfValue)
\r
1499 slider_videoQuality.Value--;
\r
1500 rfValueCurrent = 51.0 - slider_videoQuality.Value * cqStepNew;
\r
1503 // Cache the CQ step for the next calculation
\r
1504 _cachedCqStep = Properties.Settings.Default.x264cqstep;
\r
1507 private void slider_videoQuality_Scroll(object sender, EventArgs e)
\r
1509 double cqStep = Properties.Settings.Default.x264cqstep;
\r
1510 switch (drp_videoEncoder.Text)
\r
1512 case "MPEG-4 (FFmpeg)":
\r
1513 lbl_SliderValue.Text = "QP:" + (32 - slider_videoQuality.Value);
\r
1515 case "H.264 (x264)":
\r
1516 double rfValue = 51.0 - slider_videoQuality.Value * cqStep;
\r
1517 rfValue = Math.Round(rfValue, 2);
\r
1518 lbl_SliderValue.Text = "RF:" + rfValue.ToString(new CultureInfo("en-US"));
\r
1520 case "VP3 (Theora)":
\r
1521 lbl_SliderValue.Text = "QP:" + slider_videoQuality.Value;
\r
1526 private void radio_targetFilesize_CheckedChanged(object sender, EventArgs e)
\r
1528 text_bitrate.Enabled = false;
\r
1529 text_filesize.Enabled = true;
\r
1530 slider_videoQuality.Enabled = false;
\r
1532 check_2PassEncode.Enabled = true;
\r
1535 private void radio_avgBitrate_CheckedChanged(object sender, EventArgs e)
\r
1537 text_bitrate.Enabled = true;
\r
1538 text_filesize.Enabled = false;
\r
1539 slider_videoQuality.Enabled = false;
\r
1541 check_2PassEncode.Enabled = true;
\r
1544 private void radio_cq_CheckedChanged(object sender, EventArgs e)
\r
1546 text_bitrate.Enabled = false;
\r
1547 text_filesize.Enabled = false;
\r
1548 slider_videoQuality.Enabled = true;
\r
1550 check_2PassEncode.Enabled = false;
\r
1551 check_2PassEncode.CheckState = CheckState.Unchecked;
\r
1554 private void check_2PassEncode_CheckedChanged(object sender, EventArgs e)
\r
1556 if (check_2PassEncode.CheckState.ToString() == "Checked")
\r
1558 if (drp_videoEncoder.Text.Contains("H.264"))
\r
1559 check_turbo.Enabled = true;
\r
1563 check_turbo.Enabled = false;
\r
1564 check_turbo.CheckState = CheckState.Unchecked;
\r
1568 // Chapter Marker Tab
\r
1569 private void Check_ChapterMarkers_CheckedChanged(object sender, EventArgs e)
\r
1571 if (Check_ChapterMarkers.Checked)
\r
1573 if (drop_format.SelectedIndex != 1)
\r
1574 SetExtension(".m4v");
\r
1575 data_chpt.Enabled = true;
\r
1576 btn_importChapters.Enabled = true;
\r
1580 if (drop_format.SelectedIndex != 1 && !Properties.Settings.Default.useM4v)
\r
1581 SetExtension(".mp4");
\r
1582 data_chpt.Enabled = false;
\r
1583 btn_importChapters.Enabled = false;
\r
1587 private void btn_importChapters_Click(object sender, EventArgs e)
\r
1589 if (File_ChapterImport.ShowDialog() == DialogResult.OK)
\r
1591 string filename = File_ChapterImport.FileName;
\r
1592 DataGridView imported = Main.ImportChapterNames(data_chpt, filename);
\r
1593 if (imported != null)
\r
1594 data_chpt = imported;
\r
1598 private void mnu_resetChapters_Click(object sender, EventArgs e)
\r
1600 data_chpt.Rows.Clear();
\r
1601 DataGridView chapterGridView = Main.ChapterNaming(data_chpt, drop_chapterFinish.Text);
\r
1602 if (chapterGridView != null)
\r
1604 data_chpt = chapterGridView;
\r
1608 // Query Editor Tab
\r
1609 private void btn_generate_Query_Click(object sender, EventArgs e)
\r
1611 rtf_query.Text = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
1614 private void btn_clear_Click(object sender, EventArgs e)
\r
1616 rtf_query.Clear();
\r
1621 // MainWindow Components, Actions and Functions ***********************
\r
1623 #region Source Scan
\r
1625 public bool isScanning { get; set; }
\r
1627 private void StartScan(string filename, int title)
\r
1629 // Setup the GUI components for the scan.
\r
1630 sourcePath = filename;
\r
1632 this.DisableGUI();
\r
1634 if (ActivityWindow != null)
\r
1635 ActivityWindow.SetMode(ActivityLogMode.Scan);
\r
1640 isScanning = true;
\r
1641 SourceScan = new Scan();
\r
1642 SourceScan.ScanSource(sourcePath, title);
\r
1643 SourceScan.ScanStatusChanged += new EventHandler(SourceScan_ScanStatusChanged);
\r
1644 SourceScan.ScanCompleted += new EventHandler(SourceScan_ScanCompleted);
\r
1646 catch (Exception exc)
\r
1648 MessageBox.Show("frmMain.cs - StartScan " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1652 private void SourceScan_ScanStatusChanged(object sender, EventArgs e)
\r
1654 UpdateScanStatusLabel();
\r
1657 private void SourceScan_ScanCompleted(object sender, EventArgs e)
\r
1659 UpdateGuiAfterScan();
\r
1662 private void UpdateScanStatusLabel()
\r
1664 if (InvokeRequired)
\r
1666 BeginInvoke(new UpdateWindowHandler(UpdateScanStatusLabel));
\r
1669 lbl_encode.Text = SourceScan.ScanStatus();
\r
1672 private void UpdateGuiAfterScan()
\r
1674 if (InvokeRequired)
\r
1676 BeginInvoke(new UpdateWindowHandler(UpdateGuiAfterScan));
\r
1682 currentSource = SourceScan.SouceData();
\r
1684 // Setup some GUI components
\r
1685 drp_dvdtitle.Items.Clear();
\r
1686 if (currentSource.Titles.Count != 0)
\r
1687 drp_dvdtitle.Items.AddRange(currentSource.Titles.ToArray());
\r
1689 foreach (Title title in currentSource.Titles)
\r
1691 if (title.MainTitle)
\r
1693 drp_dvdtitle.SelectedItem = title;
\r
1697 // Enable the creation of chapter markers if the file is an image of a dvd.
\r
1699 int.TryParse(drop_chapterStart.Items[0].ToString(), out start);
\r
1700 int.TryParse(drop_chapterFinish.Items[drop_chapterFinish.Items.Count - 1].ToString(), out end);
\r
1702 Check_ChapterMarkers.Enabled = true;
\r
1705 Check_ChapterMarkers.Enabled = false;
\r
1706 Check_ChapterMarkers.Checked = false;
\r
1707 data_chpt.Rows.Clear();
\r
1710 // If no titles were found, Display an error message
\r
1711 if (drp_dvdtitle.Items.Count == 0)
\r
1714 "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
1715 "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
\r
1716 sourcePath = string.Empty;
\r
1718 UpdateSourceLabel();
\r
1720 // Enable the GUI components and enable any disabled components
\r
1723 catch (Exception exc)
\r
1725 MessageBox.Show("frmMain.cs - updateUIafterScan " + exc, "Error", MessageBoxButtons.OK,
\r
1726 MessageBoxIcon.Error);
\r
1731 private void EnableGUI()
\r
1735 if (InvokeRequired)
\r
1736 BeginInvoke(new UpdateWindowHandler(EnableGUI));
\r
1737 lbl_encode.Text = "Scan Completed";
\r
1738 foreach (Control ctrl in Controls)
\r
1739 ctrl.Enabled = true;
\r
1740 btn_start.Enabled = true;
\r
1741 btn_showQueue.Enabled = true;
\r
1742 btn_add2Queue.Enabled = true;
\r
1743 tb_preview.Enabled = true;
\r
1744 btn_source.Enabled = true;
\r
1745 mnu_killCLI.Visible = false;
\r
1747 catch (Exception exc)
\r
1749 MessageBox.Show("frmMain.cs - EnableGUI() " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1753 private void DisableGUI()
\r
1755 foreach (Control ctrl in Controls)
\r
1756 if (!(ctrl is StatusStrip || ctrl is MenuStrip || ctrl is ToolStrip))
\r
1757 ctrl.Enabled = false;
\r
1759 lbl_encode.Visible = true;
\r
1760 lbl_encode.Text = "Scanning ...";
\r
1761 btn_source.Enabled = false;
\r
1762 btn_start.Enabled = false;
\r
1763 btn_showQueue.Enabled = false;
\r
1764 btn_add2Queue.Enabled = false;
\r
1765 tb_preview.Enabled = false;
\r
1766 mnu_killCLI.Visible = true;
\r
1769 private void KillScan()
\r
1773 SourceScan.ScanCompleted -= new EventHandler(SourceScan_ScanCompleted);
\r
1777 if (SourceScan.ScanProcess() != null)
\r
1778 SourceScan.ScanProcess().Kill();
\r
1780 lbl_encode.Text = "Scan Cancelled!";
\r
1782 catch (Exception ex)
\r
1785 "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
1786 ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1790 private void ResetGUI()
\r
1792 drp_dvdtitle.Items.Clear();
\r
1793 drop_chapterStart.Items.Clear();
\r
1794 drop_chapterFinish.Items.Clear();
\r
1795 lbl_duration.Text = "Select a Title";
\r
1796 PictureSettings.lbl_src_res.Text = "Select a Title";
\r
1797 sourcePath = String.Empty;
\r
1798 text_destination.Text = String.Empty;
\r
1799 selectedTitle = null;
\r
1800 isScanning = false;
\r
1803 private void UpdateSourceLabel()
\r
1805 labelSource.Text = string.IsNullOrEmpty(sourcePath) ? "Select \"Source\" to continue." : this.SourceName;
\r
1807 if (selectedTitle != null)
\r
1808 if (!string.IsNullOrEmpty(selectedTitle.SourceName))
\r
1809 // If it's one of multiple source files, make sure we don't use the folder name
\r
1810 labelSource.Text = Path.GetFileName(selectedTitle.SourceName);
\r
1813 public void RecievingJob(Job job)
\r
1815 string query = job.Query;
\r
1816 StartScan(job.Source, job.Title);
\r
1818 if (query != null)
\r
1820 // Ok, Reset all the H264 widgets before changing the preset
\r
1821 x264Panel.Reset2Defaults();
\r
1823 // Send the query from the file to the Query Parser class
\r
1824 QueryParser presetQuery = QueryParser.Parse(query);
\r
1826 // Now load the preset
\r
1827 PresetLoader.LoadPreset(this, presetQuery, "Load Back From Queue", true);
\r
1829 // The x264 widgets will need updated, so do this now:
\r
1830 x264Panel.X264_StandardizeOptString();
\r
1831 x264Panel.X264_SetCurrentSettingsInPanel();
\r
1833 // Finally, let this window have a copy of the preset settings.
\r
1834 CurrentlySelectedPreset = null;
\r
1835 PictureSettings.SetPresetCropWarningLabel(null);
\r
1841 #region GUI Functions and Actions
\r
1844 /// Set the GUI to it's finished encoding state.
\r
1846 private void SetEncodeFinished()
\r
1850 if (InvokeRequired)
\r
1852 BeginInvoke(new UpdateWindowHandler(SetEncodeFinished));
\r
1856 lbl_encode.Text = "Encoding Finished";
\r
1857 btn_start.Text = "Start";
\r
1858 btn_start.ToolTipText = "Start the encoding process";
\r
1859 btn_start.Image = Properties.Resources.Play;
\r
1861 // If the window is minimized, display the notification in a popup.
\r
1862 if (Properties.Settings.Default.trayIconAlerts)
\r
1863 if (FormWindowState.Minimized == this.WindowState)
\r
1865 notifyIcon.BalloonTipText = lbl_encode.Text;
\r
1866 notifyIcon.ShowBalloonTip(500);
\r
1869 catch (Exception exc)
\r
1871 MessageBox.Show(exc.ToString());
\r
1876 /// Set the GUI to it's started encoding state.
\r
1878 private void SetEncodeStarted()
\r
1882 if (InvokeRequired)
\r
1884 BeginInvoke(new UpdateWindowHandler(SetEncodeStarted));
\r
1888 lbl_encode.Visible = true;
\r
1889 lbl_encode.Text = "Encoding with " + encodeQueue.Count + " encode(s) pending";
\r
1890 btn_start.Text = "Stop";
\r
1891 btn_start.ToolTipText = "Stop the encoding process.";
\r
1892 btn_start.Image = Properties.Resources.stop;
\r
1894 catch (Exception exc)
\r
1896 MessageBox.Show(exc.ToString());
\r
1901 /// Set the DVD Drive selection in the "Source" Menu
\r
1903 private void SetDriveSelectionMenuItem()
\r
1907 if (InvokeRequired)
\r
1909 BeginInvoke(new UpdateWindowHandler(SetDriveSelectionMenuItem));
\r
1913 drives = Main.GetDrives();
\r
1915 List<ToolStripMenuItem> menuItems = new List<ToolStripMenuItem>();
\r
1916 foreach (DriveInformation drive in drives)
\r
1918 ToolStripMenuItem menuItem = new ToolStripMenuItem();
\r
1919 menuItem.Name = drive.ToString();
\r
1920 menuItem.Text = drive.RootDirectory + " (" + drive.VolumeLabel + ")";
\r
1921 menuItem.Image = Resources.disc_small;
\r
1922 menuItem.Click += new EventHandler(mnu_dvd_drive_Click);
\r
1923 menuItems.Add(menuItem);
\r
1926 foreach (ToolStripMenuItem item in menuItems)
\r
1927 btn_source.DropDownItems.Add(item);
\r
1929 catch (Exception exc)
\r
1931 MessageBox.Show("Error in SetDriveSelectionMenuItem" + exc);
\r
1936 /// Access the preset Handler and setup the preset panel.
\r
1938 private void LoadPresetPanel()
\r
1940 if (presetHandler.CheckIfPresetsAreOutOfDate())
\r
1941 if (!Properties.Settings.Default.presetNotification)
\r
1942 MessageBox.Show(splash,
\r
1943 "HandBrake has determined your built-in presets are out of date... These presets will now be updated.",
\r
1944 "Preset Update", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
1946 presetHandler.GetPresetPanel(ref treeView_presets);
\r
1947 treeView_presets.Update();
\r
1951 /// Get the title from the selected item in the title dropdown.
\r
1956 private int getTitle()
\r
1959 if (drp_dvdtitle.SelectedItem != null)
\r
1961 string[] titleInfo = drp_dvdtitle.SelectedItem.ToString().Split(' ');
\r
1962 int.TryParse(titleInfo[0], out title);
\r
1973 /// Handle GUI shortcuts
\r
1975 /// <param name="msg"></param>
\r
1976 /// <param name="keyData"></param>
\r
1977 /// <returns></returns>
\r
1978 protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
\r
1980 if (keyData == (Keys.Control | Keys.S))
\r
1982 btn_start_Click(this, new EventArgs());
\r
1986 if (keyData == (Keys.Control | Keys.A))
\r
1988 btn_add2Queue_Click(this, new EventArgs());
\r
1991 return base.ProcessCmdKey(ref msg, keyData);
\r
1995 /// If the queue is being processed, prompt the user to confirm application close.
\r
1997 /// <param name="e"></param>
\r
1998 protected override void OnFormClosing(FormClosingEventArgs e)
\r
2000 // If currently encoding, the queue isn't paused, and there are queue items to process, prompt to confirm close.
\r
2001 if ((encodeQueue.IsEncoding) && (!encodeQueue.PauseRequested) && (encodeQueue.Count > 0))
\r
2003 DialogResult result =
\r
2005 "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
2006 "Close HandBrake?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
2007 if (result == DialogResult.No)
\r
2010 base.OnFormClosing(e);
\r
2015 #region In-GUI Encode Status (Experimental)
\r
2018 /// Starts a new thread to monitor and process the CLI encode status
\r
2020 private void EncodeMonitorThread()
\r
2024 Parser encode = new Parser(encodeQueue.HbProcess.StandardOutput.BaseStream);
\r
2025 encode.OnEncodeProgress += EncodeOnEncodeProgress;
\r
2026 while (!encode.EndOfStream)
\r
2027 encode.ReadEncodeStatus();
\r
2029 catch (Exception exc)
\r
2031 MessageBox.Show(exc.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
2036 /// Displays the Encode status in the GUI
\r
2038 /// <param name="Sender"></param>
\r
2039 /// <param name="CurrentTask"></param>
\r
2040 /// <param name="TaskCount"></param>
\r
2041 /// <param name="PercentComplete"></param>
\r
2042 /// <param name="CurrentFps"></param>
\r
2043 /// <param name="AverageFps"></param>
\r
2044 /// <param name="TimeRemaining"></param>
\r
2045 private void EncodeOnEncodeProgress(object Sender, int CurrentTask, int TaskCount, float PercentComplete, float CurrentFps, float AverageFps, TimeSpan TimeRemaining)
\r
2047 if (this.InvokeRequired)
\r
2050 new EncodeProgressEventHandler(EncodeOnEncodeProgress),
\r
2051 new[] { Sender, CurrentTask, TaskCount, PercentComplete, CurrentFps, AverageFps, TimeRemaining });
\r
2055 string.Format("Encode Progress: {0}%, FPS: {1}, Avg FPS: {2}, Time Remaining: {3} ", PercentComplete, CurrentFps, AverageFps, TimeRemaining);
\r
2060 // This is the END of the road ****************************************
\r