2 This file is part of the HandBrake source code.
\r
3 Homepage: <http://handbrake.fr/>.
\r
4 It may be used under the terms of the GNU General Public License. */
\r
9 using System.Collections.Generic;
\r
10 using System.ComponentModel;
\r
11 using System.Diagnostics;
\r
12 using System.Drawing;
\r
13 using System.Globalization;
\r
15 using System.Reflection;
\r
16 using System.Threading;
\r
17 using System.Windows.Forms;
\r
25 public partial class frmMain : Form
\r
27 // Objects which may be used by one or more other objects *************
\r
28 private Queue encodeQueue = new Queue();
\r
29 private PresetsHandler presetHandler = new PresetsHandler();
\r
31 // Globals: Mainly used for tracking. *********************************
\r
32 public Title selectedTitle;
\r
33 private frmQueue queueWindow;
\r
34 private frmPreview qtpreview;
\r
35 private frmActivityWindow ActivityWindow;
\r
36 private Form splash;
\r
37 public string sourcePath;
\r
38 private 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 ScanService SourceScan = new ScanService();
\r
44 private List<DriveInformation> drives;
\r
45 private Thread encodeMonitor;
\r
47 // Delegates **********************************************************
\r
48 private delegate void UpdateWindowHandler();
\r
50 // Applicaiton Startup ************************************************
\r
52 #region Application Startup
\r
56 // Load and setup the splash screen in this thread
\r
57 splash = new frmSplashScreen();
\r
59 Label lblStatus = new Label { Size = new Size(150, 20), Location = new Point(182, 102) };
\r
60 splash.Controls.Add(lblStatus);
\r
62 InitializeComponent();
\r
64 // Update the users config file with the CLI version data.
\r
65 lblStatus.Text = "Checking CLI Version Data ...";
\r
66 Application.DoEvents();
\r
67 Main.SetCliVersionData();
\r
68 Main.CheckForValidCliVersion();
\r
70 if (Settings.Default.hb_version.Contains("svn"))
\r
72 Version v = Assembly.GetExecutingAssembly().GetName().Version;
\r
73 this.Text += " " + v.ToString(4);
\r
76 // Show the form, but leave disabled until preloading is complete then show the main form)
\r
77 this.Enabled = false;
\r
79 Application.DoEvents(); // Forces frmMain to draw
\r
81 // Check for new versions, if update checking is enabled
\r
82 if (Properties.Settings.Default.updateStatus)
\r
84 DateTime now = DateTime.Now;
\r
85 DateTime lastCheck = Properties.Settings.Default.lastUpdateCheckDate;
\r
86 TimeSpan elapsed = now.Subtract(lastCheck);
\r
87 if (elapsed.TotalDays > Properties.Settings.Default.daysBetweenUpdateCheck)
\r
89 lblStatus.Text = "Checking for updates ...";
\r
90 Application.DoEvents();
\r
92 Main.BeginCheckForUpdates(new AsyncCallback(UpdateCheckDone), false);
\r
96 // Clear the log files in the background
\r
97 if (Properties.Settings.Default.clearOldLogs)
\r
99 lblStatus.Text = "Clearing Old Log Files ...";
\r
100 Application.DoEvents();
\r
101 Thread clearLog = new Thread(Main.ClearOldLogs);
\r
105 // Setup the GUI components
\r
106 lblStatus.Text = "Setting up the GUI ...";
\r
107 Application.DoEvents();
\r
108 LoadPresetPanel(); // Load the Preset Panel
\r
109 treeView_presets.ExpandAll();
\r
110 lbl_encode.Text = string.Empty;
\r
111 drop_mode.SelectedIndex = 0;
\r
112 queueWindow = new frmQueue(encodeQueue, this); // Prepare the Queue
\r
113 if (!Properties.Settings.Default.QueryEditorTab)
\r
114 tabs_panel.TabPages.RemoveAt(7); // Remove the query editor tab if the user does not want it enabled.
\r
116 // Load the user's default settings or Normal Preset
\r
117 if (Properties.Settings.Default.defaultPreset != string.Empty)
\r
119 if (presetHandler.GetPreset(Properties.Settings.Default.defaultPreset) != null)
\r
121 string query = presetHandler.GetPreset(Properties.Settings.Default.defaultPreset).Query;
\r
122 bool loadPictureSettings =
\r
123 presetHandler.GetPreset(Properties.Settings.Default.defaultPreset).PictureSettings;
\r
127 x264Panel.Reset2Defaults();
\r
129 QueryParser presetQuery = QueryParser.Parse(query);
\r
130 PresetLoader.LoadPreset(this, presetQuery, Properties.Settings.Default.defaultPreset,
\r
131 loadPictureSettings);
\r
133 x264Panel.X264_StandardizeOptString();
\r
134 x264Panel.X264_SetCurrentSettingsInPanel();
\r
138 loadNormalPreset();
\r
141 loadNormalPreset();
\r
143 // Enabled GUI tooltip's if Required
\r
144 if (Properties.Settings.Default.tooltipEnable)
\r
145 ToolTip.Active = true;
\r
147 // Register with Growl (if not using Growl for the encoding completion action, this wont hurt anything)
\r
148 GrowlCommunicator.Register();
\r
150 // Finished Loading
\r
151 lblStatus.Text = "Loading Complete!";
\r
152 Application.DoEvents();
\r
155 this.Enabled = true;
\r
157 // Event Handlers and Queue Recovery
\r
162 private void UpdateCheckDone(IAsyncResult result)
\r
164 if (InvokeRequired)
\r
166 Invoke(new MethodInvoker(() => UpdateCheckDone(result)));
\r
170 UpdateCheckInformation info;
\r
174 info = Main.EndCheckForUpdates(result);
\r
176 if (info.NewVersionAvailable)
\r
178 frmUpdater updateWindow = new frmUpdater(info.BuildInformation);
\r
179 updateWindow.ShowDialog();
\r
182 catch (Exception ex)
\r
184 if ((bool)result.AsyncState)
\r
186 "Unable to check for updates, Please try again later.\n\nDetailed Error Information:\n" + ex,
\r
187 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
191 // Startup Functions
\r
192 private void queueRecovery()
\r
194 if (Main.CheckQueueRecovery())
\r
196 DialogResult result =
\r
198 "HandBrake has detected unfinished items on the queue from the last time the application was launched. Would you like to recover these?",
\r
199 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
201 if (result == DialogResult.Yes)
\r
202 encodeQueue.LoadQueueFromFile("hb_queue_recovery.xml"); // Start Recovery
\r
205 // Remove the Queue recovery file if the user doesn't want to recovery the last queue.
\r
206 string queuePath = Path.Combine(Path.GetTempPath(), "hb_queue_recovery.xml");
\r
207 if (File.Exists(queuePath))
\r
208 File.Delete(queuePath);
\r
217 public string SourceName
\r
221 if (this.selectedSourceType == SourceType.DvdDrive)
\r
223 return this.dvdDriveLabel;
\r
226 if (Path.GetFileNameWithoutExtension(this.sourcePath) != "VIDEO_TS")
\r
227 return Path.GetFileNameWithoutExtension(this.sourcePath);
\r
229 return Path.GetFileNameWithoutExtension(Path.GetDirectoryName(this.sourcePath));
\r
237 // Encoding Events for setting up the GUI
\r
238 private void events()
\r
240 // Handle Widget changes when preset is selected.
\r
241 RegisterPresetEventHandler();
\r
243 // Handle Window Resize
\r
244 if (Properties.Settings.Default.MainWindowMinimize)
\r
245 this.Resize += new EventHandler(frmMain_Resize);
\r
247 // Handle Encode Start / Finish / Pause
\r
249 encodeQueue.QueuePauseRequested += new EventHandler(encodePaused);
\r
250 encodeQueue.EncodeStarted += new EventHandler(encodeStarted);
\r
251 encodeQueue.EncodeEnded += new EventHandler(encodeEnded);
\r
253 // Handle a file being draged onto the GUI.
\r
254 this.DragEnter += new DragEventHandler(frmMain_DragEnter);
\r
255 this.DragDrop += new DragEventHandler(frmMain_DragDrop);
\r
258 // 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
259 private void RegisterPresetEventHandler()
\r
262 drop_format.SelectedIndexChanged += new EventHandler(changePresetLabel);
\r
263 check_largeFile.CheckedChanged += new EventHandler(changePresetLabel);
\r
264 check_iPodAtom.CheckedChanged += new EventHandler(changePresetLabel);
\r
265 check_optimiseMP4.CheckedChanged += new EventHandler(changePresetLabel);
\r
267 // Picture Settings
\r
268 // PictureSettings.PictureSettingsChanged += new EventHandler(changePresetLabel);
\r
271 Filters.FilterSettingsChanged += new EventHandler(changePresetLabel);
\r
274 drp_videoEncoder.SelectedIndexChanged += new EventHandler(changePresetLabel);
\r
275 check_2PassEncode.CheckedChanged += new EventHandler(changePresetLabel);
\r
276 check_turbo.CheckedChanged += new EventHandler(changePresetLabel);
\r
277 text_filesize.TextChanged += new EventHandler(changePresetLabel);
\r
278 text_bitrate.TextChanged += new EventHandler(changePresetLabel);
\r
279 slider_videoQuality.ValueChanged += new EventHandler(changePresetLabel);
\r
282 AudioSettings.AudioListChanged += new EventHandler(changePresetLabel);
\r
285 x264Panel.rtf_x264Query.TextChanged += new EventHandler(changePresetLabel);
\r
288 private void UnRegisterPresetEventHandler()
\r
290 // Output Settings
\r
291 drop_format.SelectedIndexChanged -= new EventHandler(changePresetLabel);
\r
292 check_largeFile.CheckedChanged -= new EventHandler(changePresetLabel);
\r
293 check_iPodAtom.CheckedChanged -= new EventHandler(changePresetLabel);
\r
294 check_optimiseMP4.CheckedChanged -= new EventHandler(changePresetLabel);
\r
296 // Picture Settings
\r
297 // PictureSettings.PictureSettingsChanged -= new EventHandler(changePresetLabel);
\r
300 Filters.FilterSettingsChanged -= new EventHandler(changePresetLabel);
\r
303 drp_videoEncoder.SelectedIndexChanged -= new EventHandler(changePresetLabel);
\r
304 check_2PassEncode.CheckedChanged -= new EventHandler(changePresetLabel);
\r
305 check_turbo.CheckedChanged -= new EventHandler(changePresetLabel);
\r
306 text_filesize.TextChanged -= new EventHandler(changePresetLabel);
\r
307 text_bitrate.TextChanged -= new EventHandler(changePresetLabel);
\r
308 slider_videoQuality.ValueChanged -= new EventHandler(changePresetLabel);
\r
311 AudioSettings.AudioListChanged -= new EventHandler(changePresetLabel);
\r
314 x264Panel.rtf_x264Query.TextChanged -= new EventHandler(changePresetLabel);
\r
317 private void changePresetLabel(object sender, EventArgs e)
\r
319 labelPreset.Text = "Output Settings (Preset: Custom)";
\r
320 CurrentlySelectedPreset = null;
\r
323 private static void frmMain_DragEnter(object sender, DragEventArgs e)
\r
325 if (e.Data.GetDataPresent(DataFormats.FileDrop, false))
\r
326 e.Effect = DragDropEffects.All;
\r
329 private void frmMain_DragDrop(object sender, DragEventArgs e)
\r
331 string[] fileList = e.Data.GetData(DataFormats.FileDrop) as string[];
\r
332 sourcePath = string.Empty;
\r
334 if (fileList != null)
\r
336 if (fileList[0] != string.Empty)
\r
338 this.selectedSourceType = SourceType.VideoFile;
\r
339 StartScan(fileList[0], 0);
\r
342 UpdateSourceLabel();
\r
345 UpdateSourceLabel();
\r
348 private void encodeStarted(object sender, EventArgs e)
\r
350 SetEncodeStarted();
\r
352 // Experimental HBProc Process Monitoring.
\r
353 if (Properties.Settings.Default.enocdeStatusInGui)
\r
355 encodeMonitor = new Thread(EncodeMonitorThread);
\r
356 encodeMonitor.Start();
\r
360 private void encodeEnded(object sender, EventArgs e)
\r
362 SetEncodeFinished();
\r
365 private void encodePaused(object sender, EventArgs e)
\r
367 SetEncodeFinished();
\r
372 // User Interface Menus / Tool Strips *********************************
\r
376 private void mnu_killCLI_Click(object sender, EventArgs e)
\r
381 private void mnu_exit_Click(object sender, EventArgs e)
\r
383 Application.Exit();
\r
390 private void mnu_encode_Click(object sender, EventArgs e)
\r
392 queueWindow.Show();
\r
395 private void mnu_encodeLog_Click(object sender, EventArgs e)
\r
397 frmActivityWindow dvdInfoWindow = new frmActivityWindow(encodeQueue, SourceScan);
\r
398 dvdInfoWindow.Show();
\r
401 private void mnu_options_Click(object sender, EventArgs e)
\r
403 Form options = new frmOptions(this);
\r
404 options.ShowDialog();
\r
409 #region Presets Menu
\r
411 private void mnu_presetReset_Click(object sender, EventArgs e)
\r
413 presetHandler.UpdateBuiltInPresets();
\r
415 if (treeView_presets.Nodes.Count == 0)
\r
417 "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
418 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
420 MessageBox.Show("Presets have been updated!", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
422 treeView_presets.ExpandAll();
\r
425 private void mnu_delete_preset_Click(object sender, EventArgs e)
\r
427 presetHandler.RemoveBuiltInPresets();
\r
428 LoadPresetPanel(); // Reload the preset panel
\r
431 private void mnu_SelectDefault_Click(object sender, EventArgs e)
\r
433 loadNormalPreset();
\r
436 private void mnu_importMacPreset_Click(object sender, EventArgs e)
\r
441 private void mnu_exportMacPreset_Click(object sender, EventArgs e)
\r
447 private void btn_new_preset_Click(object sender, EventArgs e)
\r
449 Form preset = new frmAddPreset(this, QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
451 preset.ShowDialog();
\r
458 private void mnu_user_guide_Click(object sender, EventArgs e)
\r
460 Process.Start("http://trac.handbrake.fr/wiki/HandBrakeGuide");
\r
463 private void mnu_handbrake_home_Click(object sender, EventArgs e)
\r
465 Process.Start("http://handbrake.fr");
\r
468 private void mnu_UpdateCheck_Click(object sender, EventArgs e)
\r
470 lbl_updateCheck.Visible = true;
\r
471 Main.BeginCheckForUpdates(new AsyncCallback(updateCheckDoneMenu), false);
\r
474 private void updateCheckDoneMenu(IAsyncResult result)
\r
476 // Make sure it's running on the calling thread
\r
477 if (InvokeRequired)
\r
479 Invoke(new MethodInvoker(() => updateCheckDoneMenu(result)));
\r
482 UpdateCheckInformation info;
\r
485 // Get the information about the new build, if any, and close the window
\r
486 info = Main.EndCheckForUpdates(result);
\r
488 if (info.NewVersionAvailable && info.BuildInformation != null)
\r
490 frmUpdater updateWindow = new frmUpdater(info.BuildInformation);
\r
491 updateWindow.ShowDialog();
\r
494 MessageBox.Show("There are no new updates at this time.", "Update Check", MessageBoxButtons.OK,
\r
495 MessageBoxIcon.Information);
\r
496 lbl_updateCheck.Visible = false;
\r
499 catch (Exception ex)
\r
501 if ((bool)result.AsyncState)
\r
503 "Unable to check for updates, Please try again later.\n\nDetailed Error Information:\n" + ex,
\r
504 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
508 private void mnu_about_Click(object sender, EventArgs e)
\r
510 using (frmAbout About = new frmAbout())
\r
512 About.ShowDialog();
\r
520 // Right Click Menu Code
\r
521 private void pmnu_expandAll_Click(object sender, EventArgs e)
\r
523 treeView_presets.ExpandAll();
\r
526 private void pmnu_collapse_Click(object sender, EventArgs e)
\r
528 treeView_presets.CollapseAll();
\r
531 private void pmnu_import_Click(object sender, EventArgs e)
\r
536 private void pmnu_saveChanges_Click(object sender, EventArgs e)
\r
538 DialogResult result =
\r
540 "Do you wish to include picture settings when updating the preset: " +
\r
541 treeView_presets.SelectedNode.Text, "Update Preset", MessageBoxButtons.YesNoCancel,
\r
542 MessageBoxIcon.Question);
\r
543 if (result == DialogResult.Yes)
\r
544 presetHandler.Update(treeView_presets.SelectedNode.Text,
\r
545 QueryGenerator.GenerateTabbedComponentsQuery(this), true);
\r
546 else if (result == DialogResult.No)
\r
547 presetHandler.Update(treeView_presets.SelectedNode.Text,
\r
548 QueryGenerator.GenerateTabbedComponentsQuery(this), false);
\r
551 private void pmnu_delete_click(object sender, EventArgs e)
\r
553 if (treeView_presets.SelectedNode != null)
\r
555 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
556 treeView_presets.Nodes.Remove(treeView_presets.SelectedNode);
\r
558 treeView_presets.Select();
\r
561 private void presets_menu_Opening(object sender, CancelEventArgs e)
\r
563 // Make sure that the save menu is always disabled by default
\r
564 pmnu_saveChanges.Enabled = false;
\r
566 // Now enable the save menu if the selected preset is a user preset
\r
567 if (treeView_presets.SelectedNode != null)
\r
568 if (presetHandler.CheckIfUserPresetExists(treeView_presets.SelectedNode.Text))
\r
569 pmnu_saveChanges.Enabled = true;
\r
571 treeView_presets.Select();
\r
574 // Presets Management
\r
575 private void btn_addPreset_Click(object sender, EventArgs e)
\r
577 Form preset = new frmAddPreset(this, QueryGenerator.GenerateTabbedComponentsQuery(this), presetHandler);
\r
578 preset.ShowDialog();
\r
581 private void btn_removePreset_Click(object sender, EventArgs e)
\r
583 DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected preset?", "Preset",
\r
584 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
585 if (result == DialogResult.Yes)
\r
587 if (treeView_presets.SelectedNode != null)
\r
589 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
590 treeView_presets.Nodes.Remove(treeView_presets.SelectedNode);
\r
593 treeView_presets.Select();
\r
596 private void btn_setDefault_Click(object sender, EventArgs e)
\r
598 if (treeView_presets.SelectedNode != null)
\r
600 DialogResult result = MessageBox.Show("Are you sure you wish to set this preset as the default?",
\r
601 "Preset", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
602 if (result == DialogResult.Yes)
\r
604 Properties.Settings.Default.defaultPreset = treeView_presets.SelectedNode.Text;
\r
605 Properties.Settings.Default.Save();
\r
606 MessageBox.Show("New default preset set.", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
610 MessageBox.Show("Please select a preset first.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
613 private void treeview_presets_mouseUp(object sender, MouseEventArgs e)
\r
615 if (e.Button == MouseButtons.Right)
\r
616 treeView_presets.SelectedNode = treeView_presets.GetNodeAt(e.Location);
\r
617 else if (e.Button == MouseButtons.Left)
\r
619 if (treeView_presets.GetNodeAt(e.Location) != null)
\r
621 if (labelPreset.Text.Contains(treeView_presets.GetNodeAt(e.Location).Text))
\r
626 treeView_presets.Select();
\r
629 private void treeView_presets_AfterSelect(object sender, TreeViewEventArgs e)
\r
634 private void treeView_presets_deleteKey(object sender, KeyEventArgs e)
\r
636 if (e.KeyCode == Keys.Delete)
\r
638 DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected preset?", "Preset",
\r
639 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
640 if (result == DialogResult.Yes)
\r
642 if (treeView_presets.SelectedNode != null)
\r
643 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
645 // Remember each nodes expanded status so we can reload it
\r
646 List<bool> nodeStatus = new List<bool>();
\r
647 foreach (TreeNode node in treeView_presets.Nodes)
\r
648 nodeStatus.Add(node.IsExpanded);
\r
650 // Now reload the preset panel
\r
653 // And finally, re-expand any of the nodes if required
\r
655 foreach (TreeNode node in treeView_presets.Nodes)
\r
666 private void selectPreset()
\r
668 if (treeView_presets.SelectedNode != null)
\r
670 // Ok, so, we've selected a preset. Now we want to load it.
\r
671 string presetName = treeView_presets.SelectedNode.Text;
\r
672 Preset preset = presetHandler.GetPreset(presetName);
\r
673 if (preset != null)
\r
675 string query = presetHandler.GetPreset(presetName).Query;
\r
676 bool loadPictureSettings = presetHandler.GetPreset(presetName).PictureSettings;
\r
680 // Ok, Reset all the H264 widgets before changing the preset
\r
681 x264Panel.Reset2Defaults();
\r
683 // Send the query from the file to the Query Parser class
\r
684 QueryParser presetQuery = QueryParser.Parse(query);
\r
686 // Now load the preset
\r
687 PresetLoader.LoadPreset(this, presetQuery, presetName, loadPictureSettings);
\r
689 // The x264 widgets will need updated, so do this now:
\r
690 x264Panel.X264_StandardizeOptString();
\r
691 x264Panel.X264_SetCurrentSettingsInPanel();
\r
693 // Finally, let this window have a copy of the preset settings.
\r
694 CurrentlySelectedPreset = preset;
\r
695 PictureSettings.SetPresetCropWarningLabel(preset);
\r
701 private void loadNormalPreset()
\r
703 foreach (TreeNode treenode in treeView_presets.Nodes)
\r
705 foreach (TreeNode node in treenode.Nodes)
\r
707 if (node.Text.Equals("Normal"))
\r
708 treeView_presets.SelectedNode = treeView_presets.Nodes[treenode.Index].Nodes[0];
\r
713 private void ImportPreset()
\r
715 if (openPreset.ShowDialog() == DialogResult.OK)
\r
717 QueryParser parsed = PlistPresetHandler.Import(openPreset.FileName);
\r
718 if (presetHandler.CheckIfUserPresetExists(parsed.PresetName + " (Imported)"))
\r
720 DialogResult result =
\r
721 MessageBox.Show("This preset appears to already exist. Would you like to overwrite it?",
\r
722 "Overwrite preset?",
\r
723 MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
\r
724 if (result == DialogResult.Yes)
\r
726 PresetLoader.LoadPreset(this, parsed, parsed.PresetName, parsed.UsesPictureSettings);
\r
727 presetHandler.Update(parsed.PresetName + " (Imported)",
\r
728 QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
729 parsed.UsesPictureSettings);
\r
734 PresetLoader.LoadPreset(this, parsed, parsed.PresetName, parsed.UsesPictureSettings);
\r
735 if (presetHandler.Add(parsed.PresetName + " (Imported)",
\r
736 QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
737 parsed.UsesPictureSettings))
\r
739 TreeNode preset_treeview = new TreeNode(parsed.PresetName + " (Imported)")
\r
741 ForeColor = Color.Black
\r
743 treeView_presets.Nodes.Add(preset_treeview);
\r
749 private void ExportPreset()
\r
751 // MessageBox.Show("This feature has not been implimented yet.", "Not Implimented", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
754 SaveFileDialog savefiledialog = new SaveFileDialog();
\r
755 savefiledialog.Filter = "plist|*.plist";
\r
757 if (treeView_presets.SelectedNode != null)
\r
760 if (savefiledialog.ShowDialog() == DialogResult.OK)
\r
762 Preset preset = presetHandler.GetPreset(treeView_presets.SelectedNode.Text);
\r
763 PlistPresetHandler.Export(savefiledialog.FileName, preset);
\r
772 private void btn_source_Click(object sender, EventArgs e)
\r
774 // Remove old Drive Menu Items.
\r
775 List<ToolStripMenuItem> itemsToRemove = new List<ToolStripMenuItem>();
\r
776 foreach (var item in btn_source.DropDownItems)
\r
778 if (item.GetType() == typeof(ToolStripMenuItem))
\r
780 ToolStripMenuItem menuItem = (ToolStripMenuItem)item;
\r
781 if (menuItem.Name.StartsWith("Drive"))
\r
783 itemsToRemove.Add(menuItem);
\r
788 foreach (ToolStripMenuItem item in itemsToRemove)
\r
789 btn_source.DropDownItems.Remove(item);
\r
791 Thread driveInfoThread = new Thread(SetDriveSelectionMenuItem);
\r
792 driveInfoThread.Start();
\r
795 private void btn_start_Click(object sender, EventArgs e)
\r
797 if (btn_start.Text == "Stop")
\r
799 DialogResult result;
\r
800 if (Properties.Settings.Default.enocdeStatusInGui &&
\r
801 !Properties.Settings.Default.showCliForInGuiEncodeStatus)
\r
803 result = MessageBox.Show(
\r
804 "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
805 "Cancel Encode?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
809 result = MessageBox.Show("Are you sure you wish to cancel the encode?", "Cancel Encode?",
\r
810 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
813 if (result == DialogResult.Yes)
\r
816 encodeQueue.Pause();
\r
818 if (Properties.Settings.Default.enocdeStatusInGui &&
\r
819 !Properties.Settings.Default.showCliForInGuiEncodeStatus)
\r
821 encodeQueue.Stop();
\r
822 if (encodeQueue.HbProcess != null)
\r
823 encodeQueue.HbProcess.WaitForExit();
\r
827 encodeQueue.SafelyClose();
\r
833 if (encodeQueue.Count != 0 ||
\r
834 (!string.IsNullOrEmpty(sourcePath) && !string.IsNullOrEmpty(text_destination.Text)))
\r
836 string generatedQuery = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
837 string specifiedQuery = rtf_query.Text != string.Empty
\r
839 : QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
840 string query = string.Empty;
\r
842 // Check to make sure the generated query matches the GUI settings
\r
843 if (Properties.Settings.Default.PromptOnUnmatchingQueries && !string.IsNullOrEmpty(specifiedQuery) &&
\r
844 generatedQuery != specifiedQuery)
\r
846 DialogResult result = MessageBox.Show("The query under the \"Query Editor\" tab " +
\r
847 "does not match the current GUI settings.\n\nBecause the manual query takes " +
\r
848 "priority over the GUI, your recently updated settings will not be taken " +
\r
849 "into account when encoding this job." +
\r
850 Environment.NewLine + Environment.NewLine +
\r
851 "Do you want to replace the manual query with the updated GUI-generated query?",
\r
852 "Manual Query does not Match GUI",
\r
853 MessageBoxButtons.YesNoCancel, MessageBoxIcon.Asterisk,
\r
854 MessageBoxDefaultButton.Button3);
\r
858 case DialogResult.Yes:
\r
859 // Replace the manual query with the generated one
\r
860 query = generatedQuery;
\r
861 rtf_query.Text = generatedQuery;
\r
863 case DialogResult.No:
\r
864 // Use the manual query
\r
865 query = specifiedQuery;
\r
867 case DialogResult.Cancel:
\r
868 // Don't start the encode
\r
874 query = specifiedQuery;
\r
877 DialogResult overwrite = DialogResult.Yes;
\r
878 if (text_destination.Text != string.Empty)
\r
879 if (File.Exists(text_destination.Text))
\r
882 "The destination file already exists. Are you sure you want to overwrite it?",
\r
883 "Overwrite File?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
885 if (overwrite == DialogResult.Yes)
\r
887 if (encodeQueue.Count == 0)
\r
888 encodeQueue.Add(query, getTitle(), sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
890 queueWindow.SetQueue();
\r
891 if (encodeQueue.Count > 1)
\r
892 queueWindow.Show(false);
\r
894 SetEncodeStarted(); // Encode is running, so setup the GUI appropriately
\r
895 encodeQueue.Start(); // Start The Queue Encoding Process
\r
900 else if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
901 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
902 MessageBoxIcon.Warning);
\r
906 private void btn_add2Queue_Click(object sender, EventArgs e)
\r
908 if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
909 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
910 MessageBoxIcon.Warning);
\r
913 string query = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
914 if (rtf_query.Text != string.Empty)
\r
915 query = rtf_query.Text;
\r
917 if (encodeQueue.CheckForDestinationDuplicate(text_destination.Text))
\r
919 DialogResult result =
\r
921 "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
922 "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
\r
923 if (result == DialogResult.Yes)
\r
924 encodeQueue.Add(query, getTitle(), sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
927 encodeQueue.Add(query, getTitle(), sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
929 lbl_encode.Text = encodeQueue.Count + " encode(s) pending in the queue";
\r
931 queueWindow.Show();
\r
935 private void btn_showQueue_Click(object sender, EventArgs e)
\r
937 queueWindow.Show();
\r
938 queueWindow.Activate();
\r
941 private void tb_preview_Click(object sender, EventArgs e)
\r
943 if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
944 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
945 MessageBoxIcon.Warning);
\r
948 if (qtpreview == null)
\r
950 qtpreview = new frmPreview(this);
\r
953 else if (qtpreview.IsDisposed)
\r
955 qtpreview = new frmPreview(this);
\r
959 MessageBox.Show(qtpreview, "The preview window is already open!", "Warning", MessageBoxButtons.OK,
\r
960 MessageBoxIcon.Warning);
\r
964 private void btn_ActivityWindow_Click(object sender, EventArgs e)
\r
966 if (ActivityWindow == null || !ActivityWindow.IsHandleCreated)
\r
967 ActivityWindow = new frmActivityWindow(encodeQueue, SourceScan);
\r
969 ActivityWindow.Show();
\r
970 ActivityWindow.Activate();
\r
975 #region System Tray Icon
\r
977 private void frmMain_Resize(object sender, EventArgs e)
\r
979 if (FormWindowState.Minimized == this.WindowState)
\r
981 notifyIcon.Visible = true;
\r
984 else if (FormWindowState.Normal == this.WindowState)
\r
985 notifyIcon.Visible = false;
\r
988 private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
\r
990 this.Visible = true;
\r
992 this.WindowState = FormWindowState.Normal;
\r
993 notifyIcon.Visible = false;
\r
996 private void btn_restore_Click(object sender, EventArgs e)
\r
998 this.Visible = true;
\r
1000 this.WindowState = FormWindowState.Normal;
\r
1001 notifyIcon.Visible = false;
\r
1006 #region Tab Control
\r
1009 private void btn_dvd_source_Click(object sender, EventArgs e)
\r
1011 if (DVD_Open.ShowDialog() == DialogResult.OK)
\r
1013 this.selectedSourceType = SourceType.Folder;
\r
1014 SelectSource(DVD_Open.SelectedPath);
\r
1017 UpdateSourceLabel();
\r
1020 private void btn_file_source_Click(object sender, EventArgs e)
\r
1022 if (ISO_Open.ShowDialog() == DialogResult.OK)
\r
1024 this.selectedSourceType = SourceType.VideoFile;
\r
1025 SelectSource(ISO_Open.FileName);
\r
1028 UpdateSourceLabel();
\r
1031 private void mnu_dvd_drive_Click(object sender, EventArgs e)
\r
1033 ToolStripMenuItem item = sender as ToolStripMenuItem;
\r
1036 string driveId = item.Name.Replace("Drive", string.Empty);
\r
1038 if (int.TryParse(driveId, out id))
\r
1041 this.dvdDrivePath = drives[id].RootDirectory;
\r
1042 this.dvdDriveLabel = drives[id].VolumeLabel;
\r
1044 if (this.dvdDrivePath == null) return;
\r
1045 this.selectedSourceType = SourceType.DvdDrive;
\r
1046 SelectSource(this.dvdDrivePath);
\r
1051 private void SelectSource(string file)
\r
1053 Check_ChapterMarkers.Enabled = true;
\r
1054 sourcePath = string.Empty;
\r
1056 if (file == string.Empty) // Must have a file or path
\r
1058 UpdateSourceLabel();
\r
1062 sourcePath = Path.GetFileName(file);
\r
1063 StartScan(file, 0);
\r
1066 private void drp_dvdtitle_Click(object sender, EventArgs e)
\r
1068 if ((drp_dvdtitle.Items.Count == 1) && (drp_dvdtitle.Items[0].ToString() == "Automatic"))
\r
1070 "There are no titles to select. Please load a source file by clicking the 'Source' button above before trying to select a title.",
\r
1071 "Alert", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
\r
1074 private void drp_dvdtitle_SelectedIndexChanged(object sender, EventArgs e)
\r
1076 UnRegisterPresetEventHandler();
\r
1077 drop_mode.SelectedIndex = 0;
\r
1079 drop_chapterStart.Items.Clear();
\r
1080 drop_chapterFinish.Items.Clear();
\r
1082 // If the dropdown is set to automatic nothing else needs to be done.
\r
1083 // Otheriwse if its not, title data has to be loaded from parsing.
\r
1084 if (drp_dvdtitle.Text != "Automatic")
\r
1086 selectedTitle = drp_dvdtitle.SelectedItem as Title;
\r
1087 lbl_duration.Text = selectedTitle.Duration.ToString();
\r
1088 PictureSettings.CurrentlySelectedPreset = CurrentlySelectedPreset;
\r
1089 PictureSettings.Source = selectedTitle; // Setup Picture Settings Tab Control
\r
1091 // Populate the Angles dropdown
\r
1092 drop_angle.Items.Clear();
\r
1093 if (!Properties.Settings.Default.noDvdNav)
\r
1095 drop_angle.Visible = true;
\r
1096 lbl_angle.Visible = true;
\r
1097 drop_angle.Items.AddRange(selectedTitle.Angles.ToArray());
\r
1098 if (drop_angle.Items.Count != 0)
\r
1099 drop_angle.SelectedIndex = 0;
\r
1103 drop_angle.Visible = false;
\r
1104 lbl_angle.Visible = false;
\r
1107 // Populate the Start chapter Dropdown
\r
1108 drop_chapterStart.Items.Clear();
\r
1109 drop_chapterStart.Items.AddRange(selectedTitle.Chapters.ToArray());
\r
1110 if (drop_chapterStart.Items.Count > 0)
\r
1111 drop_chapterStart.Text = drop_chapterStart.Items[0].ToString();
\r
1113 // Populate the Final Chapter Dropdown
\r
1114 drop_chapterFinish.Items.Clear();
\r
1115 drop_chapterFinish.Items.AddRange(selectedTitle.Chapters.ToArray());
\r
1116 if (drop_chapterFinish.Items.Count > 0)
\r
1117 drop_chapterFinish.Text = drop_chapterFinish.Items[drop_chapterFinish.Items.Count - 1].ToString();
\r
1119 // Populate the Audio Channels Dropdown
\r
1120 AudioSettings.SetTrackList(selectedTitle, CurrentlySelectedPreset);
\r
1122 // Populate the Subtitles dropdown
\r
1123 Subtitles.SetSubtitleTrackAuto(selectedTitle.Subtitles.ToArray());
\r
1125 // Update the source label if we have multiple streams
\r
1126 if (selectedTitle != null)
\r
1127 if (!string.IsNullOrEmpty(selectedTitle.SourceName))
\r
1128 labelSource.Text = labelSource.Text = Path.GetFileName(selectedTitle.SourceName);
\r
1130 // Run the AutoName & ChapterNaming functions
\r
1131 if (Properties.Settings.Default.autoNaming)
\r
1133 string autoPath = Main.AutoName(this);
\r
1134 if (autoPath != null)
\r
1135 text_destination.Text = autoPath;
\r
1138 "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
1139 "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
1142 data_chpt.Rows.Clear();
\r
1143 if (selectedTitle.Chapters.Count != 1)
\r
1145 DataGridView chapterGridView = Main.ChapterNaming(data_chpt, drop_chapterFinish.Text);
\r
1146 if (chapterGridView != null)
\r
1147 data_chpt = chapterGridView;
\r
1151 Check_ChapterMarkers.Checked = false;
\r
1152 Check_ChapterMarkers.Enabled = false;
\r
1155 // Hack to force the redraw of the scrollbars which don't resize properly when the control is disabled.
\r
1156 data_chpt.Columns[0].Width = 166;
\r
1157 data_chpt.Columns[0].Width = 165;
\r
1159 RegisterPresetEventHandler();
\r
1162 private void chapersChanged(object sender, EventArgs e)
\r
1164 if (drop_mode.SelectedIndex != 0) // Function is not used if we are not in chapters mode.
\r
1167 Control ctl = (Control)sender;
\r
1168 int chapterStart, chapterEnd;
\r
1169 int.TryParse(drop_chapterStart.Text, out chapterStart);
\r
1170 int.TryParse(drop_chapterFinish.Text, out chapterEnd);
\r
1174 case "drop_chapterStart":
\r
1175 if (drop_chapterFinish.SelectedIndex == -1 && drop_chapterFinish.Items.Count != 0)
\r
1176 drop_chapterFinish.SelectedIndex = drop_chapterFinish.Items.Count - 1;
\r
1178 if (chapterEnd != 0)
\r
1179 if (chapterStart > chapterEnd)
\r
1180 drop_chapterFinish.Text = chapterStart.ToString();
\r
1182 case "drop_chapterFinish":
\r
1183 if (drop_chapterStart.Items.Count >= 1 && drop_chapterStart.SelectedIndex == -1)
\r
1184 drop_chapterStart.SelectedIndex = 0;
\r
1186 if (chapterStart != 0)
\r
1187 if (chapterEnd < chapterStart)
\r
1188 drop_chapterFinish.Text = chapterStart.ToString();
\r
1190 // Add more rows to the Chapter menu if needed.
\r
1191 if (Check_ChapterMarkers.Checked)
\r
1193 int i = data_chpt.Rows.Count, finish = 0;
\r
1194 int.TryParse(drop_chapterFinish.Text, out finish);
\r
1196 while (i < finish)
\r
1198 int n = data_chpt.Rows.Add();
\r
1199 data_chpt.Rows[n].Cells[0].Value = (i + 1);
\r
1200 data_chpt.Rows[n].Cells[1].Value = "Chapter " + (i + 1);
\r
1201 data_chpt.Rows[n].Cells[0].ValueType = typeof(int);
\r
1202 data_chpt.Rows[n].Cells[1].ValueType = typeof(string);
\r
1209 // Update the Duration
\r
1210 lbl_duration.Text =
\r
1211 Main.CalculateDuration(drop_chapterStart.SelectedIndex, drop_chapterFinish.SelectedIndex, selectedTitle)
\r
1214 // Run the Autonaming function
\r
1215 if (Properties.Settings.Default.autoNaming)
\r
1216 text_destination.Text = Main.AutoName(this);
\r
1218 // Disable chapter markers if only 1 chapter is selected.
\r
1219 if (chapterStart == chapterEnd)
\r
1221 Check_ChapterMarkers.Enabled = false;
\r
1222 btn_importChapters.Enabled = false;
\r
1223 data_chpt.Enabled = false;
\r
1227 Check_ChapterMarkers.Enabled = true;
\r
1228 if (Check_ChapterMarkers.Checked)
\r
1230 btn_importChapters.Enabled = true;
\r
1231 data_chpt.Enabled = true;
\r
1236 private void SecondsOrFramesChanged(object sender, EventArgs e)
\r
1239 int.TryParse(drop_chapterStart.Text, out start);
\r
1240 int.TryParse(drop_chapterFinish.Text, out end);
\r
1241 double duration = end - start;
\r
1243 switch (drop_mode.SelectedIndex)
\r
1246 lbl_duration.Text = TimeSpan.FromSeconds(duration).ToString();
\r
1249 if (selectedTitle != null)
\r
1251 duration = duration / selectedTitle.Fps;
\r
1252 lbl_duration.Text = TimeSpan.FromSeconds(duration).ToString();
\r
1255 lbl_duration.Text = "--:--:--";
\r
1261 private void drop_mode_SelectedIndexChanged(object sender, EventArgs e)
\r
1264 this.drop_chapterFinish.TextChanged -= new EventHandler(this.SecondsOrFramesChanged);
\r
1265 this.drop_chapterStart.TextChanged -= new EventHandler(this.SecondsOrFramesChanged);
\r
1268 switch (drop_mode.SelectedIndex)
\r
1271 drop_chapterStart.DropDownStyle = ComboBoxStyle.DropDownList;
\r
1272 drop_chapterFinish.DropDownStyle = ComboBoxStyle.DropDownList;
\r
1273 if (drop_chapterStart.Items.Count != 0)
\r
1275 drop_chapterStart.SelectedIndex = 0;
\r
1276 drop_chapterFinish.SelectedIndex = drop_chapterFinish.Items.Count - 1;
\r
1279 lbl_duration.Text = "--:--:--";
\r
1282 this.drop_chapterStart.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1283 this.drop_chapterFinish.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1284 drop_chapterStart.DropDownStyle = ComboBoxStyle.Simple;
\r
1285 drop_chapterFinish.DropDownStyle = ComboBoxStyle.Simple;
\r
1286 if (selectedTitle != null)
\r
1288 drop_chapterStart.Text = "0";
\r
1289 drop_chapterFinish.Text = selectedTitle.Duration.TotalSeconds.ToString();
\r
1293 this.drop_chapterStart.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1294 this.drop_chapterFinish.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1295 drop_chapterStart.DropDownStyle = ComboBoxStyle.Simple;
\r
1296 drop_chapterFinish.DropDownStyle = ComboBoxStyle.Simple;
\r
1297 if (selectedTitle != null)
\r
1299 drop_chapterStart.Text = "0";
\r
1300 drop_chapterFinish.Text = (selectedTitle.Fps * selectedTitle.Duration.TotalSeconds).ToString();
\r
1307 private void btn_destBrowse_Click(object sender, EventArgs e)
\r
1309 // This removes the file extension from the filename box on the save file dialog.
\r
1310 // It's daft but some users don't realise that typing an extension overrides the dropdown extension selected.
\r
1311 DVD_Save.FileName = Path.GetFileNameWithoutExtension(text_destination.Text);
\r
1313 if (Path.IsPathRooted(text_destination.Text))
\r
1314 DVD_Save.InitialDirectory = Path.GetDirectoryName(text_destination.Text);
\r
1316 // Show the dialog and set the main form file path
\r
1317 if (drop_format.SelectedIndex.Equals(0))
\r
1318 DVD_Save.FilterIndex = 1;
\r
1319 else if (drop_format.SelectedIndex.Equals(1))
\r
1320 DVD_Save.FilterIndex = 2;
\r
1322 if (DVD_Save.ShowDialog() == DialogResult.OK)
\r
1324 // Add a file extension manually, as FileDialog.AddExtension has issues with dots in filenames
\r
1325 switch (DVD_Save.FilterIndex)
\r
1329 !Path.GetExtension(DVD_Save.FileName).Equals(".mp4",
\r
1330 StringComparison.InvariantCultureIgnoreCase))
\r
1331 if (Properties.Settings.Default.useM4v)
\r
1332 DVD_Save.FileName = DVD_Save.FileName.Replace(".mp4", ".m4v").Replace(".mkv", ".m4v");
\r
1334 DVD_Save.FileName = DVD_Save.FileName.Replace(".m4v", ".mp4").Replace(".mkv", ".mp4");
\r
1338 !Path.GetExtension(DVD_Save.FileName).Equals(".mkv", StringComparison.InvariantCultureIgnoreCase))
\r
1339 DVD_Save.FileName = DVD_Save.FileName.Replace(".mp4", ".mkv").Replace(".m4v", ".mkv");
\r
1345 text_destination.Text = DVD_Save.FileName;
\r
1347 // Quicktime requires .m4v file for chapter markers to work. If checked, change the extension to .m4v (mp4 and m4v are the same thing)
\r
1348 if (Check_ChapterMarkers.Checked && DVD_Save.FilterIndex != 2)
\r
1349 SetExtension(".m4v");
\r
1353 private void text_destination_TextChanged(object sender, EventArgs e)
\r
1355 string path = text_destination.Text;
\r
1356 if (path.EndsWith(".mp4") || path.EndsWith(".m4v"))
\r
1357 drop_format.SelectedIndex = 0;
\r
1358 else if (path.EndsWith(".mkv"))
\r
1359 drop_format.SelectedIndex = 1;
\r
1362 // Output Settings
\r
1363 private void drop_format_SelectedIndexChanged(object sender, EventArgs e)
\r
1365 switch (drop_format.SelectedIndex)
\r
1368 if (Properties.Settings.Default.useM4v || Check_ChapterMarkers.Checked ||
\r
1369 AudioSettings.RequiresM4V() || Subtitles.RequiresM4V())
\r
1370 SetExtension(".m4v");
\r
1372 SetExtension(".mp4");
\r
1375 SetExtension(".mkv");
\r
1379 AudioSettings.SetContainer(drop_format.Text);
\r
1380 Subtitles.SetContainer(drop_format.SelectedIndex);
\r
1382 if (drop_format.Text.Contains("MP4"))
\r
1384 if (drp_videoEncoder.Items.Contains("VP3 (Theora)"))
\r
1386 drp_videoEncoder.Items.Remove("VP3 (Theora)");
\r
1387 drp_videoEncoder.SelectedIndex = 1;
\r
1390 else if (drop_format.Text.Contains("MKV"))
\r
1391 drp_videoEncoder.Items.Add("VP3 (Theora)");
\r
1394 public void SetExtension(string newExtension)
\r
1396 if (newExtension == ".mp4" || newExtension == ".m4v")
\r
1397 if (Properties.Settings.Default.useM4v || Check_ChapterMarkers.Checked || AudioSettings.RequiresM4V() ||
\r
1398 Subtitles.RequiresM4V())
\r
1399 newExtension = ".m4v";
\r
1401 newExtension = ".mp4";
\r
1403 if (Path.HasExtension(newExtension))
\r
1404 text_destination.Text = Path.ChangeExtension(text_destination.Text, newExtension);
\r
1408 private void drp_videoEncoder_SelectedIndexChanged(object sender, EventArgs e)
\r
1410 setContainerOpts();
\r
1412 // Turn off some options which are H.264 only when the user selects a non h.264 encoder
\r
1413 if (drp_videoEncoder.Text.Contains("H.264"))
\r
1415 if (check_2PassEncode.CheckState == CheckState.Checked)
\r
1416 check_turbo.Enabled = true;
\r
1418 tab_advanced.Enabled = true;
\r
1419 if ((drop_format.Text.Contains("MP4")) || (drop_format.Text.Contains("M4V")))
\r
1420 check_iPodAtom.Enabled = true;
\r
1422 check_iPodAtom.Enabled = false;
\r
1426 check_turbo.CheckState = CheckState.Unchecked;
\r
1427 check_turbo.Enabled = false;
\r
1428 tab_advanced.Enabled = false;
\r
1429 x264Panel.X264Query = string.Empty;
\r
1430 check_iPodAtom.Enabled = false;
\r
1431 check_iPodAtom.Checked = false;
\r
1434 // Setup the CQ Slider
\r
1435 switch (drp_videoEncoder.Text)
\r
1437 case "MPEG-4 (FFmpeg)":
\r
1438 if (slider_videoQuality.Value > 31)
\r
1439 slider_videoQuality.Value = 20; // Just reset to 70% QP 10 on encode change.
\r
1440 slider_videoQuality.Minimum = 1;
\r
1441 slider_videoQuality.Maximum = 31;
\r
1443 case "H.264 (x264)":
\r
1444 slider_videoQuality.Minimum = 0;
\r
1445 slider_videoQuality.TickFrequency = 1;
\r
1447 CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
\r
1448 double cqStep = Properties.Settings.Default.x264cqstep;
\r
1449 double multiplier = 1.0 / cqStep;
\r
1450 double value = slider_videoQuality.Value * multiplier;
\r
1452 slider_videoQuality.Maximum = (int)(51 / Properties.Settings.Default.x264cqstep);
\r
1454 if (value < slider_videoQuality.Maximum)
\r
1455 slider_videoQuality.Value = slider_videoQuality.Maximum - (int)value;
\r
1458 case "VP3 (Theora)":
\r
1459 if (slider_videoQuality.Value > 63)
\r
1460 slider_videoQuality.Value = 45; // Just reset to 70% QP 45 on encode change.
\r
1461 slider_videoQuality.Minimum = 0;
\r
1462 slider_videoQuality.Maximum = 63;
\r
1468 /// Set the container format options
\r
1470 public void setContainerOpts()
\r
1472 if ((drop_format.Text.Contains("MP4")) || (drop_format.Text.Contains("M4V")))
\r
1474 check_largeFile.Enabled = true;
\r
1475 check_optimiseMP4.Enabled = true;
\r
1476 check_iPodAtom.Enabled = true;
\r
1480 check_largeFile.Enabled = false;
\r
1481 check_optimiseMP4.Enabled = false;
\r
1482 check_iPodAtom.Enabled = false;
\r
1483 check_largeFile.Checked = false;
\r
1484 check_optimiseMP4.Checked = false;
\r
1485 check_iPodAtom.Checked = false;
\r
1489 private double _cachedCqStep = Properties.Settings.Default.x264cqstep;
\r
1492 /// Update the CQ slider for x264 for a new CQ step. This is set from option
\r
1494 public void setQualityFromSlider()
\r
1496 // Work out the current RF value.
\r
1497 double cqStep = _cachedCqStep;
\r
1498 double rfValue = 51.0 - slider_videoQuality.Value * cqStep;
\r
1500 // Change the maximum value for the slider
\r
1501 slider_videoQuality.Maximum = (int)(51 / Properties.Settings.Default.x264cqstep);
\r
1503 // Reset the CQ slider to RF0
\r
1504 slider_videoQuality.Value = slider_videoQuality.Maximum;
\r
1506 // Reset the CQ slider back to the previous value as close as possible
\r
1507 double cqStepNew = Properties.Settings.Default.x264cqstep;
\r
1508 double rfValueCurrent = 51.0 - slider_videoQuality.Value * cqStepNew;
\r
1509 while (rfValueCurrent < rfValue)
\r
1511 slider_videoQuality.Value--;
\r
1512 rfValueCurrent = 51.0 - slider_videoQuality.Value * cqStepNew;
\r
1515 // Cache the CQ step for the next calculation
\r
1516 _cachedCqStep = Properties.Settings.Default.x264cqstep;
\r
1519 private void slider_videoQuality_Scroll(object sender, EventArgs e)
\r
1521 double cqStep = Properties.Settings.Default.x264cqstep;
\r
1522 switch (drp_videoEncoder.Text)
\r
1524 case "MPEG-4 (FFmpeg)":
\r
1525 lbl_SliderValue.Text = "QP:" + (32 - slider_videoQuality.Value);
\r
1527 case "H.264 (x264)":
\r
1528 double rfValue = 51.0 - slider_videoQuality.Value * cqStep;
\r
1529 rfValue = Math.Round(rfValue, 2);
\r
1530 lbl_SliderValue.Text = "RF:" + rfValue.ToString(new CultureInfo("en-US"));
\r
1532 case "VP3 (Theora)":
\r
1533 lbl_SliderValue.Text = "QP:" + slider_videoQuality.Value;
\r
1538 private void radio_targetFilesize_CheckedChanged(object sender, EventArgs e)
\r
1540 text_bitrate.Enabled = false;
\r
1541 text_filesize.Enabled = true;
\r
1542 slider_videoQuality.Enabled = false;
\r
1544 check_2PassEncode.Enabled = true;
\r
1547 private void radio_avgBitrate_CheckedChanged(object sender, EventArgs e)
\r
1549 text_bitrate.Enabled = true;
\r
1550 text_filesize.Enabled = false;
\r
1551 slider_videoQuality.Enabled = false;
\r
1553 check_2PassEncode.Enabled = true;
\r
1556 private void radio_cq_CheckedChanged(object sender, EventArgs e)
\r
1558 text_bitrate.Enabled = false;
\r
1559 text_filesize.Enabled = false;
\r
1560 slider_videoQuality.Enabled = true;
\r
1562 check_2PassEncode.Enabled = false;
\r
1563 check_2PassEncode.CheckState = CheckState.Unchecked;
\r
1566 private void check_2PassEncode_CheckedChanged(object sender, EventArgs e)
\r
1568 if (check_2PassEncode.CheckState.ToString() == "Checked")
\r
1570 if (drp_videoEncoder.Text.Contains("H.264"))
\r
1571 check_turbo.Enabled = true;
\r
1575 check_turbo.Enabled = false;
\r
1576 check_turbo.CheckState = CheckState.Unchecked;
\r
1580 // Chapter Marker Tab
\r
1581 private void Check_ChapterMarkers_CheckedChanged(object sender, EventArgs e)
\r
1583 if (Check_ChapterMarkers.Checked)
\r
1585 if (drop_format.SelectedIndex != 1)
\r
1586 SetExtension(".m4v");
\r
1587 data_chpt.Enabled = true;
\r
1588 btn_importChapters.Enabled = true;
\r
1592 if (drop_format.SelectedIndex != 1 && !Properties.Settings.Default.useM4v)
\r
1593 SetExtension(".mp4");
\r
1594 data_chpt.Enabled = false;
\r
1595 btn_importChapters.Enabled = false;
\r
1599 private void btn_importChapters_Click(object sender, EventArgs e)
\r
1601 if (File_ChapterImport.ShowDialog() == DialogResult.OK)
\r
1603 string filename = File_ChapterImport.FileName;
\r
1604 DataGridView imported = Main.ImportChapterNames(data_chpt, filename);
\r
1605 if (imported != null)
\r
1606 data_chpt = imported;
\r
1610 private void btn_export_Click(object sender, EventArgs e)
\r
1612 SaveFileDialog saveFileDialog = new SaveFileDialog();
\r
1613 saveFileDialog.Filter = "Csv File|*.csv";
\r
1614 saveFileDialog.DefaultExt = "csv";
\r
1615 if (saveFileDialog.ShowDialog() == DialogResult.OK)
\r
1617 string filename = saveFileDialog.FileName;
\r
1619 Main.SaveChapterMarkersToCsv(this, filename);
\r
1623 private void mnu_resetChapters_Click(object sender, EventArgs e)
\r
1625 data_chpt.Rows.Clear();
\r
1626 DataGridView chapterGridView = Main.ChapterNaming(data_chpt, drop_chapterFinish.Text);
\r
1627 if (chapterGridView != null)
\r
1629 data_chpt = chapterGridView;
\r
1633 // Query Editor Tab
\r
1634 private void btn_generate_Query_Click(object sender, EventArgs e)
\r
1636 rtf_query.Text = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
1639 private void btn_clear_Click(object sender, EventArgs e)
\r
1641 rtf_query.Clear();
\r
1646 // MainWindow Components, Actions and Functions ***********************
\r
1648 #region Source Scan
\r
1650 public bool isScanning { get; set; }
\r
1652 private void StartScan(string filename, int title)
\r
1654 // Setup the GUI components for the scan.
\r
1655 sourcePath = filename;
\r
1657 this.DisableGUI();
\r
1662 isScanning = true;
\r
1663 SourceScan.Scan(sourcePath, title);
\r
1664 SourceScan.ScanStatusChanged += new EventHandler(SourceScan_ScanStatusChanged);
\r
1665 SourceScan.ScanCompleted += new EventHandler(SourceScan_ScanCompleted);
\r
1667 catch (Exception exc)
\r
1669 MessageBox.Show("frmMain.cs - StartScan " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1673 private void SourceScan_ScanStatusChanged(object sender, EventArgs e)
\r
1675 UpdateScanStatusLabel();
\r
1678 private void SourceScan_ScanCompleted(object sender, EventArgs e)
\r
1680 UpdateGuiAfterScan();
\r
1683 private void UpdateScanStatusLabel()
\r
1685 if (InvokeRequired)
\r
1687 BeginInvoke(new UpdateWindowHandler(UpdateScanStatusLabel));
\r
1690 lbl_encode.Text = SourceScan.ScanStatus;
\r
1693 private void UpdateGuiAfterScan()
\r
1695 if (InvokeRequired)
\r
1697 BeginInvoke(new UpdateWindowHandler(UpdateGuiAfterScan));
\r
1703 currentSource = SourceScan.SouceData;
\r
1705 // Setup some GUI components
\r
1706 drp_dvdtitle.Items.Clear();
\r
1707 if (currentSource.Titles.Count != 0)
\r
1708 drp_dvdtitle.Items.AddRange(currentSource.Titles.ToArray());
\r
1710 foreach (Title title in currentSource.Titles)
\r
1712 if (title.MainTitle)
\r
1714 drp_dvdtitle.SelectedItem = title;
\r
1718 if (drp_dvdtitle.SelectedItem == null && drp_dvdtitle.Items.Count > 0)
\r
1720 drp_dvdtitle.SelectedIndex = 0;
\r
1723 // Enable the creation of chapter markers if the file is an image of a dvd.
\r
1725 int.TryParse(drop_chapterStart.Items[0].ToString(), out start);
\r
1726 int.TryParse(drop_chapterFinish.Items[drop_chapterFinish.Items.Count - 1].ToString(), out end);
\r
1728 Check_ChapterMarkers.Enabled = true;
\r
1731 Check_ChapterMarkers.Enabled = false;
\r
1732 Check_ChapterMarkers.Checked = false;
\r
1733 data_chpt.Rows.Clear();
\r
1736 // If no titles were found, Display an error message
\r
1737 if (drp_dvdtitle.Items.Count == 0)
\r
1740 "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
1741 "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
\r
1742 sourcePath = string.Empty;
\r
1744 UpdateSourceLabel();
\r
1746 // Enable the GUI components and enable any disabled components
\r
1749 catch (Exception exc)
\r
1751 MessageBox.Show("frmMain.cs - updateUIafterScan " + exc, "Error", MessageBoxButtons.OK,
\r
1752 MessageBoxIcon.Error);
\r
1757 private void EnableGUI()
\r
1761 if (InvokeRequired)
\r
1762 BeginInvoke(new UpdateWindowHandler(EnableGUI));
\r
1763 lbl_encode.Text = "Scan Completed";
\r
1764 foreach (Control ctrl in Controls)
\r
1765 ctrl.Enabled = true;
\r
1766 btn_start.Enabled = true;
\r
1767 btn_showQueue.Enabled = true;
\r
1768 btn_add2Queue.Enabled = true;
\r
1769 tb_preview.Enabled = true;
\r
1770 btn_source.Enabled = true;
\r
1771 mnu_killCLI.Visible = false;
\r
1773 catch (Exception exc)
\r
1775 MessageBox.Show("frmMain.cs - EnableGUI() " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1779 private void DisableGUI()
\r
1781 foreach (Control ctrl in Controls)
\r
1782 if (!(ctrl is StatusStrip || ctrl is MenuStrip || ctrl is ToolStrip))
\r
1783 ctrl.Enabled = false;
\r
1785 lbl_encode.Visible = true;
\r
1786 lbl_encode.Text = "Scanning ...";
\r
1787 btn_source.Enabled = false;
\r
1788 btn_start.Enabled = false;
\r
1789 btn_showQueue.Enabled = false;
\r
1790 btn_add2Queue.Enabled = false;
\r
1791 tb_preview.Enabled = false;
\r
1792 mnu_killCLI.Visible = true;
\r
1795 private void KillScan()
\r
1797 SourceScan.ScanCompleted -= new EventHandler(SourceScan_ScanCompleted);
\r
1801 SourceScan.Stop();
\r
1803 lbl_encode.Text = "Scan Cancelled!";
\r
1806 private void ResetGUI()
\r
1808 drp_dvdtitle.Items.Clear();
\r
1809 drop_chapterStart.Items.Clear();
\r
1810 drop_chapterFinish.Items.Clear();
\r
1811 lbl_duration.Text = "Select a Title";
\r
1812 PictureSettings.lbl_src_res.Text = "Select a Title";
\r
1813 sourcePath = String.Empty;
\r
1814 text_destination.Text = String.Empty;
\r
1815 selectedTitle = null;
\r
1816 isScanning = false;
\r
1819 private void UpdateSourceLabel()
\r
1821 labelSource.Text = string.IsNullOrEmpty(sourcePath) ? "Select \"Source\" to continue." : this.SourceName;
\r
1823 if (selectedTitle != null)
\r
1824 if (!string.IsNullOrEmpty(selectedTitle.SourceName))
\r
1825 // If it's one of multiple source files, make sure we don't use the folder name
\r
1826 labelSource.Text = Path.GetFileName(selectedTitle.SourceName);
\r
1829 public void RecievingJob(Job job)
\r
1831 string query = job.Query;
\r
1832 StartScan(job.Source, job.Title);
\r
1834 if (query != null)
\r
1836 // Ok, Reset all the H264 widgets before changing the preset
\r
1837 x264Panel.Reset2Defaults();
\r
1839 // Send the query from the file to the Query Parser class
\r
1840 QueryParser presetQuery = QueryParser.Parse(query);
\r
1842 // Now load the preset
\r
1843 PresetLoader.LoadPreset(this, presetQuery, "Load Back From Queue", true);
\r
1845 // The x264 widgets will need updated, so do this now:
\r
1846 x264Panel.X264_StandardizeOptString();
\r
1847 x264Panel.X264_SetCurrentSettingsInPanel();
\r
1849 // Finally, let this window have a copy of the preset settings.
\r
1850 CurrentlySelectedPreset = null;
\r
1851 PictureSettings.SetPresetCropWarningLabel(null);
\r
1857 #region GUI Functions and Actions
\r
1860 /// Set the GUI to it's finished encoding state.
\r
1862 private void SetEncodeFinished()
\r
1866 if (InvokeRequired)
\r
1868 BeginInvoke(new UpdateWindowHandler(SetEncodeFinished));
\r
1872 lbl_encode.Text = "Encoding Finished";
\r
1873 ProgressBarStatus.Visible = false;
\r
1874 btn_start.Text = "Start";
\r
1875 btn_start.ToolTipText = "Start the encoding process";
\r
1876 btn_start.Image = Properties.Resources.Play;
\r
1878 // If the window is minimized, display the notification in a popup.
\r
1879 if (Properties.Settings.Default.trayIconAlerts)
\r
1880 if (FormWindowState.Minimized == this.WindowState)
\r
1882 notifyIcon.BalloonTipText = lbl_encode.Text;
\r
1883 notifyIcon.ShowBalloonTip(500);
\r
1886 catch (Exception exc)
\r
1888 MessageBox.Show(exc.ToString());
\r
1893 /// Set the GUI to it's started encoding state.
\r
1895 private void SetEncodeStarted()
\r
1899 if (InvokeRequired)
\r
1901 BeginInvoke(new UpdateWindowHandler(SetEncodeStarted));
\r
1904 lbl_encode.Visible = true;
\r
1905 ProgressBarStatus.Value = 0;
\r
1906 ProgressBarStatus.Visible = true;
\r
1907 lbl_encode.Text = "Encoding with " + encodeQueue.Count + " encode(s) pending";
\r
1908 btn_start.Text = "Stop";
\r
1909 btn_start.ToolTipText = "Stop the encoding process.";
\r
1910 btn_start.Image = Properties.Resources.stop;
\r
1912 catch (Exception exc)
\r
1914 MessageBox.Show(exc.ToString());
\r
1919 /// Set the DVD Drive selection in the "Source" Menu
\r
1921 private void SetDriveSelectionMenuItem()
\r
1925 if (InvokeRequired)
\r
1927 BeginInvoke(new UpdateWindowHandler(SetDriveSelectionMenuItem));
\r
1931 drives = Main.GetDrives();
\r
1933 List<ToolStripMenuItem> menuItems = new List<ToolStripMenuItem>();
\r
1934 foreach (DriveInformation drive in drives)
\r
1936 ToolStripMenuItem menuItem = new ToolStripMenuItem();
\r
1937 menuItem.Name = drive.ToString();
\r
1938 menuItem.Text = drive.RootDirectory + " (" + drive.VolumeLabel + ")";
\r
1939 menuItem.Image = Resources.disc_small;
\r
1940 menuItem.Click += new EventHandler(mnu_dvd_drive_Click);
\r
1941 menuItems.Add(menuItem);
\r
1944 foreach (ToolStripMenuItem item in menuItems)
\r
1945 btn_source.DropDownItems.Add(item);
\r
1947 catch (Exception exc)
\r
1949 MessageBox.Show("Error in SetDriveSelectionMenuItem" + exc);
\r
1954 /// Access the preset Handler and setup the preset panel.
\r
1956 private void LoadPresetPanel()
\r
1958 if (presetHandler.CheckIfPresetsAreOutOfDate())
\r
1959 if (!Properties.Settings.Default.presetNotification)
\r
1960 MessageBox.Show(splash,
\r
1961 "HandBrake has determined your built-in presets are out of date... These presets will now be updated.",
\r
1962 "Preset Update", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
1964 presetHandler.GetPresetPanel(ref treeView_presets);
\r
1965 treeView_presets.Update();
\r
1969 /// Get the title from the selected item in the title dropdown.
\r
1974 private int getTitle()
\r
1977 if (drp_dvdtitle.SelectedItem != null)
\r
1979 string[] titleInfo = drp_dvdtitle.SelectedItem.ToString().Split(' ');
\r
1980 int.TryParse(titleInfo[0], out title);
\r
1991 /// Handle GUI shortcuts
\r
1993 /// <param name="msg">Message</param>
\r
1994 /// <param name="keyData">Keys</param>
\r
1995 /// <returns>Bool</returns>
\r
1996 protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
\r
1998 if (keyData == (Keys.Control | Keys.S))
\r
2000 btn_start_Click(this, new EventArgs());
\r
2004 if (keyData == (Keys.Control | Keys.A))
\r
2006 btn_add2Queue_Click(this, new EventArgs());
\r
2009 return base.ProcessCmdKey(ref msg, keyData);
\r
2013 /// If the queue is being processed, prompt the user to confirm application close.
\r
2015 /// <param name="e">FormClosingEventArgs</param>
\r
2016 protected override void OnFormClosing(FormClosingEventArgs e)
\r
2018 // If currently encoding, the queue isn't paused, and there are queue items to process, prompt to confirm close.
\r
2019 if (encodeQueue.IsEncoding)
\r
2021 DialogResult result =
\r
2023 "HandBrake has queue items to process. Closing HandBrake will stop the current encoding.\n\nDo you want to close HandBrake?",
\r
2024 "Close HandBrake?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
2026 if (result == DialogResult.No)
\r
2029 // Try to safely close out if we can, or kill the cli if using in-gui status
\r
2030 if (Settings.Default.enocdeStatusInGui)
\r
2031 encodeQueue.Stop();
\r
2033 encodeQueue.SafelyClose();
\r
2036 if (SourceScan.IsScanning)
\r
2038 SourceScan.ScanCompleted -= new EventHandler(SourceScan_ScanCompleted);
\r
2039 SourceScan.Stop();
\r
2041 base.OnFormClosing(e);
\r
2046 #region In-GUI Encode Status (Experimental)
\r
2049 /// Starts a new thread to monitor and process the CLI encode status
\r
2051 private void EncodeMonitorThread()
\r
2055 Parser encode = new Parser(encodeQueue.HbProcess.StandardOutput.BaseStream);
\r
2056 encode.OnEncodeProgress += EncodeOnEncodeProgress;
\r
2057 while (!encode.EndOfStream)
\r
2058 encode.ReadEncodeStatus();
\r
2060 SetEncodeFinished();
\r
2062 catch (Exception exc)
\r
2064 MessageBox.Show(exc.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
2069 /// Displays the Encode status in the GUI
\r
2071 /// <param name="Sender"></param>
\r
2072 /// <param name="CurrentTask"></param>
\r
2073 /// <param name="TaskCount"></param>
\r
2074 /// <param name="PercentComplete"></param>
\r
2075 /// <param name="CurrentFps"></param>
\r
2076 /// <param name="AverageFps"></param>
\r
2077 /// <param name="TimeRemaining"></param>
\r
2078 private void EncodeOnEncodeProgress(object Sender, int CurrentTask, int TaskCount, float PercentComplete, float CurrentFps, float AverageFps, TimeSpan TimeRemaining)
\r
2080 if (this.InvokeRequired)
\r
2083 new EncodeProgressEventHandler(EncodeOnEncodeProgress),
\r
2084 new[] { Sender, CurrentTask, TaskCount, PercentComplete, CurrentFps, AverageFps, TimeRemaining });
\r
2089 "{0:00.00}%, FPS: {1:000.0}, Avg FPS: {2:000.0}, Time Remaining: {3}",
\r
2095 ProgressBarStatus.Value = (int)Math.Round(PercentComplete);
\r
2100 // This is the END of the road ****************************************
\r