3 This file is part of the HandBrake source code.
\r
4 Homepage: <http://handbrake.fr/>.
\r
5 It may be used under the terms of the GNU General Public License. */
\r
10 using System.Collections.Generic;
\r
11 using System.ComponentModel;
\r
12 using System.Diagnostics;
\r
13 using System.Drawing;
\r
14 using System.Globalization;
\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 = "Setting Version Data ...";
\r
66 Application.DoEvents();
\r
67 Main.SetCliVersionData();
\r
69 // Show the form, but leave disabled until preloading is complete then show the main form
\r
70 this.Enabled = false;
\r
72 Application.DoEvents(); // Forces frmMain to draw
\r
74 // Check for new versions, if update checking is enabled
\r
75 if (Properties.Settings.Default.updateStatus)
\r
77 DateTime now = DateTime.Now;
\r
78 DateTime lastCheck = Properties.Settings.Default.lastUpdateCheckDate;
\r
79 TimeSpan elapsed = now.Subtract(lastCheck);
\r
80 if (elapsed.TotalDays > Properties.Settings.Default.daysBetweenUpdateCheck)
\r
82 lblStatus.Text = "Checking for updates ...";
\r
83 Application.DoEvents();
\r
85 Main.BeginCheckForUpdates(new AsyncCallback(UpdateCheckDone), false);
\r
89 // Clear the log files in the background
\r
90 if (Properties.Settings.Default.clearOldLogs)
\r
92 lblStatus.Text = "Clearing Old Log Files ...";
\r
93 Application.DoEvents();
\r
94 Thread clearLog = new Thread(Main.ClearOldLogs);
\r
98 // Setup the GUI components
\r
99 lblStatus.Text = "Setting up the GUI ...";
\r
100 Application.DoEvents();
\r
101 LoadPresetPanel(); // Load the Preset Panel
\r
102 treeView_presets.ExpandAll();
\r
103 lbl_encode.Text = string.Empty;
\r
104 drop_mode.SelectedIndex = 0;
\r
105 queueWindow = new frmQueue(encodeQueue, this); // Prepare the Queue
\r
106 if (!Properties.Settings.Default.QueryEditorTab)
\r
107 tabs_panel.TabPages.RemoveAt(7); // Remove the query editor tab if the user does not want it enabled.
\r
109 // Load the user's default settings or Normal Preset
\r
110 if (Properties.Settings.Default.defaultPreset != string.Empty)
\r
112 if (presetHandler.GetPreset(Properties.Settings.Default.defaultPreset) != null)
\r
114 string query = presetHandler.GetPreset(Properties.Settings.Default.defaultPreset).Query;
\r
115 bool loadPictureSettings =
\r
116 presetHandler.GetPreset(Properties.Settings.Default.defaultPreset).PictureSettings;
\r
120 x264Panel.Reset2Defaults();
\r
122 QueryParser presetQuery = QueryParser.Parse(query);
\r
123 PresetLoader.LoadPreset(this, presetQuery, Properties.Settings.Default.defaultPreset,
\r
124 loadPictureSettings);
\r
126 x264Panel.X264_StandardizeOptString();
\r
127 x264Panel.X264_SetCurrentSettingsInPanel();
\r
131 loadNormalPreset();
\r
134 loadNormalPreset();
\r
136 // Enabled GUI tooltip's if Required
\r
137 if (Properties.Settings.Default.tooltipEnable)
\r
138 ToolTip.Active = true;
\r
140 // Register with Growl (if not using Growl for the encoding completion action, this wont hurt anything)
\r
141 GrowlCommunicator.Register();
\r
143 // Finished Loading
\r
144 lblStatus.Text = "Loading Complete!";
\r
145 Application.DoEvents();
\r
148 this.Enabled = true;
\r
150 // Event Handlers and Queue Recovery
\r
155 private void UpdateCheckDone(IAsyncResult result)
\r
157 if (InvokeRequired)
\r
159 Invoke(new MethodInvoker(() => UpdateCheckDone(result)));
\r
163 UpdateCheckInformation info;
\r
167 info = Main.EndCheckForUpdates(result);
\r
169 if (info.NewVersionAvailable)
\r
171 frmUpdater updateWindow = new frmUpdater(info.BuildInformation);
\r
172 updateWindow.ShowDialog();
\r
175 catch (Exception ex)
\r
177 if ((bool)result.AsyncState)
\r
179 "Unable to check for updates, Please try again later.\n\nDetailed Error Information:\n" + ex,
\r
180 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
184 // Startup Functions
\r
185 private void queueRecovery()
\r
187 if (Main.CheckQueueRecovery())
\r
189 DialogResult result =
\r
191 "HandBrake has detected unfinished items on the queue from the last time the application was launched. Would you like to recover these?",
\r
192 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
194 if (result == DialogResult.Yes)
\r
195 encodeQueue.LoadQueueFromFile("hb_queue_recovery.xml"); // Start Recovery
\r
198 // Remove the Queue recovery file if the user doesn't want to recovery the last queue.
\r
199 string queuePath = Path.Combine(Path.GetTempPath(), "hb_queue_recovery.xml");
\r
200 if (File.Exists(queuePath))
\r
201 File.Delete(queuePath);
\r
210 public string SourceName
\r
214 if (this.selectedSourceType == SourceType.DvdDrive)
\r
216 return this.dvdDriveLabel;
\r
219 if (Path.GetFileNameWithoutExtension(this.sourcePath) != "VIDEO_TS")
\r
220 return Path.GetFileNameWithoutExtension(this.sourcePath);
\r
222 return Path.GetFileNameWithoutExtension(Path.GetDirectoryName(this.sourcePath));
\r
230 // Encoding Events for setting up the GUI
\r
231 private void events()
\r
233 // Handle Widget changes when preset is selected.
\r
234 RegisterPresetEventHandler();
\r
236 // Handle Window Resize
\r
237 if (Properties.Settings.Default.MainWindowMinimize)
\r
238 this.Resize += new EventHandler(frmMain_Resize);
\r
240 // Handle Encode Start / Finish / Pause
\r
242 encodeQueue.QueuePauseRequested += new EventHandler(encodePaused);
\r
243 encodeQueue.EncodeStarted += new EventHandler(encodeStarted);
\r
244 encodeQueue.EncodeEnded += new EventHandler(encodeEnded);
\r
246 // Handle a file being draged onto the GUI.
\r
247 this.DragEnter += new DragEventHandler(frmMain_DragEnter);
\r
248 this.DragDrop += new DragEventHandler(frmMain_DragDrop);
\r
251 // 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
252 private void RegisterPresetEventHandler()
\r
255 drop_format.SelectedIndexChanged += new EventHandler(changePresetLabel);
\r
256 check_largeFile.CheckedChanged += new EventHandler(changePresetLabel);
\r
257 check_iPodAtom.CheckedChanged += new EventHandler(changePresetLabel);
\r
258 check_optimiseMP4.CheckedChanged += new EventHandler(changePresetLabel);
\r
260 // Picture Settings
\r
261 // PictureSettings.PictureSettingsChanged += new EventHandler(changePresetLabel);
\r
264 Filters.FilterSettingsChanged += new EventHandler(changePresetLabel);
\r
267 drp_videoEncoder.SelectedIndexChanged += new EventHandler(changePresetLabel);
\r
268 check_2PassEncode.CheckedChanged += new EventHandler(changePresetLabel);
\r
269 check_turbo.CheckedChanged += new EventHandler(changePresetLabel);
\r
270 text_filesize.TextChanged += new EventHandler(changePresetLabel);
\r
271 text_bitrate.TextChanged += new EventHandler(changePresetLabel);
\r
272 slider_videoQuality.ValueChanged += new EventHandler(changePresetLabel);
\r
275 AudioSettings.AudioListChanged += new EventHandler(changePresetLabel);
\r
278 x264Panel.rtf_x264Query.TextChanged += new EventHandler(changePresetLabel);
\r
281 private void UnRegisterPresetEventHandler()
\r
283 // Output Settings
\r
284 drop_format.SelectedIndexChanged -= new EventHandler(changePresetLabel);
\r
285 check_largeFile.CheckedChanged -= new EventHandler(changePresetLabel);
\r
286 check_iPodAtom.CheckedChanged -= new EventHandler(changePresetLabel);
\r
287 check_optimiseMP4.CheckedChanged -= new EventHandler(changePresetLabel);
\r
289 // Picture Settings
\r
290 // PictureSettings.PictureSettingsChanged -= new EventHandler(changePresetLabel);
\r
293 Filters.FilterSettingsChanged -= new EventHandler(changePresetLabel);
\r
296 drp_videoEncoder.SelectedIndexChanged -= new EventHandler(changePresetLabel);
\r
297 check_2PassEncode.CheckedChanged -= new EventHandler(changePresetLabel);
\r
298 check_turbo.CheckedChanged -= new EventHandler(changePresetLabel);
\r
299 text_filesize.TextChanged -= new EventHandler(changePresetLabel);
\r
300 text_bitrate.TextChanged -= new EventHandler(changePresetLabel);
\r
301 slider_videoQuality.ValueChanged -= new EventHandler(changePresetLabel);
\r
304 AudioSettings.AudioListChanged -= new EventHandler(changePresetLabel);
\r
307 x264Panel.rtf_x264Query.TextChanged -= new EventHandler(changePresetLabel);
\r
310 private void changePresetLabel(object sender, EventArgs e)
\r
312 labelPreset.Text = "Output Settings (Preset: Custom)";
\r
313 CurrentlySelectedPreset = null;
\r
316 private static void frmMain_DragEnter(object sender, DragEventArgs e)
\r
318 if (e.Data.GetDataPresent(DataFormats.FileDrop, false))
\r
319 e.Effect = DragDropEffects.All;
\r
322 private void frmMain_DragDrop(object sender, DragEventArgs e)
\r
324 string[] fileList = e.Data.GetData(DataFormats.FileDrop) as string[];
\r
325 sourcePath = string.Empty;
\r
327 if (fileList != null)
\r
329 if (fileList[0] != string.Empty)
\r
331 this.selectedSourceType = SourceType.VideoFile;
\r
332 StartScan(fileList[0], 0);
\r
335 UpdateSourceLabel();
\r
338 UpdateSourceLabel();
\r
341 private void encodeStarted(object sender, EventArgs e)
\r
343 lastAction = ActivityLogMode.Encode;
\r
344 SetEncodeStarted();
\r
346 // Experimental HBProc Process Monitoring.
\r
347 if (Properties.Settings.Default.enocdeStatusInGui)
\r
349 Thread encodeMon = new Thread(EncodeMonitorThread);
\r
354 private void encodeEnded(object sender, EventArgs e)
\r
356 SetEncodeFinished();
\r
359 private void encodePaused(object sender, EventArgs e)
\r
361 SetEncodeFinished();
\r
366 // User Interface Menus / Tool Strips *********************************
\r
370 private void mnu_killCLI_Click(object sender, EventArgs e)
\r
375 private void mnu_exit_Click(object sender, EventArgs e)
\r
377 Application.Exit();
\r
384 private void mnu_encode_Click(object sender, EventArgs e)
\r
386 queueWindow.Show();
\r
389 private void mnu_encodeLog_Click(object sender, EventArgs e)
\r
391 frmActivityWindow dvdInfoWindow = new frmActivityWindow(lastAction, encodeQueue, SourceScan);
\r
392 dvdInfoWindow.Show();
\r
395 private void mnu_options_Click(object sender, EventArgs e)
\r
397 Form options = new frmOptions(this);
\r
398 options.ShowDialog();
\r
403 #region Presets Menu
\r
405 private void mnu_presetReset_Click(object sender, EventArgs e)
\r
407 presetHandler.UpdateBuiltInPresets();
\r
409 if (treeView_presets.Nodes.Count == 0)
\r
411 "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
412 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
414 MessageBox.Show("Presets have been updated!", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
416 treeView_presets.ExpandAll();
\r
419 private void mnu_delete_preset_Click(object sender, EventArgs e)
\r
421 presetHandler.RemoveBuiltInPresets();
\r
422 LoadPresetPanel(); // Reload the preset panel
\r
425 private void mnu_SelectDefault_Click(object sender, EventArgs e)
\r
427 loadNormalPreset();
\r
430 private void mnu_importMacPreset_Click(object sender, EventArgs e)
\r
435 private void btn_new_preset_Click(object sender, EventArgs e)
\r
437 Form preset = new frmAddPreset(this, QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
439 preset.ShowDialog();
\r
446 private void mnu_user_guide_Click(object sender, EventArgs e)
\r
448 Process.Start("http://trac.handbrake.fr/wiki/HandBrakeGuide");
\r
451 private void mnu_handbrake_home_Click(object sender, EventArgs e)
\r
453 Process.Start("http://handbrake.fr");
\r
456 private void mnu_UpdateCheck_Click(object sender, EventArgs e)
\r
458 lbl_updateCheck.Visible = true;
\r
459 Main.BeginCheckForUpdates(new AsyncCallback(updateCheckDoneMenu), false);
\r
462 private void updateCheckDoneMenu(IAsyncResult result)
\r
464 // Make sure it's running on the calling thread
\r
465 if (InvokeRequired)
\r
467 Invoke(new MethodInvoker(() => updateCheckDoneMenu(result)));
\r
470 UpdateCheckInformation info;
\r
473 // Get the information about the new build, if any, and close the window
\r
474 info = Main.EndCheckForUpdates(result);
\r
476 if (info.NewVersionAvailable && info.BuildInformation != null)
\r
478 frmUpdater updateWindow = new frmUpdater(info.BuildInformation);
\r
479 updateWindow.ShowDialog();
\r
482 MessageBox.Show("There are no new updates at this time.", "Update Check", MessageBoxButtons.OK,
\r
483 MessageBoxIcon.Information);
\r
484 lbl_updateCheck.Visible = false;
\r
487 catch (Exception ex)
\r
489 if ((bool)result.AsyncState)
\r
491 "Unable to check for updates, Please try again later.\n\nDetailed Error Information:\n" + ex,
\r
492 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
496 private void mnu_about_Click(object sender, EventArgs e)
\r
498 using (frmAbout About = new frmAbout())
\r
500 About.ShowDialog();
\r
508 // Right Click Menu Code
\r
509 private void pmnu_expandAll_Click(object sender, EventArgs e)
\r
511 treeView_presets.ExpandAll();
\r
514 private void pmnu_collapse_Click(object sender, EventArgs e)
\r
516 treeView_presets.CollapseAll();
\r
519 private void pmnu_import_Click(object sender, EventArgs e)
\r
524 private void pmnu_saveChanges_Click(object sender, EventArgs e)
\r
526 DialogResult result =
\r
528 "Do you wish to include picture settings when updating the preset: " +
\r
529 treeView_presets.SelectedNode.Text, "Update Preset", MessageBoxButtons.YesNoCancel,
\r
530 MessageBoxIcon.Question);
\r
531 if (result == DialogResult.Yes)
\r
532 presetHandler.Update(treeView_presets.SelectedNode.Text,
\r
533 QueryGenerator.GenerateTabbedComponentsQuery(this), true);
\r
534 else if (result == DialogResult.No)
\r
535 presetHandler.Update(treeView_presets.SelectedNode.Text,
\r
536 QueryGenerator.GenerateTabbedComponentsQuery(this), false);
\r
539 private void pmnu_delete_click(object sender, EventArgs e)
\r
541 if (treeView_presets.SelectedNode != null)
\r
543 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
544 treeView_presets.Nodes.Remove(treeView_presets.SelectedNode);
\r
546 treeView_presets.Select();
\r
549 private void presets_menu_Opening(object sender, CancelEventArgs e)
\r
551 // Make sure that the save menu is always disabled by default
\r
552 pmnu_saveChanges.Enabled = false;
\r
554 // Now enable the save menu if the selected preset is a user preset
\r
555 if (treeView_presets.SelectedNode != null)
\r
556 if (presetHandler.CheckIfUserPresetExists(treeView_presets.SelectedNode.Text))
\r
557 pmnu_saveChanges.Enabled = true;
\r
559 treeView_presets.Select();
\r
562 // Presets Management
\r
563 private void btn_addPreset_Click(object sender, EventArgs e)
\r
565 Form preset = new frmAddPreset(this, QueryGenerator.GenerateTabbedComponentsQuery(this), presetHandler);
\r
566 preset.ShowDialog();
\r
569 private void btn_removePreset_Click(object sender, EventArgs e)
\r
571 DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected preset?", "Preset",
\r
572 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
573 if (result == DialogResult.Yes)
\r
575 if (treeView_presets.SelectedNode != null)
\r
577 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
578 treeView_presets.Nodes.Remove(treeView_presets.SelectedNode);
\r
581 treeView_presets.Select();
\r
584 private void btn_setDefault_Click(object sender, EventArgs e)
\r
586 if (treeView_presets.SelectedNode != null)
\r
588 DialogResult result = MessageBox.Show("Are you sure you wish to set this preset as the default?",
\r
589 "Preset", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
590 if (result == DialogResult.Yes)
\r
592 Properties.Settings.Default.defaultPreset = treeView_presets.SelectedNode.Text;
\r
593 Properties.Settings.Default.Save();
\r
594 MessageBox.Show("New default preset set.", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
598 MessageBox.Show("Please select a preset first.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
601 private void treeview_presets_mouseUp(object sender, MouseEventArgs e)
\r
603 if (e.Button == MouseButtons.Right)
\r
604 treeView_presets.SelectedNode = treeView_presets.GetNodeAt(e.Location);
\r
605 else if (e.Button == MouseButtons.Left)
\r
607 if (treeView_presets.GetNodeAt(e.Location) != null)
\r
609 if (labelPreset.Text.Contains(treeView_presets.GetNodeAt(e.Location).Text))
\r
614 treeView_presets.Select();
\r
617 private void treeView_presets_AfterSelect(object sender, TreeViewEventArgs e)
\r
622 private void treeView_presets_deleteKey(object sender, KeyEventArgs e)
\r
624 if (e.KeyCode == Keys.Delete)
\r
626 DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected preset?", "Preset",
\r
627 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
628 if (result == DialogResult.Yes)
\r
630 if (treeView_presets.SelectedNode != null)
\r
631 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
633 // Remember each nodes expanded status so we can reload it
\r
634 List<bool> nodeStatus = new List<bool>();
\r
635 foreach (TreeNode node in treeView_presets.Nodes)
\r
636 nodeStatus.Add(node.IsExpanded);
\r
638 // Now reload the preset panel
\r
641 // And finally, re-expand any of the nodes if required
\r
643 foreach (TreeNode node in treeView_presets.Nodes)
\r
654 private void selectPreset()
\r
656 if (treeView_presets.SelectedNode != null)
\r
658 // Ok, so, we've selected a preset. Now we want to load it.
\r
659 string presetName = treeView_presets.SelectedNode.Text;
\r
660 Preset preset = presetHandler.GetPreset(presetName);
\r
661 if (preset != null)
\r
663 string query = presetHandler.GetPreset(presetName).Query;
\r
664 bool loadPictureSettings = presetHandler.GetPreset(presetName).PictureSettings;
\r
668 // Ok, Reset all the H264 widgets before changing the preset
\r
669 x264Panel.Reset2Defaults();
\r
671 // Send the query from the file to the Query Parser class
\r
672 QueryParser presetQuery = QueryParser.Parse(query);
\r
674 // Now load the preset
\r
675 PresetLoader.LoadPreset(this, presetQuery, presetName, loadPictureSettings);
\r
677 // The x264 widgets will need updated, so do this now:
\r
678 x264Panel.X264_StandardizeOptString();
\r
679 x264Panel.X264_SetCurrentSettingsInPanel();
\r
681 // Finally, let this window have a copy of the preset settings.
\r
682 CurrentlySelectedPreset = preset;
\r
683 PictureSettings.SetPresetCropWarningLabel(preset);
\r
689 private void loadNormalPreset()
\r
691 foreach (TreeNode treenode in treeView_presets.Nodes)
\r
693 foreach (TreeNode node in treenode.Nodes)
\r
695 if (node.Text.Equals("Normal"))
\r
696 treeView_presets.SelectedNode = treeView_presets.Nodes[treenode.Index].Nodes[0];
\r
701 private void importPreset()
\r
703 if (openPreset.ShowDialog() == DialogResult.OK)
\r
705 QueryParser parsed = PlistPresetHandler.Import(openPreset.FileName);
\r
706 if (presetHandler.CheckIfUserPresetExists(parsed.PresetName + " (Imported)"))
\r
708 DialogResult result =
\r
709 MessageBox.Show("This preset appears to already exist. Would you like to overwrite it?",
\r
710 "Overwrite preset?",
\r
711 MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
\r
712 if (result == DialogResult.Yes)
\r
714 PresetLoader.LoadPreset(this, parsed, parsed.PresetName, parsed.UsesPictureSettings);
\r
715 presetHandler.Update(parsed.PresetName + " (Imported)",
\r
716 QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
717 parsed.UsesPictureSettings);
\r
722 PresetLoader.LoadPreset(this, parsed, parsed.PresetName, parsed.UsesPictureSettings);
\r
723 presetHandler.Add(parsed.PresetName,
\r
724 QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
725 parsed.UsesPictureSettings);
\r
727 if (presetHandler.Add(parsed.PresetName + " (Imported)",
\r
728 QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
729 parsed.UsesPictureSettings))
\r
731 TreeNode preset_treeview = new TreeNode(parsed.PresetName + " (Imported)")
\r
733 ForeColor = Color.Black
\r
735 treeView_presets.Nodes.Add(preset_treeview);
\r
745 private void btn_source_Click(object sender, EventArgs e)
\r
747 // Remove old Drive Menu Items.
\r
748 List<ToolStripMenuItem> itemsToRemove = new List<ToolStripMenuItem>();
\r
749 foreach (var item in btn_source.DropDownItems)
\r
751 if (item.GetType() == typeof(ToolStripMenuItem))
\r
753 ToolStripMenuItem menuItem = (ToolStripMenuItem)item;
\r
754 if (menuItem.Name.StartsWith("Drive"))
\r
756 itemsToRemove.Add(menuItem);
\r
761 foreach (ToolStripMenuItem item in itemsToRemove)
\r
762 btn_source.DropDownItems.Remove(item);
\r
764 Thread driveInfoThread = new Thread(SetDriveSelectionMenuItem);
\r
765 driveInfoThread.Start();
\r
768 private void btn_start_Click(object sender, EventArgs e)
\r
770 if (btn_start.Text == "Stop")
\r
772 DialogResult result;
\r
773 if (Properties.Settings.Default.enocdeStatusInGui &&
\r
774 !Properties.Settings.Default.showCliForInGuiEncodeStatus)
\r
776 result = MessageBox.Show(
\r
777 "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
778 "Cancel Encode?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
782 result = MessageBox.Show("Are you sure you wish to cancel the encode?", "Cancel Encode?",
\r
783 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
786 if (result == DialogResult.Yes)
\r
789 encodeQueue.Pause();
\r
791 if (Properties.Settings.Default.enocdeStatusInGui &&
\r
792 !Properties.Settings.Default.showCliForInGuiEncodeStatus)
\r
794 encodeQueue.Stop();
\r
795 if (encodeQueue.HbProcess != null)
\r
796 encodeQueue.HbProcess.WaitForExit();
\r
800 encodeQueue.SafelyClose();
\r
804 SetEncodeFinished();
\r
809 if (encodeQueue.Count != 0 ||
\r
810 (!string.IsNullOrEmpty(sourcePath) && !string.IsNullOrEmpty(text_destination.Text)))
\r
812 string generatedQuery = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
813 string specifiedQuery = rtf_query.Text != string.Empty
\r
815 : QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
816 string query = string.Empty;
\r
818 // Check to make sure the generated query matches the GUI settings
\r
819 if (Properties.Settings.Default.PromptOnUnmatchingQueries && !string.IsNullOrEmpty(specifiedQuery) &&
\r
820 generatedQuery != specifiedQuery)
\r
822 DialogResult result = MessageBox.Show("The query under the \"Query Editor\" tab " +
\r
823 "does not match the current GUI settings.\n\nBecause the manual query takes " +
\r
824 "priority over the GUI, your recently updated settings will not be taken " +
\r
825 "into account when encoding this job." +
\r
826 Environment.NewLine + Environment.NewLine +
\r
827 "Do you want to replace the manual query with the updated GUI-generated query?",
\r
828 "Manual Query does not Match GUI",
\r
829 MessageBoxButtons.YesNoCancel, MessageBoxIcon.Asterisk,
\r
830 MessageBoxDefaultButton.Button3);
\r
834 case DialogResult.Yes:
\r
835 // Replace the manual query with the generated one
\r
836 query = generatedQuery;
\r
837 rtf_query.Text = generatedQuery;
\r
839 case DialogResult.No:
\r
840 // Use the manual query
\r
841 query = specifiedQuery;
\r
843 case DialogResult.Cancel:
\r
844 // Don't start the encode
\r
850 query = specifiedQuery;
\r
853 DialogResult overwrite = DialogResult.Yes;
\r
854 if (text_destination.Text != string.Empty)
\r
855 if (File.Exists(text_destination.Text))
\r
858 "The destination file already exists. Are you sure you want to overwrite it?",
\r
859 "Overwrite File?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
861 if (overwrite == DialogResult.Yes)
\r
863 if (encodeQueue.Count == 0)
\r
864 encodeQueue.Add(query, sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
866 queueWindow.SetQueue();
\r
867 if (encodeQueue.Count > 1)
\r
868 queueWindow.Show(false);
\r
870 SetEncodeStarted(); // Encode is running, so setup the GUI appropriately
\r
871 encodeQueue.Start(); // Start The Queue Encoding Process
\r
872 lastAction = ActivityLogMode.Encode; // Set the last action to encode - Used for activity window.
\r
874 if (ActivityWindow != null)
\r
875 ActivityWindow.SetMode(ActivityLogMode.Encode);
\r
879 else if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
880 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
881 MessageBoxIcon.Warning);
\r
885 private void btn_add2Queue_Click(object sender, EventArgs e)
\r
887 if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
888 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
889 MessageBoxIcon.Warning);
\r
892 string query = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
893 if (rtf_query.Text != string.Empty)
\r
894 query = rtf_query.Text;
\r
896 if (encodeQueue.CheckForDestinationDuplicate(text_destination.Text))
\r
898 DialogResult result =
\r
900 "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
901 "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
\r
902 if (result == DialogResult.Yes)
\r
903 encodeQueue.Add(query, sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
906 encodeQueue.Add(query, sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
908 lbl_encode.Text = encodeQueue.Count + " encode(s) pending in the queue";
\r
910 queueWindow.Show();
\r
914 private void btn_showQueue_Click(object sender, EventArgs e)
\r
916 queueWindow.Show();
\r
917 queueWindow.Activate();
\r
920 private void tb_preview_Click(object sender, EventArgs e)
\r
922 if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
923 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
924 MessageBoxIcon.Warning);
\r
927 if (qtpreview == null)
\r
929 qtpreview = new frmPreview(this);
\r
932 else if (qtpreview.IsDisposed)
\r
934 qtpreview = new frmPreview(this);
\r
938 MessageBox.Show(qtpreview, "The preview window is already open!", "Warning", MessageBoxButtons.OK,
\r
939 MessageBoxIcon.Warning);
\r
943 private void btn_ActivityWindow_Click(object sender, EventArgs e)
\r
945 if (ActivityWindow == null || !ActivityWindow.IsHandleCreated)
\r
946 ActivityWindow = new frmActivityWindow(lastAction, encodeQueue, SourceScan);
\r
948 switch (lastAction)
\r
950 case ActivityLogMode.Scan:
\r
951 ActivityWindow.SetMode(ActivityLogMode.Scan);
\r
953 case ActivityLogMode.Encode:
\r
954 ActivityWindow.SetMode(ActivityLogMode.Encode);
\r
957 ActivityWindow.SetMode(ActivityLogMode.Encode);
\r
961 ActivityWindow.Show();
\r
962 ActivityWindow.Activate();
\r
967 #region System Tray Icon
\r
969 private void frmMain_Resize(object sender, EventArgs e)
\r
971 if (FormWindowState.Minimized == this.WindowState)
\r
973 notifyIcon.Visible = true;
\r
976 else if (FormWindowState.Normal == this.WindowState)
\r
977 notifyIcon.Visible = false;
\r
980 private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
\r
982 this.Visible = true;
\r
984 this.WindowState = FormWindowState.Normal;
\r
985 notifyIcon.Visible = false;
\r
988 private void btn_restore_Click(object sender, EventArgs e)
\r
990 this.Visible = true;
\r
992 this.WindowState = FormWindowState.Normal;
\r
993 notifyIcon.Visible = false;
\r
998 #region Tab Control
\r
1001 private void btn_dvd_source_Click(object sender, EventArgs e)
\r
1003 if (DVD_Open.ShowDialog() == DialogResult.OK)
\r
1005 this.selectedSourceType = SourceType.Folder;
\r
1006 SelectSource(DVD_Open.SelectedPath);
\r
1009 UpdateSourceLabel();
\r
1012 private void btn_file_source_Click(object sender, EventArgs e)
\r
1014 if (ISO_Open.ShowDialog() == DialogResult.OK)
\r
1016 this.selectedSourceType = SourceType.VideoFile;
\r
1017 SelectSource(ISO_Open.FileName);
\r
1020 UpdateSourceLabel();
\r
1023 private void mnu_dvd_drive_Click(object sender, EventArgs e)
\r
1025 ToolStripMenuItem item = sender as ToolStripMenuItem;
\r
1028 string driveId = item.Name.Replace("Drive", string.Empty);
\r
1030 if (int.TryParse(driveId, out id))
\r
1033 this.dvdDrivePath = drives[id].RootDirectory;
\r
1034 this.dvdDriveLabel = drives[id].VolumeLabel;
\r
1036 if (this.dvdDrivePath == null) return;
\r
1037 this.selectedSourceType = SourceType.DvdDrive;
\r
1038 SelectSource(this.dvdDrivePath);
\r
1043 private void SelectSource(string file)
\r
1045 Check_ChapterMarkers.Enabled = true;
\r
1046 lastAction = ActivityLogMode.Scan;
\r
1047 sourcePath = string.Empty;
\r
1049 if (file == string.Empty) // Must have a file or path
\r
1051 UpdateSourceLabel();
\r
1055 sourcePath = Path.GetFileName(file);
\r
1056 StartScan(file, 0);
\r
1059 private void drp_dvdtitle_Click(object sender, EventArgs e)
\r
1061 if ((drp_dvdtitle.Items.Count == 1) && (drp_dvdtitle.Items[0].ToString() == "Automatic"))
\r
1063 "There are no titles to select. Please load a source file by clicking the 'Source' button above before trying to select a title.",
\r
1064 "Alert", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
\r
1067 private void drp_dvdtitle_SelectedIndexChanged(object sender, EventArgs e)
\r
1069 UnRegisterPresetEventHandler();
\r
1070 drop_mode.SelectedIndex = 0;
\r
1072 drop_chapterStart.Items.Clear();
\r
1073 drop_chapterFinish.Items.Clear();
\r
1075 // If the dropdown is set to automatic nothing else needs to be done.
\r
1076 // Otheriwse if its not, title data has to be loased from parsing.
\r
1077 if (drp_dvdtitle.Text != "Automatic")
\r
1079 selectedTitle = drp_dvdtitle.SelectedItem as Title;
\r
1080 lbl_duration.Text = selectedTitle.Duration.ToString();
\r
1081 PictureSettings.CurrentlySelectedPreset = CurrentlySelectedPreset;
\r
1082 PictureSettings.Source = selectedTitle; // Setup Picture Settings Tab Control
\r
1084 // Populate the Angles dropdown
\r
1085 drop_angle.Items.Clear();
\r
1086 if (!Properties.Settings.Default.noDvdNav)
\r
1088 drop_angle.Visible = true;
\r
1089 lbl_angle.Visible = true;
\r
1090 drop_angle.Items.AddRange(selectedTitle.Angles.ToArray());
\r
1091 if (drop_angle.Items.Count != 0)
\r
1092 drop_angle.SelectedIndex = 0;
\r
1096 drop_angle.Visible = false;
\r
1097 lbl_angle.Visible = false;
\r
1100 // Populate the Start chapter Dropdown
\r
1101 drop_chapterStart.Items.Clear();
\r
1102 drop_chapterStart.Items.AddRange(selectedTitle.Chapters.ToArray());
\r
1103 if (drop_chapterStart.Items.Count > 0)
\r
1104 drop_chapterStart.Text = drop_chapterStart.Items[0].ToString();
\r
1106 // Populate the Final Chapter Dropdown
\r
1107 drop_chapterFinish.Items.Clear();
\r
1108 drop_chapterFinish.Items.AddRange(selectedTitle.Chapters.ToArray());
\r
1109 if (drop_chapterFinish.Items.Count > 0)
\r
1110 drop_chapterFinish.Text = drop_chapterFinish.Items[drop_chapterFinish.Items.Count - 1].ToString();
\r
1112 // Populate the Audio Channels Dropdown
\r
1113 AudioSettings.SetTrackList(selectedTitle);
\r
1115 // Populate the Subtitles dropdown
\r
1116 Subtitles.SetSubtitleTrackAuto(selectedTitle.Subtitles.ToArray());
\r
1118 // Update the source label if we have multiple streams
\r
1119 if (selectedTitle != null)
\r
1120 if (!string.IsNullOrEmpty(selectedTitle.SourceName))
\r
1121 labelSource.Text = labelSource.Text = Path.GetFileName(selectedTitle.SourceName);
\r
1123 // Run the AutoName & ChapterNaming functions
\r
1124 if (Properties.Settings.Default.autoNaming)
\r
1126 string autoPath = Main.AutoName(this);
\r
1127 if (autoPath != null)
\r
1128 text_destination.Text = autoPath;
\r
1131 "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
1132 "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
1135 data_chpt.Rows.Clear();
\r
1136 if (selectedTitle.Chapters.Count != 1)
\r
1138 DataGridView chapterGridView = Main.ChapterNaming(data_chpt, drop_chapterFinish.Text);
\r
1139 if (chapterGridView != null)
\r
1140 data_chpt = chapterGridView;
\r
1144 Check_ChapterMarkers.Checked = false;
\r
1145 Check_ChapterMarkers.Enabled = false;
\r
1148 // Hack to force the redraw of the scrollbars which don't resize properly when the control is disabled.
\r
1149 data_chpt.Columns[0].Width = 166;
\r
1150 data_chpt.Columns[0].Width = 165;
\r
1152 RegisterPresetEventHandler();
\r
1155 private void chapersChanged(object sender, EventArgs e)
\r
1157 if (drop_mode.SelectedIndex != 0) // Function is not used if we are not in chapters mode.
\r
1160 Control ctl = (Control)sender;
\r
1161 int chapterStart, chapterEnd;
\r
1162 int.TryParse(drop_chapterStart.Text, out chapterStart);
\r
1163 int.TryParse(drop_chapterFinish.Text, out chapterEnd);
\r
1167 case "drop_chapterStart":
\r
1168 if (drop_chapterFinish.SelectedIndex == -1 && drop_chapterFinish.Items.Count != 0)
\r
1169 drop_chapterFinish.SelectedIndex = drop_chapterFinish.Items.Count - 1;
\r
1171 if (chapterEnd != 0)
\r
1172 if (chapterStart > chapterEnd)
\r
1173 drop_chapterFinish.Text = chapterStart.ToString();
\r
1175 case "drop_chapterFinish":
\r
1176 if (drop_chapterStart.Items.Count >= 1 && drop_chapterStart.SelectedIndex == -1)
\r
1177 drop_chapterStart.SelectedIndex = 0;
\r
1179 if (chapterStart != 0)
\r
1180 if (chapterEnd < chapterStart)
\r
1181 drop_chapterFinish.Text = chapterStart.ToString();
\r
1183 // Add more rows to the Chapter menu if needed.
\r
1184 if (Check_ChapterMarkers.Checked)
\r
1186 int i = data_chpt.Rows.Count, finish = 0;
\r
1187 int.TryParse(drop_chapterFinish.Text, out finish);
\r
1189 while (i < finish)
\r
1191 int n = data_chpt.Rows.Add();
\r
1192 data_chpt.Rows[n].Cells[0].Value = (i + 1);
\r
1193 data_chpt.Rows[n].Cells[1].Value = "Chapter " + (i + 1);
\r
1194 data_chpt.Rows[n].Cells[0].ValueType = typeof(int);
\r
1195 data_chpt.Rows[n].Cells[1].ValueType = typeof(string);
\r
1202 // Update the Duration
\r
1203 lbl_duration.Text =
\r
1204 Main.CalculateDuration(drop_chapterStart.SelectedIndex, drop_chapterFinish.SelectedIndex, selectedTitle)
\r
1207 // Run the Autonaming function
\r
1208 if (Properties.Settings.Default.autoNaming)
\r
1209 text_destination.Text = Main.AutoName(this);
\r
1211 // Disable chapter markers if only 1 chapter is selected.
\r
1212 if (chapterStart == chapterEnd)
\r
1214 Check_ChapterMarkers.Enabled = false;
\r
1215 btn_importChapters.Enabled = false;
\r
1216 data_chpt.Enabled = false;
\r
1220 Check_ChapterMarkers.Enabled = true;
\r
1221 if (Check_ChapterMarkers.Checked)
\r
1223 btn_importChapters.Enabled = true;
\r
1224 data_chpt.Enabled = true;
\r
1229 private void SecondsOrFramesChanged(object sender, EventArgs e)
\r
1232 int.TryParse(drop_chapterStart.Text, out start);
\r
1233 int.TryParse(drop_chapterFinish.Text, out end);
\r
1234 double duration = end - start;
\r
1236 switch (drop_mode.SelectedIndex)
\r
1239 lbl_duration.Text = TimeSpan.FromSeconds(duration).ToString();
\r
1242 if (selectedTitle != null)
\r
1244 duration = duration / selectedTitle.Fps;
\r
1245 lbl_duration.Text = TimeSpan.FromSeconds(duration).ToString();
\r
1248 lbl_duration.Text = "--:--:--";
\r
1254 private void drop_mode_SelectedIndexChanged(object sender, EventArgs e)
\r
1257 this.drop_chapterFinish.TextChanged -= new EventHandler(this.SecondsOrFramesChanged);
\r
1258 this.drop_chapterStart.TextChanged -= new EventHandler(this.SecondsOrFramesChanged);
\r
1261 switch (drop_mode.SelectedIndex)
\r
1264 drop_chapterStart.DropDownStyle = ComboBoxStyle.DropDownList;
\r
1265 drop_chapterFinish.DropDownStyle = ComboBoxStyle.DropDownList;
\r
1266 if (drop_chapterStart.Items.Count != 0)
\r
1268 drop_chapterStart.SelectedIndex = 0;
\r
1269 drop_chapterFinish.SelectedIndex = drop_chapterFinish.Items.Count - 1;
\r
1272 lbl_duration.Text = "--:--:--";
\r
1275 this.drop_chapterStart.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1276 this.drop_chapterFinish.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1277 drop_chapterStart.DropDownStyle = ComboBoxStyle.Simple;
\r
1278 drop_chapterFinish.DropDownStyle = ComboBoxStyle.Simple;
\r
1279 if (selectedTitle != null)
\r
1281 drop_chapterStart.Text = "0";
\r
1282 drop_chapterFinish.Text = selectedTitle.Duration.TotalSeconds.ToString();
\r
1286 this.drop_chapterStart.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1287 this.drop_chapterFinish.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1288 drop_chapterStart.DropDownStyle = ComboBoxStyle.Simple;
\r
1289 drop_chapterFinish.DropDownStyle = ComboBoxStyle.Simple;
\r
1290 if (selectedTitle != null)
\r
1292 drop_chapterStart.Text = "0";
\r
1293 drop_chapterFinish.Text = (selectedTitle.Fps * selectedTitle.Duration.TotalSeconds).ToString();
\r
1300 private void btn_destBrowse_Click(object sender, EventArgs e)
\r
1302 // This removes the file extension from the filename box on the save file dialog.
\r
1303 // It's daft but some users don't realise that typing an extension overrides the dropdown extension selected.
\r
1304 DVD_Save.FileName = Path.GetFileNameWithoutExtension(text_destination.Text);
\r
1306 if (Path.IsPathRooted(text_destination.Text))
\r
1307 DVD_Save.InitialDirectory = Path.GetDirectoryName(text_destination.Text);
\r
1309 // Show the dialog and set the main form file path
\r
1310 if (drop_format.SelectedIndex.Equals(0))
\r
1311 DVD_Save.FilterIndex = 1;
\r
1312 else if (drop_format.SelectedIndex.Equals(1))
\r
1313 DVD_Save.FilterIndex = 2;
\r
1315 if (DVD_Save.ShowDialog() == DialogResult.OK)
\r
1317 // Add a file extension manually, as FileDialog.AddExtension has issues with dots in filenames
\r
1318 switch (DVD_Save.FilterIndex)
\r
1322 !Path.GetExtension(DVD_Save.FileName).Equals(".mp4",
\r
1323 StringComparison.InvariantCultureIgnoreCase))
\r
1324 if (Properties.Settings.Default.useM4v)
\r
1325 DVD_Save.FileName = DVD_Save.FileName.Replace(".mp4", ".m4v").Replace(".mkv", ".m4v");
\r
1327 DVD_Save.FileName = DVD_Save.FileName.Replace(".m4v", ".mp4").Replace(".mkv", ".mp4");
\r
1331 !Path.GetExtension(DVD_Save.FileName).Equals(".mkv",
\r
1332 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 switch (Properties.Settings.Default.x264cqstep.ToString(culture))
\r
1449 slider_videoQuality.Maximum = 255;
\r
1452 slider_videoQuality.Maximum = 204;
\r
1455 slider_videoQuality.Maximum = 102;
\r
1458 slider_videoQuality.Maximum = 51;
\r
1461 slider_videoQuality.Maximum = 51;
\r
1464 if (value < slider_videoQuality.Maximum)
\r
1465 slider_videoQuality.Value = slider_videoQuality.Maximum - (int)value;
\r
1468 case "VP3 (Theora)":
\r
1469 if (slider_videoQuality.Value > 63)
\r
1470 slider_videoQuality.Value = 45; // Just reset to 70% QP 45 on encode change.
\r
1471 slider_videoQuality.Minimum = 0;
\r
1472 slider_videoQuality.Maximum = 63;
\r
1478 /// Set the container format options
\r
1480 public void setContainerOpts()
\r
1482 if ((drop_format.Text.Contains("MP4")) || (drop_format.Text.Contains("M4V")))
\r
1484 check_largeFile.Enabled = true;
\r
1485 check_optimiseMP4.Enabled = true;
\r
1486 check_iPodAtom.Enabled = true;
\r
1490 check_largeFile.Enabled = false;
\r
1491 check_optimiseMP4.Enabled = false;
\r
1492 check_iPodAtom.Enabled = false;
\r
1493 check_largeFile.Checked = false;
\r
1494 check_optimiseMP4.Checked = false;
\r
1495 check_iPodAtom.Checked = false;
\r
1499 private double _cachedCqStep = Properties.Settings.Default.x264cqstep;
\r
1502 /// Update the CQ slider for x264 for a new CQ step. This is set from option
\r
1504 public void setQualityFromSlider()
\r
1506 // Work out the current RF value.
\r
1507 double cqStep = _cachedCqStep;
\r
1508 double rfValue = 51.0 - slider_videoQuality.Value * cqStep;
\r
1510 // Change the maximum value for the slider
\r
1511 switch (Properties.Settings.Default.x264cqstep.ToString(new CultureInfo("en-US")))
\r
1514 slider_videoQuality.Maximum = 255;
\r
1517 slider_videoQuality.Maximum = 204;
\r
1520 slider_videoQuality.Maximum = 102;
\r
1523 slider_videoQuality.Maximum = 51;
\r
1526 slider_videoQuality.Maximum = 51;
\r
1530 // Reset the CQ slider to RF0
\r
1531 slider_videoQuality.Value = slider_videoQuality.Maximum;
\r
1533 // Reset the CQ slider back to the previous value as close as possible
\r
1534 double cqStepNew = Properties.Settings.Default.x264cqstep;
\r
1535 double rfValueCurrent = 51.0 - slider_videoQuality.Value * cqStepNew;
\r
1536 while (rfValueCurrent < rfValue)
\r
1538 slider_videoQuality.Value--;
\r
1539 rfValueCurrent = 51.0 - slider_videoQuality.Value * cqStepNew;
\r
1542 // Cache the CQ step for the next calculation
\r
1543 _cachedCqStep = Properties.Settings.Default.x264cqstep;
\r
1546 private void slider_videoQuality_Scroll(object sender, EventArgs e)
\r
1548 double cqStep = Properties.Settings.Default.x264cqstep;
\r
1549 switch (drp_videoEncoder.Text)
\r
1551 case "MPEG-4 (FFmpeg)":
\r
1552 lbl_SliderValue.Text = "QP:" + (32 - slider_videoQuality.Value);
\r
1554 case "H.264 (x264)":
\r
1555 double rfValue = 51.0 - slider_videoQuality.Value * cqStep;
\r
1556 rfValue = Math.Round(rfValue, 2);
\r
1557 lbl_SliderValue.Text = "RF:" + rfValue.ToString(new CultureInfo("en-US"));
\r
1559 case "VP3 (Theora)":
\r
1560 lbl_SliderValue.Text = "QP:" + slider_videoQuality.Value;
\r
1565 private void radio_targetFilesize_CheckedChanged(object sender, EventArgs e)
\r
1567 text_bitrate.Enabled = false;
\r
1568 text_filesize.Enabled = true;
\r
1569 slider_videoQuality.Enabled = false;
\r
1571 check_2PassEncode.Enabled = true;
\r
1574 private void radio_avgBitrate_CheckedChanged(object sender, EventArgs e)
\r
1576 text_bitrate.Enabled = true;
\r
1577 text_filesize.Enabled = false;
\r
1578 slider_videoQuality.Enabled = false;
\r
1580 check_2PassEncode.Enabled = true;
\r
1583 private void radio_cq_CheckedChanged(object sender, EventArgs e)
\r
1585 text_bitrate.Enabled = false;
\r
1586 text_filesize.Enabled = false;
\r
1587 slider_videoQuality.Enabled = true;
\r
1589 check_2PassEncode.Enabled = false;
\r
1590 check_2PassEncode.CheckState = CheckState.Unchecked;
\r
1593 private void check_2PassEncode_CheckedChanged(object sender, EventArgs e)
\r
1595 if (check_2PassEncode.CheckState.ToString() == "Checked")
\r
1597 if (drp_videoEncoder.Text.Contains("H.264"))
\r
1598 check_turbo.Enabled = true;
\r
1602 check_turbo.Enabled = false;
\r
1603 check_turbo.CheckState = CheckState.Unchecked;
\r
1607 // Chapter Marker Tab
\r
1608 private void Check_ChapterMarkers_CheckedChanged(object sender, EventArgs e)
\r
1610 if (Check_ChapterMarkers.Checked)
\r
1612 if (drop_format.SelectedIndex != 1)
\r
1613 SetExtension(".m4v");
\r
1614 data_chpt.Enabled = true;
\r
1615 btn_importChapters.Enabled = true;
\r
1619 if (drop_format.SelectedIndex != 1 && !Properties.Settings.Default.useM4v)
\r
1620 SetExtension(".mp4");
\r
1621 data_chpt.Enabled = false;
\r
1622 btn_importChapters.Enabled = false;
\r
1626 private void btn_importChapters_Click(object sender, EventArgs e)
\r
1628 if (File_ChapterImport.ShowDialog() == DialogResult.OK)
\r
1630 string filename = File_ChapterImport.FileName;
\r
1631 DataGridView imported = Main.ImportChapterNames(data_chpt, filename);
\r
1632 if (imported != null)
\r
1633 data_chpt = imported;
\r
1637 private void mnu_resetChapters_Click(object sender, EventArgs e)
\r
1639 data_chpt.Rows.Clear();
\r
1640 DataGridView chapterGridView = Main.ChapterNaming(data_chpt, drop_chapterFinish.Text);
\r
1641 if (chapterGridView != null)
\r
1643 data_chpt = chapterGridView;
\r
1647 // Query Editor Tab
\r
1648 private void btn_generate_Query_Click(object sender, EventArgs e)
\r
1650 rtf_query.Text = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
1653 private void btn_clear_Click(object sender, EventArgs e)
\r
1655 rtf_query.Clear();
\r
1660 // MainWindow Components, Actions and Functions ***********************
\r
1662 #region Source Scan
\r
1664 public bool isScanning { get; set; }
\r
1666 private void StartScan(string filename, int title)
\r
1668 // Setup the GUI components for the scan.
\r
1669 sourcePath = filename;
\r
1670 foreach (Control ctrl in Controls)
\r
1671 if (!(ctrl is StatusStrip || ctrl is MenuStrip || ctrl is ToolStrip))
\r
1672 ctrl.Enabled = false;
\r
1674 lbl_encode.Visible = true;
\r
1675 lbl_encode.Text = "Scanning ...";
\r
1676 btn_source.Enabled = false;
\r
1677 btn_start.Enabled = false;
\r
1678 btn_showQueue.Enabled = false;
\r
1679 btn_add2Queue.Enabled = false;
\r
1680 tb_preview.Enabled = false;
\r
1681 mnu_killCLI.Visible = true;
\r
1683 if (ActivityWindow != null)
\r
1684 ActivityWindow.SetMode(ActivityLogMode.Scan);
\r
1689 isScanning = true;
\r
1690 SourceScan = new Scan();
\r
1691 SourceScan.ScanSource(sourcePath, title);
\r
1692 SourceScan.ScanStatusChanged += new EventHandler(SourceScan_ScanStatusChanged);
\r
1693 SourceScan.ScanCompleted += new EventHandler(SourceScan_ScanCompleted);
\r
1695 catch (Exception exc)
\r
1697 MessageBox.Show("frmMain.cs - StartScan " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1701 private void SourceScan_ScanStatusChanged(object sender, EventArgs e)
\r
1703 UpdateScanStatusLabel();
\r
1706 private void SourceScan_ScanCompleted(object sender, EventArgs e)
\r
1708 UpdateGuiAfterScan();
\r
1711 private void UpdateScanStatusLabel()
\r
1713 if (InvokeRequired)
\r
1715 BeginInvoke(new UpdateWindowHandler(UpdateScanStatusLabel));
\r
1718 lbl_encode.Text = SourceScan.ScanStatus();
\r
1721 private void UpdateGuiAfterScan()
\r
1723 if (InvokeRequired)
\r
1725 BeginInvoke(new UpdateWindowHandler(UpdateGuiAfterScan));
\r
1731 currentSource = SourceScan.SouceData();
\r
1733 // Setup some GUI components
\r
1734 drp_dvdtitle.Items.Clear();
\r
1735 if (currentSource.Titles.Count != 0)
\r
1736 drp_dvdtitle.Items.AddRange(currentSource.Titles.ToArray());
\r
1738 // Now select the longest title
\r
1739 if (currentSource.Titles.Count != 0)
\r
1740 drp_dvdtitle.SelectedItem = Main.SelectLongestTitle(currentSource);
\r
1742 // Enable the creation of chapter markers if the file is an image of a dvd.
\r
1743 if (sourcePath.ToLower().Contains(".iso") || sourcePath.Contains("VIDEO_TS") ||
\r
1744 Directory.Exists(Path.Combine(sourcePath, "VIDEO_TS")))
\r
1745 Check_ChapterMarkers.Enabled = true;
\r
1748 Check_ChapterMarkers.Enabled = false;
\r
1749 Check_ChapterMarkers.Checked = false;
\r
1750 data_chpt.Rows.Clear();
\r
1753 // If no titles were found, Display an error message
\r
1754 if (drp_dvdtitle.Items.Count == 0)
\r
1757 "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
1758 "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
\r
1759 sourcePath = string.Empty;
\r
1761 UpdateSourceLabel();
\r
1763 // Enable the GUI components and enable any disabled components
\r
1766 catch (Exception exc)
\r
1768 MessageBox.Show("frmMain.cs - updateUIafterScan " + exc, "Error", MessageBoxButtons.OK,
\r
1769 MessageBoxIcon.Error);
\r
1774 private void EnableGUI()
\r
1778 if (InvokeRequired)
\r
1779 BeginInvoke(new UpdateWindowHandler(EnableGUI));
\r
1780 lbl_encode.Text = "Scan Completed";
\r
1781 foreach (Control ctrl in Controls)
\r
1782 ctrl.Enabled = true;
\r
1783 btn_start.Enabled = true;
\r
1784 btn_showQueue.Enabled = true;
\r
1785 btn_add2Queue.Enabled = true;
\r
1786 tb_preview.Enabled = true;
\r
1787 btn_source.Enabled = true;
\r
1788 mnu_killCLI.Visible = false;
\r
1790 catch (Exception exc)
\r
1792 MessageBox.Show("frmMain.cs - EnableGUI() " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1796 private void KillScan()
\r
1800 SourceScan.ScanCompleted -= new EventHandler(SourceScan_ScanCompleted);
\r
1804 if (SourceScan.ScanProcess() != null)
\r
1805 SourceScan.ScanProcess().Kill();
\r
1807 lbl_encode.Text = "Scan Cancelled!";
\r
1809 catch (Exception ex)
\r
1812 "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
1813 ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1817 private void ResetGUI()
\r
1819 drp_dvdtitle.Items.Clear();
\r
1820 drop_chapterStart.Items.Clear();
\r
1821 drop_chapterFinish.Items.Clear();
\r
1822 lbl_duration.Text = "Select a Title";
\r
1823 PictureSettings.lbl_src_res.Text = "Select a Title";
\r
1824 sourcePath = String.Empty;
\r
1825 text_destination.Text = String.Empty;
\r
1826 selectedTitle = null;
\r
1827 isScanning = false;
\r
1830 private void UpdateSourceLabel()
\r
1832 labelSource.Text = string.IsNullOrEmpty(sourcePath) ? "Select \"Source\" to continue." : this.SourceName;
\r
1834 if (selectedTitle != null)
\r
1835 if (!string.IsNullOrEmpty(selectedTitle.SourceName))
\r
1836 // If it's one of multiple source files, make sure we don't use the folder name
\r
1837 labelSource.Text = Path.GetFileName(selectedTitle.SourceName);
\r
1840 public void RecievingJob(Job job)
\r
1842 string query = job.Query;
\r
1843 StartScan(job.Source, 0);
\r
1846 if (query != null)
\r
1848 // Ok, Reset all the H264 widgets before changing the preset
\r
1849 x264Panel.Reset2Defaults();
\r
1851 // Send the query from the file to the Query Parser class
\r
1852 QueryParser presetQuery = QueryParser.Parse(query);
\r
1854 // Now load the preset
\r
1855 PresetLoader.LoadPreset(this, presetQuery, "Load Back From Queue", true);
\r
1857 // The x264 widgets will need updated, so do this now:
\r
1858 x264Panel.X264_StandardizeOptString();
\r
1859 x264Panel.X264_SetCurrentSettingsInPanel();
\r
1861 // Finally, let this window have a copy of the preset settings.
\r
1862 CurrentlySelectedPreset = null;
\r
1863 PictureSettings.SetPresetCropWarningLabel(null);
\r
1869 #region GUI Functions and Actions
\r
1872 /// Set the GUI to it's finished encoding state.
\r
1874 private void SetEncodeFinished()
\r
1878 if (InvokeRequired)
\r
1880 BeginInvoke(new UpdateWindowHandler(SetEncodeFinished));
\r
1884 lbl_encode.Text = "Encoding Finished";
\r
1885 btn_start.Text = "Start";
\r
1886 btn_start.ToolTipText = "Start the encoding process";
\r
1887 btn_start.Image = Properties.Resources.Play;
\r
1889 // If the window is minimized, display the notification in a popup.
\r
1890 if (Properties.Settings.Default.trayIconAlerts)
\r
1891 if (FormWindowState.Minimized == this.WindowState)
\r
1893 notifyIcon.BalloonTipText = lbl_encode.Text;
\r
1894 notifyIcon.ShowBalloonTip(500);
\r
1897 catch (Exception exc)
\r
1899 MessageBox.Show(exc.ToString());
\r
1904 /// Set the GUI to it's started encoding state.
\r
1906 private void SetEncodeStarted()
\r
1910 if (InvokeRequired)
\r
1912 BeginInvoke(new UpdateWindowHandler(SetEncodeStarted));
\r
1916 lbl_encode.Visible = true;
\r
1917 lbl_encode.Text = "Encoding with " + encodeQueue.Count + " encode(s) pending";
\r
1918 btn_start.Text = "Stop";
\r
1919 btn_start.ToolTipText = "Stop the encoding process.";
\r
1920 btn_start.Image = Properties.Resources.stop;
\r
1922 catch (Exception exc)
\r
1924 MessageBox.Show(exc.ToString());
\r
1929 /// Set the DVD Drive selection in the "Source" Menu
\r
1931 private void SetDriveSelectionMenuItem()
\r
1935 if (InvokeRequired)
\r
1937 BeginInvoke(new UpdateWindowHandler(SetDriveSelectionMenuItem));
\r
1941 drives = Main.GetDrives();
\r
1943 List<ToolStripMenuItem> menuItems = new List<ToolStripMenuItem>();
\r
1944 foreach (DriveInformation drive in drives)
\r
1946 ToolStripMenuItem menuItem = new ToolStripMenuItem();
\r
1947 menuItem.Name = drive.ToString();
\r
1948 menuItem.Text = drive.RootDirectory + " (" + drive.VolumeLabel + ")";
\r
1949 menuItem.Image = Resources.disc_small;
\r
1950 menuItem.Click += new EventHandler(mnu_dvd_drive_Click);
\r
1951 menuItems.Add(menuItem);
\r
1954 foreach (ToolStripMenuItem item in menuItems)
\r
1955 btn_source.DropDownItems.Add(item);
\r
1957 catch (Exception exc)
\r
1959 MessageBox.Show("Error in SetDriveSelectionMenuItem" + exc);
\r
1964 /// Access the preset Handler and setup the preset panel.
\r
1966 private void LoadPresetPanel()
\r
1968 if (presetHandler.CheckIfPresetsAreOutOfDate())
\r
1969 if (!Properties.Settings.Default.presetNotification)
\r
1970 MessageBox.Show(splash,
\r
1971 "HandBrake has determined your built-in presets are out of date... These presets will now be updated.",
\r
1972 "Preset Update", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
1974 presetHandler.GetPresetPanel(ref treeView_presets);
\r
1975 treeView_presets.Update();
\r
1983 /// Handle GUI shortcuts
\r
1985 /// <param name="msg"></param>
\r
1986 /// <param name="keyData"></param>
\r
1987 /// <returns></returns>
\r
1988 protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
\r
1990 if (keyData == (Keys.Control | Keys.S))
\r
1992 btn_start_Click(this, new EventArgs());
\r
1996 if (keyData == (Keys.Control | Keys.A))
\r
1998 btn_add2Queue_Click(this, new EventArgs());
\r
2001 return base.ProcessCmdKey(ref msg, keyData);
\r
2005 /// If the queue is being processed, prompt the user to confirm application close.
\r
2007 /// <param name="e"></param>
\r
2008 protected override void OnFormClosing(FormClosingEventArgs e)
\r
2010 // If currently encoding, the queue isn't paused, and there are queue items to process, prompt to confirm close.
\r
2011 if ((encodeQueue.IsEncoding) && (!encodeQueue.PauseRequested) && (encodeQueue.Count > 0))
\r
2013 DialogResult result =
\r
2015 "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
2016 "Close HandBrake?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
2017 if (result == DialogResult.No)
\r
2020 base.OnFormClosing(e);
\r
2025 #region In-GUI Encode Status (Experimental)
\r
2028 /// Starts a new thread to monitor and process the CLI encode status
\r
2030 private void EncodeMonitorThread()
\r
2034 Parser encode = new Parser(encodeQueue.HbProcess.StandardOutput.BaseStream);
\r
2035 encode.OnEncodeProgress += EncodeOnEncodeProgress;
\r
2036 while (!encode.EndOfStream)
\r
2037 encode.ReadEncodeStatus();
\r
2039 catch (Exception exc)
\r
2041 MessageBox.Show(exc.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
2046 /// Displays the Encode status in the GUI
\r
2048 /// <param name="Sender"></param>
\r
2049 /// <param name="CurrentTask"></param>
\r
2050 /// <param name="TaskCount"></param>
\r
2051 /// <param name="PercentComplete"></param>
\r
2052 /// <param name="CurrentFps"></param>
\r
2053 /// <param name="AverageFps"></param>
\r
2054 /// <param name="TimeRemaining"></param>
\r
2055 private void EncodeOnEncodeProgress(object Sender, int CurrentTask, int TaskCount, float PercentComplete,
\r
2056 float CurrentFps, float AverageFps, TimeSpan TimeRemaining)
\r
2058 if (this.InvokeRequired)
\r
2060 this.BeginInvoke(new EncodeProgressEventHandler(EncodeOnEncodeProgress),
\r
2063 Sender, CurrentTask, TaskCount, PercentComplete, CurrentFps, AverageFps,
\r
2069 string.Format("Encode Progress: {0}%, FPS: {1}, Avg FPS: {2}, Time Remaining: {3} ",
\r
2070 PercentComplete, CurrentFps, AverageFps, TimeRemaining);
\r
2075 // This is the END of the road ****************************************
\r