/// </summary>\r
public sealed class EnumComboConverter : IValueConverter\r
{\r
- /// <summary>\r
- /// Convert an Enum to it's display value (attribute)\r
- /// </summary>\r
- /// <param name="value">\r
- /// The value.\r
- /// </param>\r
- /// <param name="targetType">\r
- /// The target type.\r
- /// </param>\r
- /// <param name="parameter">\r
- /// The parameter. (A boolean which inverts the output)\r
- /// </param>\r
- /// <param name="culture">\r
- /// The culture.\r
- /// </param>\r
- /// <returns>\r
- /// Visibility property\r
- /// </returns>\r
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)\r
{\r
if (value == null)\r
{\r
return EnumHelper<VideoEncoder>.GetEnumDisplayValues(typeof(VideoEncoder));\r
}\r
+\r
if (value is IEnumerable<PresetPictureSettingsMode>)\r
{\r
return EnumHelper<PresetPictureSettingsMode>.GetEnumDisplayValues(typeof(PresetPictureSettingsMode));\r
}\r
+\r
if (value is IEnumerable<Detelecine>)\r
{\r
return EnumHelper<Detelecine>.GetEnumDisplayValues(typeof(Detelecine));\r
}\r
+\r
if (value is IEnumerable<Denoise>)\r
{\r
return EnumHelper<Denoise>.GetEnumDisplayValues(typeof(Denoise));\r
}\r
+\r
if (value is IEnumerable<VideoScaler>)\r
{\r
return EnumHelper<VideoScaler>.GetEnumDisplayValues(typeof(VideoScaler));\r
}\r
+\r
if (value is IEnumerable<OutputFormat>)\r
{\r
return EnumHelper<OutputFormat>.GetEnumDisplayValues(typeof(OutputFormat));\r
}\r
+\r
if (value is IEnumerable<DeinterlaceFilter>)\r
{\r
return EnumHelper<DeinterlaceFilter>.GetEnumDisplayValues(typeof(DeinterlaceFilter));\r
}\r
+\r
if (value is IEnumerable<CombDetect>)\r
{\r
return EnumHelper<CombDetect>.GetEnumDisplayValues(typeof(CombDetect));\r
}\r
+\r
if (value is IEnumerable<Sharpen>)\r
{\r
return EnumHelper<Sharpen>.GetEnumDisplayValues(typeof(Sharpen));\r
}\r
+\r
if (value is IEnumerable<FileOverwriteBehaviour>)\r
{\r
return EnumHelper<FileOverwriteBehaviour>.GetEnumDisplayValues(typeof(FileOverwriteBehaviour));\r
}\r
\r
+ if (value is IEnumerable<AutonameFileCollisionBehaviour>)\r
+ {\r
+ return EnumHelper<AutonameFileCollisionBehaviour>.GetEnumDisplayValues(typeof(AutonameFileCollisionBehaviour));\r
+ }\r
\r
// Single Items\r
if (targetType == typeof(VideoEncoder) || value.GetType() == typeof(VideoEncoder))\r
{\r
return EnumHelper<VideoEncoder>.GetDisplay((VideoEncoder)value);\r
- } \r
+ }\r
+\r
if (targetType == typeof(PresetPictureSettingsMode) || value.GetType() == typeof(PresetPictureSettingsMode))\r
{\r
return EnumHelper<PresetPictureSettingsMode>.GetDisplay((PresetPictureSettingsMode)value);\r
}\r
+\r
if (targetType == typeof(Detelecine) || value.GetType() == typeof(Detelecine))\r
{\r
return EnumHelper<Detelecine>.GetDisplay((Detelecine)value);\r
}\r
+\r
if (targetType == typeof(Denoise) || value.GetType() == typeof(Denoise))\r
{\r
return EnumHelper<Denoise>.GetDisplay((Denoise)value);\r
}\r
+\r
if (targetType == typeof(QueueItemStatus) || value.GetType() == typeof(QueueItemStatus))\r
{\r
return EnumHelper<QueueItemStatus>.GetDisplay((QueueItemStatus)value);\r
{\r
return EnumHelper<DeinterlaceFilter>.GetDisplay((DeinterlaceFilter)value);\r
}\r
+\r
if (targetType == typeof(CombDetect) || value.GetType() == typeof(CombDetect))\r
{\r
return EnumHelper<CombDetect>.GetDisplay((CombDetect)value);\r
}\r
+\r
if (targetType == typeof(Sharpen) || value.GetType() == typeof(Sharpen))\r
{\r
return EnumHelper<Sharpen>.GetDisplay((Sharpen)value);\r
}\r
+\r
if (targetType == typeof(FileOverwriteBehaviour) || value.GetType() == typeof(FileOverwriteBehaviour))\r
{\r
return EnumHelper<FileOverwriteBehaviour>.GetDisplay((FileOverwriteBehaviour)value);\r
}\r
\r
+ if (targetType == typeof(AutonameFileCollisionBehaviour) || value.GetType() == typeof(AutonameFileCollisionBehaviour))\r
+ {\r
+ return EnumHelper<AutonameFileCollisionBehaviour>.GetDisplay((AutonameFileCollisionBehaviour)value);\r
+ }\r
+\r
return null;\r
}\r
\r
- /// <summary>\r
- /// Convert Back for the IValueConverter Interface. \r
- /// </summary>\r
- /// <param name="value">\r
- /// The value.\r
- /// </param>\r
- /// <param name="targetType">\r
- /// The target type.\r
- /// </param>\r
- /// <param name="parameter">\r
- /// The parameter.\r
- /// </param>\r
- /// <param name="culture">\r
- /// The culture.\r
- /// </param>\r
- /// <returns>\r
- /// Nothing\r
- /// </returns>\r
- /// <exception cref="NotImplementedException">\r
- /// This method is not used!\r
- /// </exception>\r
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)\r
{\r
+ if (value is null)\r
+ {\r
+ return null;\r
+ }\r
+\r
if (targetType == typeof(VideoEncoder) || value.GetType() == typeof(VideoEncoder))\r
{\r
return EnumHelper<VideoEncoder>.GetValue(value.ToString());\r
}\r
+\r
if (targetType == typeof(PresetPictureSettingsMode) || value.GetType() == typeof(PresetPictureSettingsMode))\r
{\r
return EnumHelper<PresetPictureSettingsMode>.GetValue(value.ToString());\r
}\r
+\r
if (targetType == typeof(Denoise) || value.GetType() == typeof(Denoise))\r
{\r
return EnumHelper<Denoise>.GetValue(value.ToString());\r
}\r
+\r
if (targetType == typeof(Detelecine) || value.GetType() == typeof(Detelecine))\r
{\r
return EnumHelper<Detelecine>.GetValue(value.ToString());\r
}\r
+\r
if (targetType == typeof(VideoScaler) || value.GetType() == typeof(VideoScaler))\r
{\r
return EnumHelper<VideoScaler>.GetValue(value.ToString());\r
{\r
return EnumHelper<Sharpen>.GetValue(value.ToString());\r
}\r
+\r
return null;\r
}\r
}\r
<Compile Include="Model\Audio\AudioBehaviourModes.cs" />\r
<Compile Include="Model\Audio\AudioBehaviours.cs" />\r
<Compile Include="Model\DriveInformation.cs" />\r
+ <Compile Include="Model\Options\AutonameFileCollisionBehaviour.cs" />\r
<Compile Include="Model\Options\FileOverwriteBehaviour.cs" />\r
<Compile Include="Model\Filters\FilterTune.cs" />\r
<Compile Include="Model\Filters\FilterPreset.cs" />\r
namespace HandBrakeWPF.Helpers\r
{\r
using System;\r
+ using System.Diagnostics;\r
using System.IO;\r
using System.Linq;\r
using System.Runtime.CompilerServices;\r
+ using System.Threading.Tasks;\r
\r
using Caliburn.Micro;\r
\r
autoNamePath = Path.Combine(Path.GetDirectoryName(task.Destination), destinationFilename);\r
}\r
\r
- // Append out_ to files that already exist or is the source file\r
- //FileOverwriteBehaviour behaviour = (FileOverwriteBehaviour)userSettingService.GetUserSetting<int>(UserSettingConstants.FileOverwriteBehaviour, typeof(int));\r
- //if (behaviour == FileOverwriteBehaviour.Autoname)\r
- //{\r
- if (autoNamePath?.ToLower() == task.Source?.ToLower())\r
- {\r
- autoNamePath = Path.Combine(Path.GetDirectoryName(task.Source), "output_" + destinationFilename);\r
+ autoNamePath = CheckAndHandleFilenameCollisions(autoNamePath, destinationFilename, task, userSettingService);\r
+\r
\r
- int counter = 1;\r
- while (autoNamePath == task.Source)\r
- {\r
- autoNamePath = Path.Combine(Path.GetDirectoryName(task.Source), string.Format("output{0}_", counter) + destinationFilename);\r
- counter = counter + 1;\r
- }\r
- }\r
- //}\r
}\r
\r
return autoNamePath;\r
return userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNamePath).Trim().StartsWith(Constants.SourcePath) ||\r
(userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNamePath).Contains(Constants.SourceFolderName) ||\r
Directory.Exists(userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNamePath).Trim()));\r
- } \r
+ }\r
+\r
+ private static string CheckAndHandleFilenameCollisions(string autoNamePath, string destinationFilename, EncodeTask task, IUserSettingService userSettingService)\r
+ {\r
+ AutonameFileCollisionBehaviour behaviour = (AutonameFileCollisionBehaviour)userSettingService.GetUserSetting<int>(UserSettingConstants.AutonameFileCollisionBehaviour, typeof(int));\r
+ string prefix = string.Empty, postfix = string.Empty;\r
+ switch (behaviour)\r
+ {\r
+ case AutonameFileCollisionBehaviour.Postfix:\r
+ postfix = userSettingService.GetUserSetting<string>(UserSettingConstants.AutonameFilePrePostString);\r
+ break;\r
+ case AutonameFileCollisionBehaviour.Prefix:\r
+ prefix = userSettingService.GetUserSetting<string>(UserSettingConstants.AutonameFilePrePostString);\r
+ break;\r
+ }\r
+\r
+ string extension = Path.GetExtension(destinationFilename);\r
+ string filenameWithoutExt = Path.GetFileNameWithoutExtension(destinationFilename);\r
+\r
+ if (behaviour != AutonameFileCollisionBehaviour.AppendNumber)\r
+ {\r
+ if (autoNamePath?.ToLower() == task.Source?.ToLower())\r
+ {\r
+ autoNamePath = Path.Combine(Path.GetDirectoryName(task.Source), prefix + filenameWithoutExt + postfix + extension);\r
+\r
+ int counter = 0;\r
+ while (File.Exists(autoNamePath))\r
+ {\r
+ counter = counter + 1;\r
+ string appendedNumber = string.Format("({0})", counter);\r
+ autoNamePath = Path.Combine(Path.GetDirectoryName(task.Source), prefix + filenameWithoutExt + postfix + appendedNumber + extension);\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ int counter = 0;\r
+ while (File.Exists(autoNamePath))\r
+ {\r
+ counter = counter + 1;\r
+ string appendedNumber = string.Format("({0})", counter);\r
+ autoNamePath = Path.Combine(Path.GetDirectoryName(task.Source), filenameWithoutExt + appendedNumber + extension);\r
+ }\r
+ }\r
+\r
+ return autoNamePath;\r
+ }\r
}\r
}\r
--- /dev/null
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="AutonameFileCollisionBehaviour.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Model.Options
+{
+ using HandBrake.Interop.Attributes;
+
+ using HandBrakeWPF.Properties;
+
+ public enum AutonameFileCollisionBehaviour
+ {
+ [DisplayName(typeof(Resources), "CollisionBehaviour_AppendNumber")]
+ AppendNumber = 0,
+ [DisplayName(typeof(Resources), "CollisionBehaviour_Pre")]
+ Prefix = 1,
+ [DisplayName(typeof(Resources), "CollisionBehaviour_Post")]
+ Postfix = 2,
+ }
+}
}
}
+ /// <summary>
+ /// Looks up a localized string similar to Append Number.
+ /// </summary>
+ public static string CollisionBehaviour_AppendNumber {
+ get {
+ return ResourceManager.GetString("CollisionBehaviour_AppendNumber", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Postfix.
+ /// </summary>
+ public static string CollisionBehaviour_Post {
+ get {
+ return ResourceManager.GetString("CollisionBehaviour_Post", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Prefix.
+ /// </summary>
+ public static string CollisionBehaviour_Pre {
+ get {
+ return ResourceManager.GetString("CollisionBehaviour_Pre", resourceCulture);
+ }
+ }
+
/// <summary>
/// Looks up a localized string similar to Confirm.
/// </summary>
}
}
+ /// <summary>
+ /// Looks up a localized string similar to Filename collision behaviour:.
+ /// </summary>
+ public static string OptionsView_FileCollisionBehaviour {
+ get {
+ return ResourceManager.GetString("OptionsView_FileCollisionBehaviour", resourceCulture);
+ }
+ }
+
/// <summary>
/// Looks up a localized string similar to File overwrite behaviour:.
/// </summary>
<data name="Options_WhenDoneColon" xml:space="preserve">\r
<value>When Done:</value>\r
</data>\r
+ <data name="OptionsView_FileCollisionBehaviour" xml:space="preserve">\r
+ <value>Filename collision behaviour:</value>\r
+ </data>\r
+ <data name="CollisionBehaviour_Post" xml:space="preserve">\r
+ <value>Postfix</value>\r
+ </data>\r
+ <data name="CollisionBehaviour_Pre" xml:space="preserve">\r
+ <value>Prefix</value>\r
+ </data>\r
+ <data name="CollisionBehaviour_AppendNumber" xml:space="preserve">\r
+ <value>Append Number</value>\r
+ </data>\r
</root>
\ No newline at end of file
/// </summary>\r
public class UserSettingConstants\r
{\r
- #region Constants and Fields\r
-\r
public const string AutoNameFormat = "autoNameFormat";\r
public const string AutoNamePath = "autoNamePath";\r
public const string AutoNameRemoveUnderscore = "AutoNameRemoveUnderscore";\r
public const string ShowAddAllToQueue = "ShowAddAllToQueue";\r
public const string ShowAddSelectionToQueue = "ShowAddSelectionToQueue";\r
public const string FileOverwriteBehaviour = "FileOverwriteBehaviour";\r
-\r
- #endregion\r
+ public const string AutonameFileCollisionBehaviour = "AutonameFileCollisionBehaviour";\r
+ public const string AutonameFilePrePostString = "AutonameFilePrePostString";\r
}\r
}
\ No newline at end of file
private bool showAddSelectionToQueue;\r
private bool showAddAllToQueue;\r
private int selectedOverwriteBehaviour;\r
+ private int selectedCollisionBehaviour;\r
+\r
+ private string prePostFilenameText;\r
+\r
+ private bool showPrePostFilenameBox;\r
\r
#endregion\r
\r
}\r
}\r
\r
+ public BindingList<AutonameFileCollisionBehaviour> AutonameFileCollisionBehaviours { get; set; }\r
+\r
+ public int SelectedCollisionBehaviour\r
+ {\r
+ get => this.selectedCollisionBehaviour;\r
+ set\r
+ {\r
+ if (value == this.selectedCollisionBehaviour) return;\r
+ this.selectedCollisionBehaviour = value;\r
+\r
+ this.ShowPrePostFilenameBox = this.selectedCollisionBehaviour >= 1;\r
+\r
+ this.NotifyOfPropertyChange(() => this.SelectedCollisionBehaviour);\r
+ }\r
+ }\r
+\r
+ public string PrePostFilenameText\r
+ {\r
+ get => this.prePostFilenameText;\r
+ set\r
+ {\r
+ if (value == this.prePostFilenameText) return;\r
+\r
+ if (this.IsValidAutonameFormat(value, false))\r
+ {\r
+ this.prePostFilenameText = value;\r
+ }\r
+\r
+ this.NotifyOfPropertyChange(() => this.PrePostFilenameText);\r
+ }\r
+ }\r
+\r
+ public bool ShowPrePostFilenameBox\r
+ {\r
+ get => this.showPrePostFilenameBox;\r
+ set\r
+ {\r
+ if (value == this.showPrePostFilenameBox) return;\r
+ this.showPrePostFilenameBox = value;\r
+ this.NotifyOfPropertyChange(() => this.ShowPrePostFilenameBox);\r
+ }\r
+ }\r
+\r
#endregion\r
\r
#region Preview\r
this.FileOverwriteBehaviourList = new BindingList<FileOverwriteBehaviour>();\r
this.FileOverwriteBehaviourList.Add(FileOverwriteBehaviour.Ask);\r
this.FileOverwriteBehaviourList.Add(FileOverwriteBehaviour.ForceOverwrite);\r
- // this.FileOverwriteBehaviourList.Add(FileOverwriteBehaviour.Autoname);\r
this.SelectedOverwriteBehaviour = this.userSettingService.GetUserSetting<int>(UserSettingConstants.FileOverwriteBehaviour, typeof(int));\r
\r
+ // Collision behaviour\r
+ this.AutonameFileCollisionBehaviours = new BindingList<AutonameFileCollisionBehaviour>() { AutonameFileCollisionBehaviour.AppendNumber, AutonameFileCollisionBehaviour.Prefix, AutonameFileCollisionBehaviour.Postfix };\r
+ this.SelectedCollisionBehaviour = this.userSettingService.GetUserSetting<int>(UserSettingConstants.AutonameFileCollisionBehaviour, typeof(int));\r
+ this.PrePostFilenameText = this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutonameFilePrePostString);\r
+\r
// #############################\r
// Picture Tab\r
// #############################\r
this.userSettingService.SetUserSetting(UserSettingConstants.AutoNameTitleCase, this.ChangeToTitleCase);\r
this.userSettingService.SetUserSetting(UserSettingConstants.RemovePunctuation, this.RemovePunctuation);\r
this.userSettingService.SetUserSetting(UserSettingConstants.FileOverwriteBehaviour, this.SelectedOverwriteBehaviour);\r
+ this.userSettingService.SetUserSetting(UserSettingConstants.AutonameFileCollisionBehaviour, this.SelectedCollisionBehaviour);\r
+ this.userSettingService.SetUserSetting(UserSettingConstants.AutonameFilePrePostString, this.PrePostFilenameText);\r
\r
/* Previews */\r
this.userSettingService.SetUserSetting(UserSettingConstants.VLCPath, this.VLCPath);\r
/// <returns>True if valid</returns>\r
private bool IsValidAutonameFormat(string input, bool isSilent)\r
{\r
+ if (string.IsNullOrEmpty(input))\r
+ {\r
+ return true;\r
+ }\r
+\r
char[] invalidchars = Path.GetInvalidFileNameChars();\r
Array.Sort(invalidchars);\r
foreach (var characterToTest in input)\r
<TextBlock Text="{x:Static Properties:Resources.OptionsView_FormatOptions}" Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" FontStyle="Italic" FontSize="11" TextWrapping="Wrap" />\r
</Grid>\r
\r
+ <StackPanel Orientation="Horizontal" Margin="0,15,0,0">\r
+ <TextBlock VerticalAlignment="Center" Text="{x:Static Properties:Resources.OptionsView_FileCollisionBehaviour}" />\r
+ <ComboBox Width="120" ItemsSource="{Binding AutonameFileCollisionBehaviours, Converter={StaticResource enumComboConverter}}" SelectedIndex="{Binding SelectedCollisionBehaviour}" HorizontalAlignment="Left" />\r
+ <TextBox Text="{Binding PrePostFilenameText, UpdateSourceTrigger=PropertyChanged}" Width="150" VerticalAlignment="Center" Visibility="{Binding ShowPrePostFilenameBox, Converter={StaticResource boolToVisConverter}}" HorizontalAlignment="Left" Margin="5,0,0,0" />\r
+ </StackPanel>\r
+\r
+\r
<StackPanel Orientation="Vertical" Margin="0,15,0,0">\r
<CheckBox Content="{x:Static Properties:Resources.Options_TitleCase}" IsChecked="{Binding ChangeToTitleCase}" />\r
<CheckBox Content="{x:Static Properties:Resources.Options_ReplaceUnderscores}" IsChecked="{Binding RemoveUnderscores}"/>\r
<anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:int" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">0</anyType>\r
</value>\r
</item>\r
- \r
+ <item>\r
+ <key>\r
+ <string>AutonameFileCollisionBehaviour</string>\r
+ </key>\r
+ <value>\r
+ <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:int" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">1</anyType>\r
+ </value>\r
+ </item>\r
+ <item>\r
+ <key>\r
+ <string>AutonameFilePrePostString</string>\r
+ </key>\r
+ <value>\r
+ <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:string" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">output_</anyType>\r
+ </value>\r
+ </item>\r
+\r
</dictionary>
\ No newline at end of file