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
24 public partial class frmMain : Form
\r
26 // Objects which may be used by one or more other objects *************
\r
27 private Queue encodeQueue = new Queue();
\r
28 private PresetsHandler presetHandler = new PresetsHandler();
\r
30 // Globals: Mainly used for tracking. *********************************
\r
31 public Title selectedTitle;
\r
32 private frmQueue queueWindow;
\r
33 private frmPreview qtpreview;
\r
34 private frmActivityWindow ActivityWindow;
\r
35 private Form splash;
\r
36 public string sourcePath;
\r
37 private ActivityLogMode lastAction;
\r
38 private SourceType selectedSourceType;
\r
39 private string dvdDrivePath;
\r
40 private string dvdDriveLabel;
\r
41 private Preset CurrentlySelectedPreset;
\r
42 private DVD currentSource;
\r
43 private Scan SourceScan = new Scan();
\r
45 // Delegates **********************************************************
\r
46 private delegate void UpdateWindowHandler();
\r
48 // Applicaiton Startup ************************************************
\r
50 #region Application Startup
\r
54 // Load and setup the splash screen in this thread
\r
55 splash = new frmSplashScreen();
\r
57 Label lblStatus = new Label {Size = new Size(150, 20), Location = new Point(182, 102)};
\r
58 splash.Controls.Add(lblStatus);
\r
60 InitializeComponent();
\r
62 // Update the users config file with the CLI version data.
\r
63 lblStatus.Text = "Setting Version Data ...";
\r
64 Application.DoEvents();
\r
65 Main.SetCliVersionData();
\r
67 // Show the form, but leave disabled until preloading is complete then show the main form
\r
68 this.Enabled = false;
\r
70 Application.DoEvents(); // Forces frmMain to draw
\r
72 // Check for new versions, if update checking is enabled
\r
73 if (Properties.Settings.Default.updateStatus)
\r
75 DateTime now = DateTime.Now;
\r
76 DateTime lastCheck = Properties.Settings.Default.lastUpdateCheckDate;
\r
77 TimeSpan elapsed = now.Subtract(lastCheck);
\r
78 if (elapsed.TotalDays > Properties.Settings.Default.daysBetweenUpdateCheck)
\r
80 lblStatus.Text = "Checking for updates ...";
\r
81 Application.DoEvents();
\r
83 Main.BeginCheckForUpdates(new AsyncCallback(UpdateCheckDone), false);
\r
87 // Clear the log files in the background
\r
88 if (Properties.Settings.Default.clearOldLogs)
\r
90 lblStatus.Text = "Clearing Old Log Files ...";
\r
91 Application.DoEvents();
\r
92 Thread clearLog = new Thread(Main.ClearOldLogs);
\r
96 // Setup the GUI components
\r
97 lblStatus.Text = "Setting up the GUI ...";
\r
98 Application.DoEvents();
\r
99 LoadPresetPanel(); // Load the Preset Panel
\r
100 treeView_presets.ExpandAll();
\r
101 lbl_encode.Text = string.Empty;
\r
102 drop_mode.SelectedIndex = 0;
\r
103 queueWindow = new frmQueue(encodeQueue, this); // Prepare the Queue
\r
104 if (!Properties.Settings.Default.QueryEditorTab)
\r
105 tabs_panel.TabPages.RemoveAt(7); // Remove the query editor tab if the user does not want it enabled.
\r
107 // Load the user's default settings or Normal Preset
\r
108 if (Properties.Settings.Default.defaultPreset != string.Empty)
\r
110 if (presetHandler.GetPreset(Properties.Settings.Default.defaultPreset) != null)
\r
112 string query = presetHandler.GetPreset(Properties.Settings.Default.defaultPreset).Query;
\r
113 bool loadPictureSettings =
\r
114 presetHandler.GetPreset(Properties.Settings.Default.defaultPreset).PictureSettings;
\r
118 x264Panel.Reset2Defaults();
\r
120 QueryParser presetQuery = QueryParser.Parse(query);
\r
121 PresetLoader.LoadPreset(this, presetQuery, Properties.Settings.Default.defaultPreset,
\r
122 loadPictureSettings);
\r
124 x264Panel.X264_StandardizeOptString();
\r
125 x264Panel.X264_SetCurrentSettingsInPanel();
\r
129 loadNormalPreset();
\r
132 loadNormalPreset();
\r
134 // Enabled GUI tooltip's if Required
\r
135 if (Properties.Settings.Default.tooltipEnable)
\r
136 ToolTip.Active = true;
\r
138 // Register with Growl (if not using Growl for the encoding completion action, this wont hurt anything)
\r
139 GrowlCommunicator.Register();
\r
141 // Finished Loading
\r
142 lblStatus.Text = "Loading Complete!";
\r
143 Application.DoEvents();
\r
146 this.Enabled = true;
\r
148 // Event Handlers and Queue Recovery
\r
153 private void UpdateCheckDone(IAsyncResult result)
\r
155 if (InvokeRequired)
\r
157 Invoke(new MethodInvoker(() => UpdateCheckDone(result)));
\r
161 UpdateCheckInformation info;
\r
165 info = Main.EndCheckForUpdates(result);
\r
167 if (info.NewVersionAvailable)
\r
169 frmUpdater updateWindow = new frmUpdater(info.BuildInformation);
\r
170 updateWindow.ShowDialog();
\r
173 catch (Exception ex)
\r
175 if ((bool) result.AsyncState)
\r
177 "Unable to check for updates, Please try again later.\n\nDetailed Error Information:\n" + ex,
\r
178 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
182 // Startup Functions
\r
183 private void queueRecovery()
\r
185 if (Main.CheckQueueRecovery())
\r
187 DialogResult result =
\r
189 "HandBrake has detected unfinished items on the queue from the last time the application was launched. Would you like to recover these?",
\r
190 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
192 if (result == DialogResult.Yes)
\r
193 encodeQueue.LoadQueueFromFile("hb_queue_recovery.xml"); // Start Recovery
\r
196 // Remove the Queue recovery file if the user doesn't want to recovery the last queue.
\r
197 string queuePath = Path.Combine(Path.GetTempPath(), "hb_queue_recovery.xml");
\r
198 if (File.Exists(queuePath))
\r
199 File.Delete(queuePath);
\r
208 public string SourceName
\r
212 if (this.selectedSourceType == SourceType.DvdDrive)
\r
214 return this.dvdDriveLabel;
\r
217 if (Path.GetFileNameWithoutExtension(this.sourcePath) != "VIDEO_TS")
\r
218 return Path.GetFileNameWithoutExtension(this.sourcePath);
\r
220 return Path.GetFileNameWithoutExtension(Path.GetDirectoryName(this.sourcePath));
\r
228 // Encoding Events for setting up the GUI
\r
229 private void events()
\r
231 // Handle Widget changes when preset is selected.
\r
232 RegisterPresetEventHandler();
\r
234 // Handle Window Resize
\r
235 if (Properties.Settings.Default.MainWindowMinimize)
\r
236 this.Resize += new EventHandler(frmMain_Resize);
\r
238 // Handle Encode Start / Finish / Pause
\r
240 encodeQueue.QueuePauseRequested += new EventHandler(encodePaused);
\r
241 encodeQueue.EncodeStarted += new EventHandler(encodeStarted);
\r
242 encodeQueue.EncodeEnded += new EventHandler(encodeEnded);
\r
244 // Handle a file being draged onto the GUI.
\r
245 this.DragEnter += new DragEventHandler(frmMain_DragEnter);
\r
246 this.DragDrop += new DragEventHandler(frmMain_DragDrop);
\r
249 // 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
250 private void RegisterPresetEventHandler()
\r
253 drop_format.SelectedIndexChanged += new EventHandler(changePresetLabel);
\r
254 check_largeFile.CheckedChanged += new EventHandler(changePresetLabel);
\r
255 check_iPodAtom.CheckedChanged += new EventHandler(changePresetLabel);
\r
256 check_optimiseMP4.CheckedChanged += new EventHandler(changePresetLabel);
\r
258 // Picture Settings
\r
259 // PictureSettings.PictureSettingsChanged += new EventHandler(changePresetLabel);
\r
262 Filters.FilterSettingsChanged += new EventHandler(changePresetLabel);
\r
265 drp_videoEncoder.SelectedIndexChanged += new EventHandler(changePresetLabel);
\r
266 check_2PassEncode.CheckedChanged += new EventHandler(changePresetLabel);
\r
267 check_turbo.CheckedChanged += new EventHandler(changePresetLabel);
\r
268 text_filesize.TextChanged += new EventHandler(changePresetLabel);
\r
269 text_bitrate.TextChanged += new EventHandler(changePresetLabel);
\r
270 slider_videoQuality.ValueChanged += new EventHandler(changePresetLabel);
\r
273 AudioSettings.AudioListChanged += new EventHandler(changePresetLabel);
\r
276 x264Panel.rtf_x264Query.TextChanged += new EventHandler(changePresetLabel);
\r
279 private void UnRegisterPresetEventHandler()
\r
281 // Output Settings
\r
282 drop_format.SelectedIndexChanged -= new EventHandler(changePresetLabel);
\r
283 check_largeFile.CheckedChanged -= new EventHandler(changePresetLabel);
\r
284 check_iPodAtom.CheckedChanged -= new EventHandler(changePresetLabel);
\r
285 check_optimiseMP4.CheckedChanged -= new EventHandler(changePresetLabel);
\r
287 // Picture Settings
\r
288 // PictureSettings.PictureSettingsChanged -= new EventHandler(changePresetLabel);
\r
291 Filters.FilterSettingsChanged -= new EventHandler(changePresetLabel);
\r
294 drp_videoEncoder.SelectedIndexChanged -= new EventHandler(changePresetLabel);
\r
295 check_2PassEncode.CheckedChanged -= new EventHandler(changePresetLabel);
\r
296 check_turbo.CheckedChanged -= new EventHandler(changePresetLabel);
\r
297 text_filesize.TextChanged -= new EventHandler(changePresetLabel);
\r
298 text_bitrate.TextChanged -= new EventHandler(changePresetLabel);
\r
299 slider_videoQuality.ValueChanged -= new EventHandler(changePresetLabel);
\r
302 AudioSettings.AudioListChanged -= new EventHandler(changePresetLabel);
\r
305 x264Panel.rtf_x264Query.TextChanged -= new EventHandler(changePresetLabel);
\r
308 private void changePresetLabel(object sender, EventArgs e)
\r
310 labelPreset.Text = "Output Settings (Preset: Custom)";
\r
311 CurrentlySelectedPreset = null;
\r
314 private static void frmMain_DragEnter(object sender, DragEventArgs e)
\r
316 if (e.Data.GetDataPresent(DataFormats.FileDrop, false))
\r
317 e.Effect = DragDropEffects.All;
\r
320 private void frmMain_DragDrop(object sender, DragEventArgs e)
\r
322 string[] fileList = e.Data.GetData(DataFormats.FileDrop) as string[];
\r
323 sourcePath = string.Empty;
\r
325 if (fileList != null)
\r
327 if (fileList[0] != string.Empty)
\r
329 this.selectedSourceType = SourceType.VideoFile;
\r
330 StartScan(fileList[0], 0);
\r
333 UpdateSourceLabel();
\r
336 UpdateSourceLabel();
\r
339 private void encodeStarted(object sender, EventArgs e)
\r
341 lastAction = ActivityLogMode.Encode;
\r
342 SetEncodeStarted();
\r
344 // Experimental HBProc Process Monitoring.
\r
345 if (Properties.Settings.Default.enocdeStatusInGui)
\r
347 Thread encodeMon = new Thread(EncodeMonitorThread);
\r
352 private void encodeEnded(object sender, EventArgs e)
\r
354 SetEncodeFinished();
\r
357 private void encodePaused(object sender, EventArgs e)
\r
359 SetEncodeFinished();
\r
364 // User Interface Menus / Tool Strips *********************************
\r
368 private void mnu_killCLI_Click(object sender, EventArgs e)
\r
373 private void mnu_exit_Click(object sender, EventArgs e)
\r
375 Application.Exit();
\r
382 private void mnu_encode_Click(object sender, EventArgs e)
\r
384 queueWindow.Show();
\r
387 private void mnu_encodeLog_Click(object sender, EventArgs e)
\r
389 frmActivityWindow dvdInfoWindow = new frmActivityWindow(lastAction, encodeQueue, SourceScan);
\r
390 dvdInfoWindow.Show();
\r
393 private void mnu_options_Click(object sender, EventArgs e)
\r
395 Form options = new frmOptions(this);
\r
396 options.ShowDialog();
\r
401 #region Presets Menu
\r
403 private void mnu_presetReset_Click(object sender, EventArgs e)
\r
405 presetHandler.UpdateBuiltInPresets();
\r
407 if (treeView_presets.Nodes.Count == 0)
\r
409 "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
410 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
412 MessageBox.Show("Presets have been updated!", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
414 treeView_presets.ExpandAll();
\r
417 private void mnu_delete_preset_Click(object sender, EventArgs e)
\r
419 presetHandler.RemoveBuiltInPresets();
\r
420 LoadPresetPanel(); // Reload the preset panel
\r
423 private void mnu_SelectDefault_Click(object sender, EventArgs e)
\r
425 loadNormalPreset();
\r
428 private void mnu_importMacPreset_Click(object sender, EventArgs e)
\r
433 private void btn_new_preset_Click(object sender, EventArgs e)
\r
435 Form preset = new frmAddPreset(this, QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
437 preset.ShowDialog();
\r
444 private void mnu_user_guide_Click(object sender, EventArgs e)
\r
446 Process.Start("http://trac.handbrake.fr/wiki/HandBrakeGuide");
\r
449 private void mnu_handbrake_home_Click(object sender, EventArgs e)
\r
451 Process.Start("http://handbrake.fr");
\r
454 private void mnu_UpdateCheck_Click(object sender, EventArgs e)
\r
456 lbl_updateCheck.Visible = true;
\r
457 Main.BeginCheckForUpdates(new AsyncCallback(updateCheckDoneMenu), false);
\r
460 private void updateCheckDoneMenu(IAsyncResult result)
\r
462 // Make sure it's running on the calling thread
\r
463 if (InvokeRequired)
\r
465 Invoke(new MethodInvoker(() => updateCheckDoneMenu(result)));
\r
468 UpdateCheckInformation info;
\r
471 // Get the information about the new build, if any, and close the window
\r
472 info = Main.EndCheckForUpdates(result);
\r
474 if (info.NewVersionAvailable && info.BuildInformation != null)
\r
476 frmUpdater updateWindow = new frmUpdater(info.BuildInformation);
\r
477 updateWindow.ShowDialog();
\r
480 MessageBox.Show("There are no new updates at this time.", "Update Check", MessageBoxButtons.OK,
\r
481 MessageBoxIcon.Information);
\r
482 lbl_updateCheck.Visible = false;
\r
485 catch (Exception ex)
\r
487 if ((bool) result.AsyncState)
\r
489 "Unable to check for updates, Please try again later.\n\nDetailed Error Information:\n" + ex,
\r
490 "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
494 private void mnu_about_Click(object sender, EventArgs e)
\r
496 using (frmAbout About = new frmAbout())
\r
498 About.ShowDialog();
\r
506 // Right Click Menu Code
\r
507 private void pmnu_expandAll_Click(object sender, EventArgs e)
\r
509 treeView_presets.ExpandAll();
\r
512 private void pmnu_collapse_Click(object sender, EventArgs e)
\r
514 treeView_presets.CollapseAll();
\r
517 private void pmnu_import_Click(object sender, EventArgs e)
\r
522 private void pmnu_saveChanges_Click(object sender, EventArgs e)
\r
524 DialogResult result =
\r
526 "Do you wish to include picture settings when updating the preset: " +
\r
527 treeView_presets.SelectedNode.Text, "Update Preset", MessageBoxButtons.YesNoCancel,
\r
528 MessageBoxIcon.Question);
\r
529 if (result == DialogResult.Yes)
\r
530 presetHandler.Update(treeView_presets.SelectedNode.Text,
\r
531 QueryGenerator.GenerateTabbedComponentsQuery(this), true);
\r
532 else if (result == DialogResult.No)
\r
533 presetHandler.Update(treeView_presets.SelectedNode.Text,
\r
534 QueryGenerator.GenerateTabbedComponentsQuery(this), false);
\r
537 private void pmnu_delete_click(object sender, EventArgs e)
\r
539 if (treeView_presets.SelectedNode != null)
\r
541 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
542 treeView_presets.Nodes.Remove(treeView_presets.SelectedNode);
\r
544 treeView_presets.Select();
\r
547 private void presets_menu_Opening(object sender, CancelEventArgs e)
\r
549 // Make sure that the save menu is always disabled by default
\r
550 pmnu_saveChanges.Enabled = false;
\r
552 // Now enable the save menu if the selected preset is a user preset
\r
553 if (treeView_presets.SelectedNode != null)
\r
554 if (presetHandler.CheckIfUserPresetExists(treeView_presets.SelectedNode.Text))
\r
555 pmnu_saveChanges.Enabled = true;
\r
557 treeView_presets.Select();
\r
560 // Presets Management
\r
561 private void btn_addPreset_Click(object sender, EventArgs e)
\r
563 Form preset = new frmAddPreset(this, QueryGenerator.GenerateTabbedComponentsQuery(this), presetHandler);
\r
564 preset.ShowDialog();
\r
567 private void btn_removePreset_Click(object sender, EventArgs e)
\r
569 DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected preset?", "Preset",
\r
570 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
571 if (result == DialogResult.Yes)
\r
573 if (treeView_presets.SelectedNode != null)
\r
575 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
576 treeView_presets.Nodes.Remove(treeView_presets.SelectedNode);
\r
579 treeView_presets.Select();
\r
582 private void btn_setDefault_Click(object sender, EventArgs e)
\r
584 if (treeView_presets.SelectedNode != null)
\r
586 DialogResult result = MessageBox.Show("Are you sure you wish to set this preset as the default?",
\r
587 "Preset", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
588 if (result == DialogResult.Yes)
\r
590 Properties.Settings.Default.defaultPreset = treeView_presets.SelectedNode.Text;
\r
591 Properties.Settings.Default.Save();
\r
592 MessageBox.Show("New default preset set.", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
596 MessageBox.Show("Please select a preset first.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
599 private void treeview_presets_mouseUp(object sender, MouseEventArgs e)
\r
601 if (e.Button == MouseButtons.Right)
\r
602 treeView_presets.SelectedNode = treeView_presets.GetNodeAt(e.Location);
\r
603 else if (e.Button == MouseButtons.Left)
\r
605 if (treeView_presets.GetNodeAt(e.Location) != null)
\r
607 if (labelPreset.Text.Contains(treeView_presets.GetNodeAt(e.Location).Text))
\r
612 treeView_presets.Select();
\r
615 private void treeView_presets_AfterSelect(object sender, TreeViewEventArgs e)
\r
620 private void treeView_presets_deleteKey(object sender, KeyEventArgs e)
\r
622 if (e.KeyCode == Keys.Delete)
\r
624 DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected preset?", "Preset",
\r
625 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
626 if (result == DialogResult.Yes)
\r
628 if (treeView_presets.SelectedNode != null)
\r
629 presetHandler.Remove(treeView_presets.SelectedNode.Text);
\r
631 // Remember each nodes expanded status so we can reload it
\r
632 List<bool> nodeStatus = new List<bool>();
\r
633 foreach (TreeNode node in treeView_presets.Nodes)
\r
634 nodeStatus.Add(node.IsExpanded);
\r
636 // Now reload the preset panel
\r
639 // And finally, re-expand any of the nodes if required
\r
641 foreach (TreeNode node in treeView_presets.Nodes)
\r
652 private void selectPreset()
\r
654 if (treeView_presets.SelectedNode != null)
\r
656 // Ok, so, we've selected a preset. Now we want to load it.
\r
657 string presetName = treeView_presets.SelectedNode.Text;
\r
658 Preset preset = presetHandler.GetPreset(presetName);
\r
659 if (preset != null)
\r
661 string query = presetHandler.GetPreset(presetName).Query;
\r
662 bool loadPictureSettings = presetHandler.GetPreset(presetName).PictureSettings;
\r
666 // Ok, Reset all the H264 widgets before changing the preset
\r
667 x264Panel.Reset2Defaults();
\r
669 // Send the query from the file to the Query Parser class
\r
670 QueryParser presetQuery = QueryParser.Parse(query);
\r
672 // Now load the preset
\r
673 PresetLoader.LoadPreset(this, presetQuery, presetName, loadPictureSettings);
\r
675 // The x264 widgets will need updated, so do this now:
\r
676 x264Panel.X264_StandardizeOptString();
\r
677 x264Panel.X264_SetCurrentSettingsInPanel();
\r
679 // Finally, let this window have a copy of the preset settings.
\r
680 CurrentlySelectedPreset = preset;
\r
681 PictureSettings.SetPresetCropWarningLabel(preset);
\r
687 private void loadNormalPreset()
\r
689 foreach (TreeNode treenode in treeView_presets.Nodes)
\r
691 foreach (TreeNode node in treenode.Nodes)
\r
693 if (node.Text.Equals("Normal"))
\r
694 treeView_presets.SelectedNode = treeView_presets.Nodes[treenode.Index].Nodes[0];
\r
699 private void importPreset()
\r
701 if (openPreset.ShowDialog() == DialogResult.OK)
\r
703 QueryParser parsed = PlistPresetHandler.Import(openPreset.FileName);
\r
704 if (presetHandler.CheckIfUserPresetExists(parsed.PresetName + " (Imported)"))
\r
706 DialogResult result =
\r
707 MessageBox.Show("This preset appears to already exist. Would you like to overwrite it?",
\r
708 "Overwrite preset?",
\r
709 MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
\r
710 if (result == DialogResult.Yes)
\r
712 PresetLoader.LoadPreset(this, parsed, parsed.PresetName, parsed.UsesPictureSettings);
\r
713 presetHandler.Update(parsed.PresetName + " (Imported)",
\r
714 QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
715 parsed.UsesPictureSettings);
\r
720 PresetLoader.LoadPreset(this, parsed, parsed.PresetName, parsed.UsesPictureSettings);
\r
721 presetHandler.Add(parsed.PresetName,
\r
722 QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
723 parsed.UsesPictureSettings);
\r
725 if (presetHandler.Add(parsed.PresetName + " (Imported)",
\r
726 QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null),
\r
727 parsed.UsesPictureSettings))
\r
729 TreeNode preset_treeview = new TreeNode(parsed.PresetName + " (Imported)")
\r
731 ForeColor = Color.Black
\r
733 treeView_presets.Nodes.Add(preset_treeview);
\r
743 private void btn_source_Click(object sender, EventArgs e)
\r
745 mnu_dvd_drive.Visible = true;
\r
746 Thread driveInfoThread = new Thread(SetDriveSelectionMenuItem);
\r
747 driveInfoThread.Start();
\r
750 private void btn_start_Click(object sender, EventArgs e)
\r
752 if (btn_start.Text == "Stop")
\r
754 DialogResult result;
\r
755 if (Properties.Settings.Default.enocdeStatusInGui &&
\r
756 !Properties.Settings.Default.showCliForInGuiEncodeStatus)
\r
758 result = MessageBox.Show(
\r
759 "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
760 "Cancel Encode?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
764 result = MessageBox.Show("Are you sure you wish to cancel the encode?", "Cancel Encode?",
\r
765 MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
768 if (result == DialogResult.Yes)
\r
771 encodeQueue.Pause();
\r
773 if (Properties.Settings.Default.enocdeStatusInGui &&
\r
774 !Properties.Settings.Default.showCliForInGuiEncodeStatus)
\r
776 encodeQueue.Stop();
\r
777 if (encodeQueue.HbProcess != null)
\r
778 encodeQueue.HbProcess.WaitForExit();
\r
782 encodeQueue.SafelyClose();
\r
786 SetEncodeFinished();
\r
791 if (encodeQueue.Count != 0 ||
\r
792 (!string.IsNullOrEmpty(sourcePath) && !string.IsNullOrEmpty(text_destination.Text)))
\r
794 string generatedQuery = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
795 string specifiedQuery = rtf_query.Text != string.Empty
\r
797 : QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
798 string query = string.Empty;
\r
800 // Check to make sure the generated query matches the GUI settings
\r
801 if (Properties.Settings.Default.PromptOnUnmatchingQueries && !string.IsNullOrEmpty(specifiedQuery) &&
\r
802 generatedQuery != specifiedQuery)
\r
804 DialogResult result = MessageBox.Show("The query under the \"Query Editor\" tab " +
\r
805 "does not match the current GUI settings.\n\nBecause the manual query takes " +
\r
806 "priority over the GUI, your recently updated settings will not be taken " +
\r
807 "into account when encoding this job." +
\r
808 Environment.NewLine + Environment.NewLine +
\r
809 "Do you want to replace the manual query with the updated GUI-generated query?",
\r
810 "Manual Query does not Match GUI",
\r
811 MessageBoxButtons.YesNoCancel, MessageBoxIcon.Asterisk,
\r
812 MessageBoxDefaultButton.Button3);
\r
816 case DialogResult.Yes:
\r
817 // Replace the manual query with the generated one
\r
818 query = generatedQuery;
\r
819 rtf_query.Text = generatedQuery;
\r
821 case DialogResult.No:
\r
822 // Use the manual query
\r
823 query = specifiedQuery;
\r
825 case DialogResult.Cancel:
\r
826 // Don't start the encode
\r
832 query = specifiedQuery;
\r
835 DialogResult overwrite = DialogResult.Yes;
\r
836 if (text_destination.Text != string.Empty)
\r
837 if (File.Exists(text_destination.Text))
\r
840 "The destination file already exists. Are you sure you want to overwrite it?",
\r
841 "Overwrite File?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
843 if (overwrite == DialogResult.Yes)
\r
845 if (encodeQueue.Count == 0)
\r
846 encodeQueue.Add(query, sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
848 queueWindow.SetQueue();
\r
849 if (encodeQueue.Count > 1)
\r
850 queueWindow.Show(false);
\r
852 SetEncodeStarted(); // Encode is running, so setup the GUI appropriately
\r
853 encodeQueue.Start(); // Start The Queue Encoding Process
\r
854 lastAction = ActivityLogMode.Encode; // Set the last action to encode - Used for activity window.
\r
856 if (ActivityWindow != null)
\r
857 ActivityWindow.SetMode(ActivityLogMode.Encode);
\r
861 else if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
862 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
863 MessageBoxIcon.Warning);
\r
867 private void btn_add2Queue_Click(object sender, EventArgs e)
\r
869 if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
870 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
871 MessageBoxIcon.Warning);
\r
874 string query = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
875 if (rtf_query.Text != string.Empty)
\r
876 query = rtf_query.Text;
\r
878 if (encodeQueue.CheckForDestinationDuplicate(text_destination.Text))
\r
880 DialogResult result =
\r
882 "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
883 "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
\r
884 if (result == DialogResult.Yes)
\r
885 encodeQueue.Add(query, sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
888 encodeQueue.Add(query, sourcePath, text_destination.Text, (rtf_query.Text != string.Empty));
\r
890 lbl_encode.Text = encodeQueue.Count + " encode(s) pending in the queue";
\r
892 queueWindow.Show();
\r
896 private void btn_showQueue_Click(object sender, EventArgs e)
\r
898 queueWindow.Show();
\r
899 queueWindow.Activate();
\r
902 private void tb_preview_Click(object sender, EventArgs e)
\r
904 if (string.IsNullOrEmpty(sourcePath) || string.IsNullOrEmpty(text_destination.Text))
\r
905 MessageBox.Show("No source or destination selected.", "Warning", MessageBoxButtons.OK,
\r
906 MessageBoxIcon.Warning);
\r
909 if (qtpreview == null)
\r
911 qtpreview = new frmPreview(this);
\r
914 else if (qtpreview.IsDisposed)
\r
916 qtpreview = new frmPreview(this);
\r
920 MessageBox.Show(qtpreview, "The preview window is already open!", "Warning", MessageBoxButtons.OK,
\r
921 MessageBoxIcon.Warning);
\r
925 private void btn_ActivityWindow_Click(object sender, EventArgs e)
\r
927 if (ActivityWindow == null || !ActivityWindow.IsHandleCreated)
\r
928 ActivityWindow = new frmActivityWindow(lastAction, encodeQueue, SourceScan);
\r
930 switch (lastAction)
\r
932 case ActivityLogMode.Scan:
\r
933 ActivityWindow.SetMode(ActivityLogMode.Scan);
\r
935 case ActivityLogMode.Encode:
\r
936 ActivityWindow.SetMode(ActivityLogMode.Encode);
\r
939 ActivityWindow.SetMode(ActivityLogMode.Encode);
\r
943 ActivityWindow.Show();
\r
944 ActivityWindow.Activate();
\r
949 #region System Tray Icon
\r
951 private void frmMain_Resize(object sender, EventArgs e)
\r
953 if (FormWindowState.Minimized == this.WindowState)
\r
955 notifyIcon.Visible = true;
\r
958 else if (FormWindowState.Normal == this.WindowState)
\r
959 notifyIcon.Visible = false;
\r
962 private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
\r
964 this.Visible = true;
\r
966 this.WindowState = FormWindowState.Normal;
\r
967 notifyIcon.Visible = false;
\r
970 private void btn_restore_Click(object sender, EventArgs e)
\r
972 this.Visible = true;
\r
974 this.WindowState = FormWindowState.Normal;
\r
975 notifyIcon.Visible = false;
\r
980 #region Tab Control
\r
983 private void btn_dvd_source_Click(object sender, EventArgs e)
\r
985 if (DVD_Open.ShowDialog() == DialogResult.OK)
\r
987 this.selectedSourceType = SourceType.Folder;
\r
988 SelectSource(DVD_Open.SelectedPath);
\r
991 UpdateSourceLabel();
\r
994 private void btn_file_source_Click(object sender, EventArgs e)
\r
996 if (ISO_Open.ShowDialog() == DialogResult.OK)
\r
998 this.selectedSourceType = SourceType.VideoFile;
\r
999 SelectSource(ISO_Open.FileName);
\r
1002 UpdateSourceLabel();
\r
1005 private void mnu_dvd_drive_Click(object sender, EventArgs e)
\r
1007 if (this.dvdDrivePath == null) return;
\r
1008 this.selectedSourceType = SourceType.DvdDrive;
\r
1009 SelectSource(this.dvdDrivePath);
\r
1012 private void SelectSource(string file)
\r
1014 Check_ChapterMarkers.Enabled = true;
\r
1015 lastAction = ActivityLogMode.Scan;
\r
1016 sourcePath = string.Empty;
\r
1018 if (file == string.Empty) // Must have a file or path
\r
1020 UpdateSourceLabel();
\r
1024 sourcePath = Path.GetFileName(file);
\r
1025 StartScan(file, 0);
\r
1028 private void drp_dvdtitle_Click(object sender, EventArgs e)
\r
1030 if ((drp_dvdtitle.Items.Count == 1) && (drp_dvdtitle.Items[0].ToString() == "Automatic"))
\r
1032 "There are no titles to select. Please load a source file by clicking the 'Source' button above before trying to select a title.",
\r
1033 "Alert", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
\r
1036 private void drp_dvdtitle_SelectedIndexChanged(object sender, EventArgs e)
\r
1038 UnRegisterPresetEventHandler();
\r
1039 drop_mode.SelectedIndex = 0;
\r
1041 drop_chapterStart.Items.Clear();
\r
1042 drop_chapterFinish.Items.Clear();
\r
1044 // If the dropdown is set to automatic nothing else needs to be done.
\r
1045 // Otheriwse if its not, title data has to be loased from parsing.
\r
1046 if (drp_dvdtitle.Text != "Automatic")
\r
1048 selectedTitle = drp_dvdtitle.SelectedItem as Title;
\r
1049 lbl_duration.Text = selectedTitle.Duration.ToString();
\r
1050 PictureSettings.CurrentlySelectedPreset = CurrentlySelectedPreset;
\r
1051 PictureSettings.Source = selectedTitle; // Setup Picture Settings Tab Control
\r
1053 // Populate the Angles dropdown
\r
1054 drop_angle.Items.Clear();
\r
1055 if (!Properties.Settings.Default.noDvdNav)
\r
1057 drop_angle.Visible = true;
\r
1058 lbl_angle.Visible = true;
\r
1059 drop_angle.Items.AddRange(selectedTitle.Angles.ToArray());
\r
1060 if (drop_angle.Items.Count != 0)
\r
1061 drop_angle.SelectedIndex = 0;
\r
1065 drop_angle.Visible = false;
\r
1066 lbl_angle.Visible = false;
\r
1069 // Populate the Start chapter Dropdown
\r
1070 drop_chapterStart.Items.Clear();
\r
1071 drop_chapterStart.Items.AddRange(selectedTitle.Chapters.ToArray());
\r
1072 if (drop_chapterStart.Items.Count > 0)
\r
1073 drop_chapterStart.Text = drop_chapterStart.Items[0].ToString();
\r
1075 // Populate the Final Chapter Dropdown
\r
1076 drop_chapterFinish.Items.Clear();
\r
1077 drop_chapterFinish.Items.AddRange(selectedTitle.Chapters.ToArray());
\r
1078 if (drop_chapterFinish.Items.Count > 0)
\r
1079 drop_chapterFinish.Text = drop_chapterFinish.Items[drop_chapterFinish.Items.Count - 1].ToString();
\r
1081 // Populate the Audio Channels Dropdown
\r
1082 AudioSettings.SetTrackList(selectedTitle);
\r
1084 // Populate the Subtitles dropdown
\r
1085 Subtitles.SetSubtitleTrackAuto(selectedTitle.Subtitles.ToArray());
\r
1087 // Update the source label if we have multiple streams
\r
1088 if (selectedTitle != null)
\r
1089 if (!string.IsNullOrEmpty(selectedTitle.SourceName))
\r
1090 labelSource.Text = labelSource.Text = Path.GetFileName(selectedTitle.SourceName);
\r
1092 // Run the AutoName & ChapterNaming functions
\r
1093 if (Properties.Settings.Default.autoNaming)
\r
1095 string autoPath = Main.AutoName(this);
\r
1096 if (autoPath != null)
\r
1097 text_destination.Text = autoPath;
\r
1100 "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
1101 "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
\r
1104 data_chpt.Rows.Clear();
\r
1105 if (selectedTitle.Chapters.Count != 1)
\r
1107 DataGridView chapterGridView = Main.ChapterNaming(data_chpt, drop_chapterFinish.Text);
\r
1108 if (chapterGridView != null)
\r
1109 data_chpt = chapterGridView;
\r
1113 Check_ChapterMarkers.Checked = false;
\r
1114 Check_ChapterMarkers.Enabled = false;
\r
1117 // Hack to force the redraw of the scrollbars which don't resize properly when the control is disabled.
\r
1118 data_chpt.Columns[0].Width = 166;
\r
1119 data_chpt.Columns[0].Width = 165;
\r
1121 RegisterPresetEventHandler();
\r
1124 private void chapersChanged(object sender, EventArgs e)
\r
1126 if (drop_mode.SelectedIndex != 0) // Function is not used if we are not in chapters mode.
\r
1129 Control ctl = (Control) sender;
\r
1130 int chapterStart, chapterEnd;
\r
1131 int.TryParse(drop_chapterStart.Text, out chapterStart);
\r
1132 int.TryParse(drop_chapterFinish.Text, out chapterEnd);
\r
1136 case "drop_chapterStart":
\r
1137 if (drop_chapterFinish.SelectedIndex == -1 && drop_chapterFinish.Items.Count != 0)
\r
1138 drop_chapterFinish.SelectedIndex = drop_chapterFinish.Items.Count - 1;
\r
1140 if (chapterEnd != 0)
\r
1141 if (chapterStart > chapterEnd)
\r
1142 drop_chapterFinish.Text = chapterStart.ToString();
\r
1144 case "drop_chapterFinish":
\r
1145 if (drop_chapterStart.Items.Count >= 1 && drop_chapterStart.SelectedIndex == -1)
\r
1146 drop_chapterStart.SelectedIndex = 0;
\r
1148 if (chapterStart != 0)
\r
1149 if (chapterEnd < chapterStart)
\r
1150 drop_chapterFinish.Text = chapterStart.ToString();
\r
1152 // Add more rows to the Chapter menu if needed.
\r
1153 if (Check_ChapterMarkers.Checked)
\r
1155 int i = data_chpt.Rows.Count, finish = 0;
\r
1156 int.TryParse(drop_chapterFinish.Text, out finish);
\r
1158 while (i < finish)
\r
1160 int n = data_chpt.Rows.Add();
\r
1161 data_chpt.Rows[n].Cells[0].Value = (i + 1);
\r
1162 data_chpt.Rows[n].Cells[1].Value = "Chapter " + (i + 1);
\r
1163 data_chpt.Rows[n].Cells[0].ValueType = typeof (int);
\r
1164 data_chpt.Rows[n].Cells[1].ValueType = typeof (string);
\r
1171 // Update the Duration
\r
1172 lbl_duration.Text =
\r
1173 Main.CalculateDuration(drop_chapterStart.SelectedIndex, drop_chapterFinish.SelectedIndex, selectedTitle)
\r
1176 // Run the Autonaming function
\r
1177 if (Properties.Settings.Default.autoNaming)
\r
1178 text_destination.Text = Main.AutoName(this);
\r
1180 // Disable chapter markers if only 1 chapter is selected.
\r
1181 if (chapterStart == chapterEnd)
\r
1183 Check_ChapterMarkers.Enabled = false;
\r
1184 btn_importChapters.Enabled = false;
\r
1185 data_chpt.Enabled = false;
\r
1189 Check_ChapterMarkers.Enabled = true;
\r
1190 if (Check_ChapterMarkers.Checked)
\r
1192 btn_importChapters.Enabled = true;
\r
1193 data_chpt.Enabled = true;
\r
1198 private void SecondsOrFramesChanged(object sender, EventArgs e)
\r
1201 int.TryParse(drop_chapterStart.Text, out start);
\r
1202 int.TryParse(drop_chapterFinish.Text, out end);
\r
1203 double duration = end - start;
\r
1205 switch (drop_mode.SelectedIndex)
\r
1208 lbl_duration.Text = TimeSpan.FromSeconds(duration).ToString();
\r
1211 if (selectedTitle != null)
\r
1213 duration = duration/selectedTitle.Fps;
\r
1214 lbl_duration.Text = TimeSpan.FromSeconds(duration).ToString();
\r
1217 lbl_duration.Text = "--:--:--";
\r
1223 private void drop_mode_SelectedIndexChanged(object sender, EventArgs e)
\r
1226 this.drop_chapterFinish.TextChanged -= new EventHandler(this.SecondsOrFramesChanged);
\r
1227 this.drop_chapterStart.TextChanged -= new EventHandler(this.SecondsOrFramesChanged);
\r
1230 switch (drop_mode.SelectedIndex)
\r
1233 drop_chapterStart.DropDownStyle = ComboBoxStyle.DropDownList;
\r
1234 drop_chapterFinish.DropDownStyle = ComboBoxStyle.DropDownList;
\r
1235 if (drop_chapterStart.Items.Count != 0)
\r
1237 drop_chapterStart.SelectedIndex = 0;
\r
1238 drop_chapterFinish.SelectedIndex = drop_chapterFinish.Items.Count - 1;
\r
1241 lbl_duration.Text = "--:--:--";
\r
1244 this.drop_chapterStart.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1245 this.drop_chapterFinish.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1246 drop_chapterStart.DropDownStyle = ComboBoxStyle.Simple;
\r
1247 drop_chapterFinish.DropDownStyle = ComboBoxStyle.Simple;
\r
1248 if (selectedTitle != null)
\r
1250 drop_chapterStart.Text = "0";
\r
1251 drop_chapterFinish.Text = selectedTitle.Duration.TotalSeconds.ToString();
\r
1255 this.drop_chapterStart.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1256 this.drop_chapterFinish.TextChanged += new EventHandler(this.SecondsOrFramesChanged);
\r
1257 drop_chapterStart.DropDownStyle = ComboBoxStyle.Simple;
\r
1258 drop_chapterFinish.DropDownStyle = ComboBoxStyle.Simple;
\r
1259 if (selectedTitle != null)
\r
1261 drop_chapterStart.Text = "0";
\r
1262 drop_chapterFinish.Text = (selectedTitle.Fps*selectedTitle.Duration.TotalSeconds).ToString();
\r
1269 private void btn_destBrowse_Click(object sender, EventArgs e)
\r
1271 // This removes the file extension from the filename box on the save file dialog.
\r
1272 // It's daft but some users don't realise that typing an extension overrides the dropdown extension selected.
\r
1273 DVD_Save.FileName = Path.GetFileNameWithoutExtension(text_destination.Text);
\r
1275 if (Path.IsPathRooted(text_destination.Text))
\r
1276 DVD_Save.InitialDirectory = Path.GetDirectoryName(text_destination.Text);
\r
1278 // Show the dialog and set the main form file path
\r
1279 if (drop_format.SelectedIndex.Equals(0))
\r
1280 DVD_Save.FilterIndex = 1;
\r
1281 else if (drop_format.SelectedIndex.Equals(1))
\r
1282 DVD_Save.FilterIndex = 2;
\r
1284 if (DVD_Save.ShowDialog() == DialogResult.OK)
\r
1286 // Add a file extension manually, as FileDialog.AddExtension has issues with dots in filenames
\r
1287 switch (DVD_Save.FilterIndex)
\r
1291 !Path.GetExtension(DVD_Save.FileName).Equals(".mp4",
\r
1292 StringComparison.InvariantCultureIgnoreCase))
\r
1293 if (Properties.Settings.Default.useM4v)
\r
1294 DVD_Save.FileName = DVD_Save.FileName.Replace(".mp4", ".m4v").Replace(".mkv", ".m4v");
\r
1296 DVD_Save.FileName = DVD_Save.FileName.Replace(".m4v", ".mp4").Replace(".mkv", ".mp4");
\r
1300 !Path.GetExtension(DVD_Save.FileName).Equals(".mkv",
\r
1301 StringComparison.InvariantCultureIgnoreCase))
\r
1302 DVD_Save.FileName = DVD_Save.FileName.Replace(".mp4", ".mkv").Replace(".m4v", ".mkv");
\r
1308 text_destination.Text = DVD_Save.FileName;
\r
1310 // Quicktime requires .m4v file for chapter markers to work. If checked, change the extension to .m4v (mp4 and m4v are the same thing)
\r
1311 if (Check_ChapterMarkers.Checked && DVD_Save.FilterIndex != 2)
\r
1312 SetExtension(".m4v");
\r
1316 private void text_destination_TextChanged(object sender, EventArgs e)
\r
1318 string path = text_destination.Text;
\r
1319 if (path.EndsWith(".mp4") || path.EndsWith(".m4v"))
\r
1320 drop_format.SelectedIndex = 0;
\r
1321 else if (path.EndsWith(".mkv"))
\r
1322 drop_format.SelectedIndex = 1;
\r
1325 // Output Settings
\r
1326 private void drop_format_SelectedIndexChanged(object sender, EventArgs e)
\r
1328 switch (drop_format.SelectedIndex)
\r
1331 if (Properties.Settings.Default.useM4v || Check_ChapterMarkers.Checked ||
\r
1332 AudioSettings.RequiresM4V() || Subtitles.RequiresM4V())
\r
1333 SetExtension(".m4v");
\r
1335 SetExtension(".mp4");
\r
1338 SetExtension(".mkv");
\r
1342 AudioSettings.SetContainer(drop_format.Text);
\r
1343 Subtitles.SetContainer(drop_format.SelectedIndex);
\r
1345 if (drop_format.Text.Contains("MP4"))
\r
1347 if (drp_videoEncoder.Items.Contains("VP3 (Theora)"))
\r
1349 drp_videoEncoder.Items.Remove("VP3 (Theora)");
\r
1350 drp_videoEncoder.SelectedIndex = 1;
\r
1353 else if (drop_format.Text.Contains("MKV"))
\r
1354 drp_videoEncoder.Items.Add("VP3 (Theora)");
\r
1357 public void SetExtension(string newExtension)
\r
1359 if (newExtension == ".mp4" || newExtension == ".m4v")
\r
1360 if (Properties.Settings.Default.useM4v || Check_ChapterMarkers.Checked || AudioSettings.RequiresM4V() ||
\r
1361 Subtitles.RequiresM4V())
\r
1362 newExtension = ".m4v";
\r
1364 newExtension = ".mp4";
\r
1366 if (Path.HasExtension(newExtension))
\r
1367 text_destination.Text = Path.ChangeExtension(text_destination.Text, newExtension);
\r
1371 private void drp_videoEncoder_SelectedIndexChanged(object sender, EventArgs e)
\r
1373 setContainerOpts();
\r
1375 // Turn off some options which are H.264 only when the user selects a non h.264 encoder
\r
1376 if (drp_videoEncoder.Text.Contains("H.264"))
\r
1378 if (check_2PassEncode.CheckState == CheckState.Checked)
\r
1379 check_turbo.Enabled = true;
\r
1381 tab_advanced.Enabled = true;
\r
1382 if ((drop_format.Text.Contains("MP4")) || (drop_format.Text.Contains("M4V")))
\r
1383 check_iPodAtom.Enabled = true;
\r
1385 check_iPodAtom.Enabled = false;
\r
1389 check_turbo.CheckState = CheckState.Unchecked;
\r
1390 check_turbo.Enabled = false;
\r
1391 tab_advanced.Enabled = false;
\r
1392 x264Panel.X264Query = string.Empty;
\r
1393 check_iPodAtom.Enabled = false;
\r
1394 check_iPodAtom.Checked = false;
\r
1397 // Setup the CQ Slider
\r
1398 switch (drp_videoEncoder.Text)
\r
1400 case "MPEG-4 (FFmpeg)":
\r
1401 if (slider_videoQuality.Value > 31)
\r
1402 slider_videoQuality.Value = 20; // Just reset to 70% QP 10 on encode change.
\r
1403 slider_videoQuality.Minimum = 1;
\r
1404 slider_videoQuality.Maximum = 31;
\r
1406 case "H.264 (x264)":
\r
1407 slider_videoQuality.Minimum = 0;
\r
1408 slider_videoQuality.TickFrequency = 1;
\r
1410 CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
\r
1411 double cqStep = Properties.Settings.Default.x264cqstep;
\r
1412 double multiplier = 1.0/cqStep;
\r
1413 double value = slider_videoQuality.Value*multiplier;
\r
1415 switch (Properties.Settings.Default.x264cqstep.ToString(culture))
\r
1418 slider_videoQuality.Maximum = 255;
\r
1421 slider_videoQuality.Maximum = 204;
\r
1424 slider_videoQuality.Maximum = 102;
\r
1427 slider_videoQuality.Maximum = 51;
\r
1430 slider_videoQuality.Maximum = 51;
\r
1433 if (value < slider_videoQuality.Maximum)
\r
1434 slider_videoQuality.Value = slider_videoQuality.Maximum - (int) value;
\r
1437 case "VP3 (Theora)":
\r
1438 if (slider_videoQuality.Value > 63)
\r
1439 slider_videoQuality.Value = 45; // Just reset to 70% QP 45 on encode change.
\r
1440 slider_videoQuality.Minimum = 0;
\r
1441 slider_videoQuality.Maximum = 63;
\r
1447 /// Set the container format options
\r
1449 public void setContainerOpts()
\r
1451 if ((drop_format.Text.Contains("MP4")) || (drop_format.Text.Contains("M4V")))
\r
1453 check_largeFile.Enabled = true;
\r
1454 check_optimiseMP4.Enabled = true;
\r
1455 check_iPodAtom.Enabled = true;
\r
1459 check_largeFile.Enabled = false;
\r
1460 check_optimiseMP4.Enabled = false;
\r
1461 check_iPodAtom.Enabled = false;
\r
1462 check_largeFile.Checked = false;
\r
1463 check_optimiseMP4.Checked = false;
\r
1464 check_iPodAtom.Checked = false;
\r
1468 private double _cachedCqStep = Properties.Settings.Default.x264cqstep;
\r
1471 /// Update the CQ slider for x264 for a new CQ step. This is set from option
\r
1473 public void setQualityFromSlider()
\r
1475 // Work out the current RF value.
\r
1476 double cqStep = _cachedCqStep;
\r
1477 double rfValue = 51.0 - slider_videoQuality.Value*cqStep;
\r
1479 // Change the maximum value for the slider
\r
1480 switch (Properties.Settings.Default.x264cqstep.ToString(new CultureInfo("en-US")))
\r
1483 slider_videoQuality.Maximum = 255;
\r
1486 slider_videoQuality.Maximum = 204;
\r
1489 slider_videoQuality.Maximum = 102;
\r
1492 slider_videoQuality.Maximum = 51;
\r
1495 slider_videoQuality.Maximum = 51;
\r
1499 // Reset the CQ slider to RF0
\r
1500 slider_videoQuality.Value = slider_videoQuality.Maximum;
\r
1502 // Reset the CQ slider back to the previous value as close as possible
\r
1503 double cqStepNew = Properties.Settings.Default.x264cqstep;
\r
1504 double rfValueCurrent = 51.0 - slider_videoQuality.Value*cqStepNew;
\r
1505 while (rfValueCurrent < rfValue)
\r
1507 slider_videoQuality.Value--;
\r
1508 rfValueCurrent = 51.0 - slider_videoQuality.Value*cqStepNew;
\r
1511 // Cache the CQ step for the next calculation
\r
1512 _cachedCqStep = Properties.Settings.Default.x264cqstep;
\r
1515 private void slider_videoQuality_Scroll(object sender, EventArgs e)
\r
1517 double cqStep = Properties.Settings.Default.x264cqstep;
\r
1518 switch (drp_videoEncoder.Text)
\r
1520 case "MPEG-4 (FFmpeg)":
\r
1521 lbl_SliderValue.Text = "QP:" + (32 - slider_videoQuality.Value);
\r
1523 case "H.264 (x264)":
\r
1524 double rfValue = 51.0 - slider_videoQuality.Value*cqStep;
\r
1525 rfValue = Math.Round(rfValue, 2);
\r
1526 lbl_SliderValue.Text = "RF:" + rfValue.ToString(new CultureInfo("en-US"));
\r
1528 case "VP3 (Theora)":
\r
1529 lbl_SliderValue.Text = "QP:" + slider_videoQuality.Value;
\r
1534 private void radio_targetFilesize_CheckedChanged(object sender, EventArgs e)
\r
1536 text_bitrate.Enabled = false;
\r
1537 text_filesize.Enabled = true;
\r
1538 slider_videoQuality.Enabled = false;
\r
1540 check_2PassEncode.Enabled = true;
\r
1543 private void radio_avgBitrate_CheckedChanged(object sender, EventArgs e)
\r
1545 text_bitrate.Enabled = true;
\r
1546 text_filesize.Enabled = false;
\r
1547 slider_videoQuality.Enabled = false;
\r
1549 check_2PassEncode.Enabled = true;
\r
1552 private void radio_cq_CheckedChanged(object sender, EventArgs e)
\r
1554 text_bitrate.Enabled = false;
\r
1555 text_filesize.Enabled = false;
\r
1556 slider_videoQuality.Enabled = true;
\r
1558 check_2PassEncode.Enabled = false;
\r
1559 check_2PassEncode.CheckState = CheckState.Unchecked;
\r
1562 private void check_2PassEncode_CheckedChanged(object sender, EventArgs e)
\r
1564 if (check_2PassEncode.CheckState.ToString() == "Checked")
\r
1566 if (drp_videoEncoder.Text.Contains("H.264"))
\r
1567 check_turbo.Enabled = true;
\r
1571 check_turbo.Enabled = false;
\r
1572 check_turbo.CheckState = CheckState.Unchecked;
\r
1576 // Chapter Marker Tab
\r
1577 private void Check_ChapterMarkers_CheckedChanged(object sender, EventArgs e)
\r
1579 if (Check_ChapterMarkers.Checked)
\r
1581 if (drop_format.SelectedIndex != 1)
\r
1582 SetExtension(".m4v");
\r
1583 data_chpt.Enabled = true;
\r
1584 btn_importChapters.Enabled = true;
\r
1588 if (drop_format.SelectedIndex != 1 && !Properties.Settings.Default.useM4v)
\r
1589 SetExtension(".mp4");
\r
1590 data_chpt.Enabled = false;
\r
1591 btn_importChapters.Enabled = false;
\r
1595 private void btn_importChapters_Click(object sender, EventArgs e)
\r
1597 if (File_ChapterImport.ShowDialog() == DialogResult.OK)
\r
1599 string filename = File_ChapterImport.FileName;
\r
1600 DataGridView imported = Main.ImportChapterNames(data_chpt, filename);
\r
1601 if (imported != null)
\r
1602 data_chpt = imported;
\r
1606 private void mnu_resetChapters_Click(object sender, EventArgs e)
\r
1608 data_chpt.Rows.Clear();
\r
1609 DataGridView chapterGridView = Main.ChapterNaming(data_chpt, drop_chapterFinish.Text);
\r
1610 if (chapterGridView != null)
\r
1612 data_chpt = chapterGridView;
\r
1616 // Query Editor Tab
\r
1617 private void btn_generate_Query_Click(object sender, EventArgs e)
\r
1619 rtf_query.Text = QueryGenerator.GenerateCliQuery(this, drop_mode.SelectedIndex, 0, null);
\r
1622 private void btn_clear_Click(object sender, EventArgs e)
\r
1624 rtf_query.Clear();
\r
1629 // MainWindow Components, Actions and Functions ***********************
\r
1631 #region Source Scan
\r
1633 public bool isScanning { get; set; }
\r
1635 private void StartScan(string filename, int title)
\r
1637 // Setup the GUI components for the scan.
\r
1638 sourcePath = filename;
\r
1639 foreach (Control ctrl in Controls)
\r
1640 if (!(ctrl is StatusStrip || ctrl is MenuStrip || ctrl is ToolStrip))
\r
1641 ctrl.Enabled = false;
\r
1643 lbl_encode.Visible = true;
\r
1644 lbl_encode.Text = "Scanning ...";
\r
1645 btn_source.Enabled = false;
\r
1646 btn_start.Enabled = false;
\r
1647 btn_showQueue.Enabled = false;
\r
1648 btn_add2Queue.Enabled = false;
\r
1649 tb_preview.Enabled = false;
\r
1650 mnu_killCLI.Visible = true;
\r
1652 if (ActivityWindow != null)
\r
1653 ActivityWindow.SetMode(ActivityLogMode.Scan);
\r
1658 isScanning = true;
\r
1659 SourceScan = new Scan();
\r
1660 SourceScan.ScanSource(sourcePath, title);
\r
1661 SourceScan.ScanStatusChanged += new EventHandler(SourceScan_ScanStatusChanged);
\r
1662 SourceScan.ScanCompleted += new EventHandler(SourceScan_ScanCompleted);
\r
1664 catch (Exception exc)
\r
1666 MessageBox.Show("frmMain.cs - StartScan " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1670 private void SourceScan_ScanStatusChanged(object sender, EventArgs e)
\r
1672 UpdateScanStatusLabel();
\r
1675 private void SourceScan_ScanCompleted(object sender, EventArgs e)
\r
1677 UpdateGuiAfterScan();
\r
1680 private void UpdateScanStatusLabel()
\r
1682 if (InvokeRequired)
\r
1684 BeginInvoke(new UpdateWindowHandler(UpdateScanStatusLabel));
\r
1687 lbl_encode.Text = SourceScan.ScanStatus();
\r
1690 private void UpdateGuiAfterScan()
\r
1692 if (InvokeRequired)
\r
1694 BeginInvoke(new UpdateWindowHandler(UpdateGuiAfterScan));
\r
1700 currentSource = SourceScan.SouceData();
\r
1702 // Setup some GUI components
\r
1703 drp_dvdtitle.Items.Clear();
\r
1704 if (currentSource.Titles.Count != 0)
\r
1705 drp_dvdtitle.Items.AddRange(currentSource.Titles.ToArray());
\r
1707 // Now select the longest title
\r
1708 if (currentSource.Titles.Count != 0)
\r
1709 drp_dvdtitle.SelectedItem = Main.SelectLongestTitle(currentSource);
\r
1711 // Enable the creation of chapter markers if the file is an image of a dvd.
\r
1712 if (sourcePath.ToLower().Contains(".iso") || sourcePath.Contains("VIDEO_TS") ||
\r
1713 Directory.Exists(Path.Combine(sourcePath, "VIDEO_TS")))
\r
1714 Check_ChapterMarkers.Enabled = true;
\r
1717 Check_ChapterMarkers.Enabled = false;
\r
1718 Check_ChapterMarkers.Checked = false;
\r
1719 data_chpt.Rows.Clear();
\r
1722 // If no titles were found, Display an error message
\r
1723 if (drp_dvdtitle.Items.Count == 0)
\r
1726 "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
1727 "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
\r
1728 sourcePath = string.Empty;
\r
1730 UpdateSourceLabel();
\r
1732 // Enable the GUI components and enable any disabled components
\r
1735 catch (Exception exc)
\r
1737 MessageBox.Show("frmMain.cs - updateUIafterScan " + exc, "Error", MessageBoxButtons.OK,
\r
1738 MessageBoxIcon.Error);
\r
1743 private void EnableGUI()
\r
1747 if (InvokeRequired)
\r
1748 BeginInvoke(new UpdateWindowHandler(EnableGUI));
\r
1749 lbl_encode.Text = "Scan Completed";
\r
1750 foreach (Control ctrl in Controls)
\r
1751 ctrl.Enabled = true;
\r
1752 btn_start.Enabled = true;
\r
1753 btn_showQueue.Enabled = true;
\r
1754 btn_add2Queue.Enabled = true;
\r
1755 tb_preview.Enabled = true;
\r
1756 btn_source.Enabled = true;
\r
1757 mnu_killCLI.Visible = false;
\r
1759 catch (Exception exc)
\r
1761 MessageBox.Show("frmMain.cs - EnableGUI() " + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1765 private void KillScan()
\r
1769 SourceScan.ScanCompleted -= new EventHandler(SourceScan_ScanCompleted);
\r
1773 if (SourceScan.ScanProcess() != null)
\r
1774 SourceScan.ScanProcess().Kill();
\r
1776 lbl_encode.Text = "Scan Cancelled!";
\r
1778 catch (Exception ex)
\r
1781 "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
1782 ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
1786 private void ResetGUI()
\r
1788 drp_dvdtitle.Items.Clear();
\r
1789 drop_chapterStart.Items.Clear();
\r
1790 drop_chapterFinish.Items.Clear();
\r
1791 lbl_duration.Text = "Select a Title";
\r
1792 PictureSettings.lbl_src_res.Text = "Select a Title";
\r
1793 sourcePath = String.Empty;
\r
1794 text_destination.Text = String.Empty;
\r
1795 selectedTitle = null;
\r
1796 isScanning = false;
\r
1799 private void UpdateSourceLabel()
\r
1801 labelSource.Text = string.IsNullOrEmpty(sourcePath) ? "Select \"Source\" to continue." : this.SourceName;
\r
1803 if (selectedTitle != null)
\r
1804 if (!string.IsNullOrEmpty(selectedTitle.SourceName))
\r
1805 // If it's one of multiple source files, make sure we don't use the folder name
\r
1806 labelSource.Text = Path.GetFileName(selectedTitle.SourceName);
\r
1809 public void RecievingJob(Job job)
\r
1811 string query = job.Query;
\r
1812 StartScan(job.Source, 0);
\r
1815 if (query != null)
\r
1817 // Ok, Reset all the H264 widgets before changing the preset
\r
1818 x264Panel.Reset2Defaults();
\r
1820 // Send the query from the file to the Query Parser class
\r
1821 QueryParser presetQuery = QueryParser.Parse(query);
\r
1823 // Now load the preset
\r
1824 PresetLoader.LoadPreset(this, presetQuery, "Load Back From Queue", true);
\r
1826 // The x264 widgets will need updated, so do this now:
\r
1827 x264Panel.X264_StandardizeOptString();
\r
1828 x264Panel.X264_SetCurrentSettingsInPanel();
\r
1830 // Finally, let this window have a copy of the preset settings.
\r
1831 CurrentlySelectedPreset = null;
\r
1832 PictureSettings.SetPresetCropWarningLabel(null);
\r
1838 #region GUI Functions and Actions
\r
1841 /// Set the GUI to it's finished encoding state.
\r
1843 private void SetEncodeFinished()
\r
1847 if (InvokeRequired)
\r
1849 BeginInvoke(new UpdateWindowHandler(SetEncodeFinished));
\r
1853 lbl_encode.Text = "Encoding Finished";
\r
1854 btn_start.Text = "Start";
\r
1855 btn_start.ToolTipText = "Start the encoding process";
\r
1856 btn_start.Image = Properties.Resources.Play;
\r
1858 // If the window is minimized, display the notification in a popup.
\r
1859 if (Properties.Settings.Default.trayIconAlerts)
\r
1860 if (FormWindowState.Minimized == this.WindowState)
\r
1862 notifyIcon.BalloonTipText = lbl_encode.Text;
\r
1863 notifyIcon.ShowBalloonTip(500);
\r
1866 catch (Exception exc)
\r
1868 MessageBox.Show(exc.ToString());
\r
1873 /// Set the GUI to it's started encoding state.
\r
1875 private void SetEncodeStarted()
\r
1879 if (InvokeRequired)
\r
1881 BeginInvoke(new UpdateWindowHandler(SetEncodeStarted));
\r
1885 lbl_encode.Visible = true;
\r
1886 lbl_encode.Text = "Encoding with " + encodeQueue.Count + " encode(s) pending";
\r
1887 btn_start.Text = "Stop";
\r
1888 btn_start.ToolTipText = "Stop the encoding process.";
\r
1889 btn_start.Image = Properties.Resources.stop;
\r
1891 catch (Exception exc)
\r
1893 MessageBox.Show(exc.ToString());
\r
1898 /// Set the DVD Drive selection in the "Source" Menu
\r
1900 private void SetDriveSelectionMenuItem()
\r
1904 if (InvokeRequired)
\r
1906 BeginInvoke(new UpdateWindowHandler(SetDriveSelectionMenuItem));
\r
1910 List<DriveInformation> drives = Main.GetDrives();
\r
1912 if (drives.Count == 0)
\r
1914 mnu_dvd_drive.Text = "[No DVD Drive Ready]";
\r
1918 this.dvdDrivePath = drives[0].RootDirectory;
\r
1919 this.dvdDriveLabel = drives[0].VolumeLabel;
\r
1920 mnu_dvd_drive.Text = this.dvdDrivePath + " (" + this.dvdDriveLabel + ")";
\r
1924 mnu_dvd_drive.Text = "[No DVD Drive Ready / Found]";
\r
1929 /// Access the preset Handler and setup the preset panel.
\r
1931 private void LoadPresetPanel()
\r
1933 if (presetHandler.CheckIfPresetsAreOutOfDate())
\r
1934 if (!Properties.Settings.Default.presetNotification)
\r
1935 MessageBox.Show(splash,
\r
1936 "HandBrake has determined your built-in presets are out of date... These presets will now be updated.",
\r
1937 "Preset Update", MessageBoxButtons.OK, MessageBoxIcon.Information);
\r
1939 presetHandler.GetPresetPanel(ref treeView_presets);
\r
1940 treeView_presets.Update();
\r
1948 /// Handle GUI shortcuts
\r
1950 /// <param name="msg"></param>
\r
1951 /// <param name="keyData"></param>
\r
1952 /// <returns></returns>
\r
1953 protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
\r
1955 if (keyData == (Keys.Control | Keys.S))
\r
1957 btn_start_Click(this, new EventArgs());
\r
1961 if (keyData == (Keys.Control | Keys.A))
\r
1963 btn_add2Queue_Click(this, new EventArgs());
\r
1966 return base.ProcessCmdKey(ref msg, keyData);
\r
1970 /// If the queue is being processed, prompt the user to confirm application close.
\r
1972 /// <param name="e"></param>
\r
1973 protected override void OnFormClosing(FormClosingEventArgs e)
\r
1975 // If currently encoding, the queue isn't paused, and there are queue items to process, prompt to confirm close.
\r
1976 if ((encodeQueue.IsEncoding) && (!encodeQueue.PauseRequested) && (encodeQueue.Count > 0))
\r
1978 DialogResult result =
\r
1980 "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
1981 "Close HandBrake?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
1982 if (result == DialogResult.No)
\r
1985 base.OnFormClosing(e);
\r
1990 #region In-GUI Encode Status (Experimental)
\r
1993 /// Starts a new thread to monitor and process the CLI encode status
\r
1995 private void EncodeMonitorThread()
\r
1999 Parser encode = new Parser(encodeQueue.HbProcess.StandardOutput.BaseStream);
\r
2000 encode.OnEncodeProgress += EncodeOnEncodeProgress;
\r
2001 while (!encode.EndOfStream)
\r
2002 encode.ReadEncodeStatus();
\r
2004 catch (Exception exc)
\r
2006 MessageBox.Show(exc.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
2011 /// Displays the Encode status in the GUI
\r
2013 /// <param name="Sender"></param>
\r
2014 /// <param name="CurrentTask"></param>
\r
2015 /// <param name="TaskCount"></param>
\r
2016 /// <param name="PercentComplete"></param>
\r
2017 /// <param name="CurrentFps"></param>
\r
2018 /// <param name="AverageFps"></param>
\r
2019 /// <param name="TimeRemaining"></param>
\r
2020 private void EncodeOnEncodeProgress(object Sender, int CurrentTask, int TaskCount, float PercentComplete,
\r
2021 float CurrentFps, float AverageFps, TimeSpan TimeRemaining)
\r
2023 if (this.InvokeRequired)
\r
2025 this.BeginInvoke(new EncodeProgressEventHandler(EncodeOnEncodeProgress),
\r
2028 Sender, CurrentTask, TaskCount, PercentComplete, CurrentFps, AverageFps,
\r
2034 string.Format("Encode Progress: {0}%, FPS: {1}, Avg FPS: {2}, Time Remaining: {3} ",
\r
2035 PercentComplete, CurrentFps, AverageFps, TimeRemaining);
\r
2040 // This is the END of the road ****************************************
\r