}\r
\r
/// <summary>\r
- /// Looks up a localized string similar to Unable to save Chapter Makrers file! .\r
+ /// Looks up a localized string similar to Unable to save Chapter Markers file! .\r
/// </summary>\r
public static string ChaptersViewModel_UnableToExportChaptersWarning {\r
get {\r
}\r
}\r
\r
+ /// <summary>\r
+ /// Looks up a localized string similar to First column in chapters file must only contain a integer number value higher than zero (0).\r
+ /// </summary>\r
+ public static string ChaptersViewModel_UnableToImportChaptersFirstColumnMustContainOnlyIntegerNumber {\r
+ get {\r
+ return ResourceManager.GetString("ChaptersViewModel_UnableToImportChaptersFirstColumnMustContainOnlyIntegerNumber", resourceCulture);\r
+ }\r
+ }\r
+ \r
+ /// <summary>\r
+ /// Looks up a localized string similar to All lines in chapters file must have at least 2 columns of data.\r
+ /// </summary>\r
+ public static string ChaptersViewModel_UnableToImportChaptersLineDoesNotHaveAtLeastTwoColumns {\r
+ get {\r
+ return ResourceManager.GetString("ChaptersViewModel_UnableToImportChaptersLineDoesNotHaveAtLeastTwoColumns", resourceCulture);\r
+ }\r
+ }\r
+ \r
+ /// <summary>\r
+ /// Looks up a localized string similar to Line {0} is invalid. Nothing will be imported..\r
+ /// </summary>\r
+ public static string ChaptersViewModel_UnableToImportChaptersMalformedLineMsg {\r
+ get {\r
+ return ResourceManager.GetString("ChaptersViewModel_UnableToImportChaptersMalformedLineMsg", resourceCulture);\r
+ }\r
+ }\r
+ \r
+ /// <summary>\r
+ /// Looks up a localized string similar to Unable to import chapter file.\r
+ /// </summary>\r
+ public static string ChaptersViewModel_UnableToImportChaptersWarning {\r
+ get {\r
+ return ResourceManager.GetString("ChaptersViewModel_UnableToImportChaptersWarning", resourceCulture);\r
+ }\r
+ }\r
+ \r
/// <summary>\r
/// Looks up a localized string similar to Confirm.\r
/// </summary>\r
using System.Collections.Generic;\r
using System.Collections.ObjectModel;\r
using System.IO;\r
+ using System.Text;\r
+ using System.Windows.Forms;\r
\r
using Caliburn.Micro;\r
\r
using HandBrakeWPF.Services.Interfaces;\r
using HandBrakeWPF.Services.Presets.Model;\r
using HandBrakeWPF.Services.Scan.Model;\r
+ using HandBrakeWPF.Utilities.Output;\r
using HandBrakeWPF.ViewModels.Interfaces;\r
\r
- using LumenWorks.Framework.IO.Csv;\r
-\r
- using Microsoft.Win32;\r
+ using Microsoft.VisualBasic.FileIO;\r
\r
using ChapterMarker = HandBrakeWPF.Services.Encode.Model.Models.ChapterMarker;\r
using EncodeTask = HandBrakeWPF.Services.Encode.Model.EncodeTask;\r
\r
#region Public Methods\r
\r
- /// <summary>\r
- /// Export a CSV file.\r
- /// </summary>\r
- public void Export()\r
- {\r
- var saveFileDialog = new OpenFileDialog\r
- {\r
- Filter = "Csv File|*.csv",\r
- DefaultExt = "csv",\r
- CheckPathExists = true\r
- };\r
- bool? dialogResult = saveFileDialog.ShowDialog();\r
- if (dialogResult.HasValue && dialogResult.Value && !string.IsNullOrEmpty(saveFileDialog.FileName))\r
- {\r
- this.ExportChaptersToCSV(saveFileDialog.FileName);\r
- }\r
- }\r
-\r
/// <summary>\r
/// Export the Chapter Markers to a CSV file\r
/// </summary>\r
- /// <param name="filename">\r
- /// The filename.\r
- /// </param>\r
/// <exception cref="GeneralApplicationException">\r
/// Thrown when exporting fails.\r
/// </exception>\r
- public void ExportChaptersToCSV(string filename)\r
+ public void Export()\r
{\r
- try\r
+ string fileName = null;\r
+ using (var saveFileDialog = new SaveFileDialog()\r
+ {\r
+ Filter = "Csv File|*.csv",\r
+ DefaultExt = "csv",\r
+ CheckPathExists = true,\r
+ OverwritePrompt = true\r
+ })\r
{\r
- string csv = string.Empty;\r
+ var dialogResult = saveFileDialog.ShowDialog();\r
+ fileName = saveFileDialog.FileName;\r
\r
- foreach (ChapterMarker row in this.Task.ChapterNames)\r
+ // Exit early if the user cancelled or the filename is invalid\r
+ if (dialogResult != DialogResult.OK || string.IsNullOrWhiteSpace(fileName))\r
+ return;\r
+ }\r
+\r
+ try\r
+ {\r
+ using (var csv = new StreamWriter(fileName))\r
{\r
- csv += row.ChapterNumber.ToString();\r
- csv += ",";\r
- csv += row.ChapterName.Replace(",", "\\,");\r
- csv += Environment.NewLine;\r
+ foreach (ChapterMarker row in this.Task.ChapterNames)\r
+ {\r
+ csv.Write("{0},{1}{2}", row.ChapterNumber, CsvHelper.Escape(row.ChapterName), Environment.NewLine);\r
+ }\r
}\r
- var file = new StreamWriter(filename);\r
- file.Write(csv);\r
- file.Close();\r
- file.Dispose();\r
}\r
catch (Exception exc)\r
{\r
/// </summary>\r
public void Import()\r
{\r
- var dialog = new OpenFileDialog { Filter = "CSV files (*.csv)|*.csv", CheckFileExists = true };\r
- bool? dialogResult = dialog.ShowDialog();\r
- string filename = dialog.FileName;\r
-\r
- if (!dialogResult.HasValue || !dialogResult.Value || string.IsNullOrEmpty(filename))\r
+ string filename = null;\r
+ using (var dialog = new OpenFileDialog() { Filter = "CSV files (*.csv)|*.csv", CheckFileExists = true })\r
{\r
- return;\r
+ var dialogResult = dialog.ShowDialog();\r
+ filename = dialog.FileName;\r
+\r
+ // Exit if the user didn't press the OK button or the file name is invalid\r
+ if (dialogResult != DialogResult.OK || string.IsNullOrWhiteSpace(filename))\r
+ return;\r
}\r
\r
- IDictionary<int, string> chapterMap = new Dictionary<int, string>();\r
- try\r
+ var chapterMap = new Dictionary<int, string>();\r
+\r
+ using (TextFieldParser csv = new TextFieldParser(filename)\r
+ { CommentTokens = new[] { "#" }, // Comment lines\r
+ Delimiters = new[] { ",", "\t", ";", ":" }, // Support all of these common delimeter types\r
+ HasFieldsEnclosedInQuotes = true, // Assume that our data will be properly escaped\r
+ TextFieldType = FieldType.Delimited,\r
+ TrimWhiteSpace = true // Remove excess whitespace from ends of imported values\r
+ })\r
{\r
- using (CsvReader csv = new CsvReader(new StreamReader(filename), false))\r
+ while (!csv.EndOfData)\r
{\r
- while (csv.ReadNextRecord())\r
+ try\r
{\r
- if (csv.FieldCount == 2)\r
- {\r
- int chapter;\r
- int.TryParse(csv[0], out chapter);\r
- chapterMap[chapter] = csv[1];\r
- }\r
+ // Only read the first two columns, anything else will be ignored but will not raise an error\r
+ var row = csv.ReadFields();\r
+ if (row == null || row.Length < 2) // null condition happens if the file is somehow corrupt during reading\r
+ throw new MalformedLineException(Resources.ChaptersViewModel_UnableToImportChaptersLineDoesNotHaveAtLeastTwoColumns, csv.LineNumber);\r
+\r
+ int chapterNumber;\r
+ if (!int.TryParse(row[0], out chapterNumber))\r
+ throw new MalformedLineException(Resources.ChaptersViewModel_UnableToImportChaptersFirstColumnMustContainOnlyIntegerNumber, csv.LineNumber);\r
+\r
+ // Store the chapter name at the correct index\r
+ chapterMap[chapterNumber] = row[1]?.Trim();\r
+ }\r
+ catch (MalformedLineException mlex)\r
+ {\r
+ throw new GeneralApplicationException(\r
+ Resources.ChaptersViewModel_UnableToImportChaptersWarning,\r
+ string.Format(Resources.ChaptersViewModel_UnableToImportChaptersMalformedLineMsg, mlex.LineNumber),\r
+ mlex);\r
}\r
}\r
}\r
- catch (Exception)\r
- {\r
- // Do Nothing\r
- }\r
+\r
+ // Exit early if no chapter information was extracted\r
+ if (chapterMap.Count <= 0)\r
+ return;\r
\r
// Now iterate over each chatper we have, and set it's name\r
foreach (ChapterMarker item in this.Task.ChapterNames)\r
{\r
string chapterName;\r
- item.ChapterName = chapterMap.TryGetValue(item.ChapterNumber, out chapterName) ? chapterName : string.Empty;\r
+\r
+ // If we don't have a chapter name for this chapter then \r
+ // fallback to the value that is already set for the chapter\r
+ if (!chapterMap.TryGetValue(item.ChapterNumber, out chapterName))\r
+ chapterName = item.ChapterName;\r
+\r
+ // Assign the chapter name unless the name is not set or only whitespace charaters\r
+ item.ChapterName = !string.IsNullOrWhiteSpace(chapterName) ? chapterName : string.Empty;\r
}\r
}\r
\r