2
\$\begingroup\$

Since the last post, I have ported it to WPF (semi-MVVM) and added support for Excel and PowerPoint files, and custom fields and scripts.

The conversion is done by interop with office. Apparently consistency is too much to ask for from Microsoft, and the libraries for Excel, PowerPoint, and Word are all slightly different. (I've also found that Excel will randomly fail to open/convert a spreadsheet, or randomly display odd windows, progress bars, or enable/disable add-ins. But, I digress.)

Just to get it out of the way (it has been mentioned before), the iTextSharp library is not mine, and so I do not control the naming conventions for it. Please do not suggest to rename any part of that library. I also wish they would properly capitalize their namespaces, but there is nothing I can do.

File Processor

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using iTextSharp.text;
using iTextSharp.text.pdf;
using MichaelBrandonMorris.Extensions.CollectionExtensions;
using MichaelBrandonMorris.Extensions.PrimitiveExtensions;
using static System.Environment;
using static System.Environment.SpecialFolder;
using static System.IO.Path;
using static Microsoft.Office.Core.MsoAutomationSecurity;
using static System.IO.Directory;
using Progress = System.IProgress<System.Tuple<int, int, string>>;
using ProgressReport = System.Tuple<int, int, string>;
using static Microsoft.Office.Interop.Word.WdExportFormat;
using static Microsoft.Office.Interop.Excel.XlFixedFormatType;
using static Microsoft.Office.Interop.PowerPoint.PpFixedFormatType;
using WordApplication = Microsoft.Office.Interop.Word.Application;
using ExcelApplication = Microsoft.Office.Interop.Excel.Application;
using PowerPointApplication = Microsoft.Office.Interop.PowerPoint.Application;
using static System.IO.File;
using static System.Diagnostics.Debug;
using ActionTypeMapping = System.Collections.Generic.Dictionary
    <MichaelBrandonMorris.PdfConversionAndTimeStampTool.ScriptTiming,
        iTextSharp.text.pdf.PdfName>;
using static MichaelBrandonMorris.PdfConversionAndTimeStampTool.FieldPages;
using static MichaelBrandonMorris.PdfConversionAndTimeStampTool.ScriptTiming;
using static iTextSharp.text.pdf.PdfFormField;
using static Microsoft.Office.Interop.PowerPoint.PpAlertLevel;
using static iTextSharp.text.pdf.PdfAction;
using static Microsoft.Office.Core.MsoTriState;

namespace MichaelBrandonMorris.PdfConversionAndTimeStampTool
{
    internal class FileProcessor
    {
        private const int AlternatingPageIncrement = 2;
        private const string DateTimeFormat = "yyyyMMddTHHmmss";
        private const int EveryPageIncrement = 1;
        private const string ExcelExtension = ".xls";
        private const string ExcelXmlExtension = ".xlsx";
        private const int FirstPageNumber = 1;
        private const string FolderName = "PDF Conversion And Time Stamp Tool";
        private const string PdfExtension = ".pdf";
        private const string PowerPointExtension = ".ppt";
        private const string PowerPointXmlExtension = ".pptx";
        private const string WordExtension = ".doc";
        private const string WordXmlExtension = ".docx";

        private static readonly string OutputFolderPath = Combine(
            GetFolderPath(MyDocuments), FolderName);

        private static readonly string ProcessingFolderPath = Combine(
            GetFolderPath(ApplicationData), FolderName);

        private static readonly ActionTypeMapping ActionTypeMapping =
            new ActionTypeMapping
            {
                [DidPrint] = PdfWriter.DID_PRINT,
                [DidSave] = PdfWriter.DID_SAVE,
                [WillPrint] = PdfWriter.WILL_PRINT,
                [WillSave] = PdfWriter.WILL_SAVE
            };


        internal FileProcessor(
            IList<string> fileNames,
            Progress progress,
            Field field = null,
            Script script = null)
        {
            FileNames = fileNames;
            Progress = progress;
            Field = field;
            Script = script;
            CreateDirectory(OutputFolderPath);
            CreateDirectory(ProcessingFolderPath);
        }

        private CancellationToken CancellationToken =>
            CancellationTokenSource.Token;

        private CancellationTokenSource CancellationTokenSource
        {
            get;
        } = new CancellationTokenSource();

        private Field Field
        {
            get;
        }

        private IList<string> FileNames
        {
            get;
        }

        private List<string> Log
        {
            get;
        } = new List<string>();

        private Progress Progress
        {
            get;
        }

        private Script Script
        {
            get;
        }

        internal void Cancel()
        {
            CancellationTokenSource.Cancel();
        }

        internal async Task Execute()
        {
            var task = Task.Run(
                () =>
                {
                    var count = 0;
                    foreach (var t in FileNames)
                    {
                        CancellationToken.ThrowIfCancellationRequested();
                        var currentFileName = string.Empty;
                        try
                        {
                            ClearProcessing();
                            currentFileName = CopyToProcessing(t);

                            if (!IsPdf(currentFileName))
                            {
                                currentFileName = ConvertToPdf(currentFileName);
                            }

                            if (Field != null || Script != null)
                            {
                                ProcessPdf(currentFileName);
                            }
                            else
                            {
                                MoveToOutput(currentFileName);
                            }
                        }
                        catch (Exception e)
                        {
                            Log.Add(e.Message);
                        }

                        Progress.Report(
                            new ProgressReport(
                                ++count, FileNames.Count, currentFileName));
                    }
                },
                CancellationToken);

            await task;

            if (!Log.IsEmpty())
            {
                var now = DateTime.Now;
                var logFileName = $"Log - {now.ToString(DateTimeFormat)}.txt";
                var logFilePath = Combine(OutputFolderPath, logFileName);
                WriteAllLines(logFilePath, Log);
            }
        }

        private static void ClearProcessing()
        {
            foreach (var file in GetFiles(ProcessingFolderPath))
            {
                File.Delete(file);
            }
        }

        private static void ConvertExcelToPdf(
            string fileName, string processingPath)
        {
            var excelApplication = new ExcelApplication
            {
                ScreenUpdating = false,
                DisplayAlerts = false,
                AutomationSecurity = msoAutomationSecurityForceDisable
            };

            var excelWorkbook = excelApplication.Workbooks.Open(fileName);

            if (excelWorkbook == null)
            {
                excelApplication.Quit();
                throw new Exception(
                    $"The file '{fileName}' could not be opened.");
            }

            try
            {
                excelWorkbook.ExportAsFixedFormat(xlTypePDF, processingPath);
            }
            finally
            {
                excelWorkbook.Close();
                excelApplication.Quit();
            }
        }

        private static void ConvertPowerPointToPdf(
            string fileName, string processingPath)
        {
            var powerPointApplication = new PowerPointApplication
            {
                DisplayAlerts = ppAlertsNone,
                AutomationSecurity = msoAutomationSecurityForceDisable,
                DisplayDocumentInformationPanel = false
            };

            var powerPointPresentation =
                powerPointApplication.Presentations.Open(
                    fileName, WithWindow: msoFalse);

            if (powerPointPresentation == null)
            {
                powerPointApplication.Quit();
                return;
            }

            try
            {
                powerPointPresentation.ExportAsFixedFormat(
                    processingPath, ppFixedFormatTypePDF);
            }
            finally
            {
                powerPointPresentation.Close();
                powerPointApplication.Quit();
            }
        }

        [SuppressMessage("ReSharper", "ImplicitlyCapturedClosure")]
        private static string ConvertToPdf(string fileName)
        {
            var processingFileName = GetFileNameWithoutExtension(fileName) +
                                     PdfExtension;

            var processingPath = Combine(
                ProcessingFolderPath, processingFileName);

            var extension = GetExtension(fileName)?.ToLower();

            if (extension.IsNullOrWhiteSpace())
            {
                throw new Exception(
                    $"The file '{fileName}'does not have an extension.");
            }

            var extensionMapping = new Dictionary<string, Action>
            {
                [WordExtension] = () =>
                {
                    ConvertWordToPdf(fileName, processingPath);
                },
                [WordXmlExtension] = () =>
                {
                    ConvertWordToPdf(fileName, processingPath);
                },
                [ExcelExtension] = () =>
                {
                    ConvertExcelToPdf(fileName, processingPath);
                },
                [ExcelXmlExtension] = () =>
                {
                    ConvertExcelToPdf(fileName, processingPath);
                },
                [PowerPointExtension] = () =>
                {
                    ConvertPowerPointToPdf(fileName, processingPath);
                },
                [PowerPointXmlExtension] = () =>
                {
                    ConvertPowerPointToPdf(fileName, processingPath);
                }
            };

            Assert(extension != null, "extension != null");
            extensionMapping[extension]();
            return processingPath;
        }

        private static void ConvertWordToPdf(
            string fileName, string processingPath)
        {
            var wordApplication = new WordApplication
            {
                AutomationSecurity = msoAutomationSecurityForceDisable
            };

            wordApplication.Application.AutomationSecurity =
                msoAutomationSecurityForceDisable;

            var wordDocument = wordApplication.Documents.Open(fileName);

            if (wordDocument == null)
            {
                wordApplication.Quit();
                return;
            }

            try
            {
                wordDocument.ExportAsFixedFormat(
                    processingPath, wdExportFormatPDF);
            }
            finally
            {
                wordDocument.Close(false);
                wordApplication.Quit();
            }
        }

        private static string CopyToProcessing(string fileName)
        {
            var processingPath = GetProcessingPath(fileName);
            Copy(fileName, processingPath);
            return processingPath;
        }

        private static string GetOutputPath(string fileName)
        {
            var outputFileName = GetFileName(fileName);

            if (outputFileName == null)
            {
                throw new Exception(
                    $"The name of the file '{fileName}' " +
                    "is incorrectly formatted.");
            }

            return Combine(OutputFolderPath, outputFileName);
        }

        private static string GetProcessingPath(string fileName)
        {
            var processingFileName = GetFileName(fileName);

            if (processingFileName != null)
            {
                return Combine(ProcessingFolderPath, processingFileName);
            }

            throw new Exception(
                $"The name of the file '{fileName}' " +
                "is incorrectly formatted.");
        }

        private static bool IsPdf(string fileName)
        {
            return GetExtension(fileName).EqualsOrdinalIgnoreCase(
                PdfExtension);
        }

        private static void MoveToOutput(string fileName)
        {
            var outputPath = GetOutputPath(fileName);

            if (File.Exists(outputPath))
            {
                File.Delete(outputPath);
            }

            File.Move(fileName, outputPath);
        }

        private void AddFieldToPage(
            int pageNumber,
            PdfStamper pdfStamper,
            PdfFormField parentField)
        {
            var rectangle = new Rectangle(
                Field.LeftX, Field.TopY, Field.RightX, Field.BottomY);

            var textField = new TextField(pdfStamper.Writer, rectangle, null);
            var childField = textField.GetTextField();
            parentField.AddKid(childField);
            childField.PlaceInPage = pageNumber;
        }

        private void AddFieldToPdf(PdfStamper pdfStamper, int numberOfPages)
        {
            var parentField = CreateTextField(
                pdfStamper.Writer, false, false, 0);

            parentField.FieldName = Field.Name;

            var pageNumber = Field.Pages == Last
                ? numberOfPages
                : FirstPageNumber;

            // ReSharper disable once ConvertIfStatementToSwitchStatement
            if (Field.Pages == First ||
                Field.Pages == Last)
            {
                AddFieldToPage(pageNumber, pdfStamper, parentField);
            }
            else if (Field.Pages == Custom)
            {
                foreach (var customPageNumber in Field.CustomPageNumbers)
                {
                    AddFieldToPage(customPageNumber, pdfStamper, parentField);
                }
            }
            else
            {
                var increment = Field.Pages == All
                    ? EveryPageIncrement
                    : AlternatingPageIncrement;

                if (Field.Pages == Even)
                {
                    pageNumber += 1;
                }

                for (; pageNumber < numberOfPages; pageNumber += increment)
                {
                    AddFieldToPage(pageNumber, pdfStamper, parentField);
                }
            }

            pdfStamper.AddAnnotation(parentField, FirstPageNumber);
        }

        private void AddScriptToPdf(PdfStamper pdfStamper)
        {
            var pdfAction = JavaScript(Script.Text, pdfStamper.Writer);

            pdfStamper.Writer.SetAdditionalAction(
                ActionTypeMapping[Script.Timing], pdfAction);
        }

        private void ProcessPdf(string fileName)
        {
            using (var pdfReader = new PdfReader(fileName))
            using (var fileStream = new FileStream(
                GetOutputPath(fileName), FileMode.Create))
            using (var pdfStamper = new PdfStamper(pdfReader, fileStream))
            {
                if (Field != null)
                {
                    AddFieldToPdf(pdfStamper, pdfReader.NumberOfPages);
                }

                if (Script != null)
                {
                    AddScriptToPdf(pdfStamper);
                }
            }
        }
    }
}

Field

using System.Collections.Generic;
using static MichaelBrandonMorris.PdfConversionAndTimeStampTool.FieldPages;

namespace MichaelBrandonMorris.PdfConversionAndTimeStampTool
{
    internal enum FieldPages
    {
        All,
        Custom,
        Even,
        First,
        Last,
        Odd
    }

    internal class Field
    {
        internal static readonly Field TimeStampField = new Field(
            TimeStampFieldName,
            TimeStampFieldLeftX,
            TimeStampFieldTopY,
            TimeStampFieldRightX,
            TimeStampFieldBottomY,
            All);

        private const int TimeStampFieldBottomY = 756;
        private const int TimeStampFieldLeftX = 36;
        private const string TimeStampFieldName = "Timestamp";
        private const int TimeStampFieldRightX = 576;
        private const int TimeStampFieldTopY = 792;

        internal Field(
            string name,
            int leftX,
            int topY,
            int rightX,
            int bottomY,
            FieldPages pages,
            IEnumerable<int> customPageNumbers = null)
        {
            Name = name;
            LeftX = leftX;
            TopY = topY;
            RightX = rightX;
            BottomY = bottomY;
            Pages = pages;
            CustomPageNumbers = customPageNumbers;
        }

        internal int BottomY
        {
            get;
        }

        internal IEnumerable<int> CustomPageNumbers
        {
            get;
        }

        internal int LeftX
        {
            get;
        }

        internal string Name
        {
            get;
        }

        internal FieldPages Pages
        {
            get;
        }

        internal int RightX
        {
            get;
        }

        internal int TopY
        {
            get;
        }

        internal static IList<FieldPages> GetFieldPages()
        {
            return new List<FieldPages>
            {
                All,
                Custom,
                Even,
                First,
                Last,
                Odd
            };
        }
    }
}

Script

using System.Collections.Generic;
using static
    MichaelBrandonMorris.PdfConversionAndTimeStampTool.Properties.Resources;
using static MichaelBrandonMorris.PdfConversionAndTimeStampTool.ScriptTiming;

namespace MichaelBrandonMorris.PdfConversionAndTimeStampTool
{
    internal enum ScriptTiming
    {
        DidPrint,
        DidSave,
        WillPrint,
        WillSave
    }

    internal class Script
    {
        internal static readonly Script TimeStampOnPrintDay = new Script(
            TimeStampDay, WillPrint);

        internal static readonly Script TimeStampOnPrintMonth = new Script(
            TimeStampMonth, WillPrint);

        internal Script(string text, ScriptTiming timing)
        {
            Text = text;
            Timing = timing;
        }

        internal string Text
        {
            get;
        }

        internal ScriptTiming Timing
        {
            get;
        }

        internal static IList<ScriptTiming> GetScriptTimings()
        {
            return new List<ScriptTiming>
            {
                DidPrint,
                DidSave,
                WillPrint,
                WillSave
            };
        }
    }
}

ViewModel

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Deployment.Application;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using GalaSoft.MvvmLight.CommandWpf;
using MichaelBrandonMorris.Extensions.CollectionExtensions;
using MichaelBrandonMorris.Extensions.PrimitiveExtensions;
using Microsoft.Win32;
using static MichaelBrandonMorris.PdfConversionAndTimeStampTool.FieldPages;
using static MichaelBrandonMorris.PdfConversionAndTimeStampTool.Field;
using static MichaelBrandonMorris.PdfConversionAndTimeStampTool.Script;
using ProgressReport = System.Tuple<int, int, string>;
using Progress = System.IProgress<System.Tuple<int, int, string>>;
using static System.IO.File;
using static System.Windows.MessageBox;
using static System.Windows.MessageBoxResult;
using static System.Windows.MessageBoxButton;
using static System.IO.Path;

namespace MichaelBrandonMorris.PdfConversionAndTimeStampTool
{
    internal class ViewModel : INotifyPropertyChanged
    {
        private const string ReplaceFilesMessageBoxText =
            "Would you like to replace the already selected files?";

        private const string SelectFilesFilter =
            "Office Files & PDFs|*.doc;*.docx;*.pdf;*.ppt;*.pptx;*.xls;*.xlsx";

        private static readonly string HelpFile =
            Combine(Combine("Resources", "Help"), "Help.chm");

        private AboutWindow _aboutWindow;
        private string _customPageNumbers;
        private int _fieldBottomY;
        private int _fieldLeftX;
        private int _fieldRightX;
        private string _fieldTitle;
        private int _fieldTopY;
        private bool _isBusy;
        private string _message;
        private bool _messageIsVisible;
        private int _messageZIndex;
        private int _progressPercent;
        private string _progressText;
        private FieldPages _selectedFieldPages;
        private string _selectedScript;
        private ScriptTiming _selectedTiming;
        private bool _shouldShowCustomPageNumbers;
        private Process _userGuide;

        public ICommand Cancel => new RelayCommand(ExecuteCancel, CanCancel);

        public ICommand Convert => new RelayCommand(
            ExecuteConvert, CanExecuteAction);

        public ICommand CustomAction => new RelayCommand(
            ExecuteCustomAction, CanExecuteAction);

        public string CustomPageNumbers
        {
            get
            {
                return _customPageNumbers;
            }
            set
            {
                if (_customPageNumbers == value)
                {
                    return;
                }

                _customPageNumbers = value;
                NotifyProeprtyChanged();
            }
        }

        public int FieldBottomY
        {
            get
            {
                return _fieldBottomY;
            }
            set
            {
                if (_fieldBottomY == value)
                {
                    return;
                }

                _fieldBottomY = value;
                NotifyProeprtyChanged();
            }
        }

        public int FieldLeftX
        {
            get
            {
                return _fieldLeftX;
            }
            set
            {
                if (_fieldLeftX == value)
                {
                    return;
                }

                _fieldLeftX = value;
                NotifyProeprtyChanged();
            }
        }

        public IList<FieldPages> FieldPages
        {
            get;
        } = GetFieldPages();

        public int FieldRightX
        {
            get
            {
                return _fieldRightX;
            }
            set
            {
                if (_fieldRightX == value)
                {
                    return;
                }

                _fieldRightX = value;
                NotifyProeprtyChanged();
            }
        }

        public string FieldTitle
        {
            get
            {
                return _fieldTitle;
            }
            set
            {
                if (_fieldTitle == value)
                {
                    return;
                }

                _fieldTitle = value;
                NotifyProeprtyChanged();
            }
        }

        public int FieldTopY
        {
            get
            {
                return _fieldTopY;
            }
            set
            {
                if (_fieldTopY == value)
                {
                    return;
                }

                _fieldTopY = value;
                NotifyProeprtyChanged();
            }
        }

        public bool IsBusy
        {
            get
            {
                return _isBusy;
            }
            set
            {
                if (_isBusy == value)
                {
                    return;
                }

                _isBusy = value;
                NotifyProeprtyChanged();
            }
        }

        public string Message
        {
            get
            {
                return _message;
            }
            set
            {
                if (_message == value)
                {
                    return;
                }

                _message = value;
                NotifyProeprtyChanged();
            }
        }

        public bool MessageIsVisible
        {
            get
            {
                return _messageIsVisible;
            }
            set
            {
                if (_messageIsVisible == value)
                {
                    return;
                }

                _messageIsVisible = value;
                NotifyProeprtyChanged();
            }
        }

        public int MessageZIndex
        {
            get
            {
                return _messageZIndex;
            }
            set
            {
                if (_messageZIndex == value)
                {
                    return;
                }

                _messageZIndex = value;
                NotifyProeprtyChanged();
            }
        }

        public ICommand OpenAboutWindow
            => new RelayCommand(ExecuteOpenAboutWindow);

        public ICommand OpenUserGuide => new RelayCommand(
            ExecuteOpenUserGuide);

        public int ProgressPercent
        {
            get
            {
                return _progressPercent;
            }
            set
            {
                if (_progressPercent == value)
                {
                    return;
                }

                _progressPercent = value;
                NotifyProeprtyChanged();
            }
        }

        public string ProgressText
        {
            get
            {
                return _progressText;
            }
            set
            {
                if (_progressText == value)
                {
                    return;
                }

                _progressText = value;
                NotifyProeprtyChanged();
            }
        }

        public IList<ScriptTiming> ScriptTimings
        {
            get;
        } = GetScriptTimings();

        public FieldPages SelectedFieldPages
        {
            get
            {
                return _selectedFieldPages;
            }
            set
            {
                if (_selectedFieldPages == value)
                {
                    return;
                }

                _selectedFieldPages = value;
                NotifyProeprtyChanged();
                ShouldShowCustomPageNumbers = _selectedFieldPages == Custom;
            }
        }

        public ObservableCollection<CheckedListItem<string>> SelectedFileNames
        {
            get;
            set;
        } = new ObservableCollection<CheckedListItem<string>>();

        public string SelectedScript
        {
            get
            {
                return _selectedScript;
            }
            set
            {
                if (_selectedScript == value)
                {
                    return;
                }

                _selectedScript = value;
                NotifyProeprtyChanged();
            }
        }

        public ScriptTiming SelectedTiming
        {
            get
            {
                return _selectedTiming;
            }
            set
            {
                if (_selectedTiming == value)
                {
                    return;
                }

                _selectedTiming = value;
                NotifyProeprtyChanged();
            }
        }

        public ICommand SelectFiles => new RelayCommand(ExecuteSelectFiles);

        public ICommand SelectScript => new RelayCommand(ExecuteSelectScript);

        public bool ShouldShowCustomPageNumbers
        {
            get
            {
                return _shouldShowCustomPageNumbers;
            }
            set
            {
                if (_shouldShowCustomPageNumbers == value)
                {
                    return;
                }

                _shouldShowCustomPageNumbers = value;
                NotifyProeprtyChanged();
            }
        }

        public ICommand TimeStampDay => new RelayCommand(
            ExecuteTimeStampDay, CanExecuteAction);

        public ICommand TimeStampMonth => new RelayCommand(
            ExecuteTimeStampMonth, CanExecuteAction);

        public string Version
        {
            get
            {
                string version;

                try
                {
                    version =
                        ApplicationDeployment.CurrentDeployment.CurrentVersion
                            .ToString();
                }
                catch (InvalidDeploymentException)
                {
                    version = "Dev";
                }

                return version;
            }
        }

        private AboutWindow AboutWindow
        {
            get
            {
                if (_aboutWindow == null || !_aboutWindow.IsVisible)
                {
                    _aboutWindow = new AboutWindow();
                }

                return _aboutWindow;
            }
        }

        private FileProcessor FileProcessor
        {
            get;
            set;
        }

        private Progress Progress =>
            new Progress<ProgressReport>(HandleProgressReport);

        private Process UserGuide
        {
            get
            {
                if (_userGuide != null && !_userGuide.HasExited)
                {
                    _userGuide.Kill();
                }
                _userGuide = new Process
                {
                    StartInfo =
                    {
                        FileName = HelpFile
                    }
                };

                return _userGuide;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private bool CanCancel()
        {
            return IsBusy;
        }

        private bool CanExecuteAction()
        {
            return !SelectedFileNames.IsEmpty();
        }

        private void ExecuteCancel()
        {
            FileProcessor.Cancel();
        }

        private void ExecuteConvert()
        {
            ExecuteTask();
        }

        private void ExecuteCustomAction()
        {
            var field = new Field(
                FieldTitle,
                FieldLeftX,
                FieldTopY,
                FieldRightX,
                FieldBottomY,
                SelectedFieldPages,
                GetCustomPageNumbers());

            var scriptText = ReadAllText(SelectedScript);
            var script = new Script(scriptText, SelectedTiming);

            ExecuteTask(field, script);
        }

        private void ExecuteOpenAboutWindow()
        {
            AboutWindow.Show();
            AboutWindow.Activate();
        }

        private void ExecuteOpenUserGuide()
        {
            try
            {
                UserGuide.Start();
            }
            catch (Exception)
            {
                ShowMessage("User guide could not be opened.");
            }
        }

        private void ExecuteSelectFiles()
        {
            if (!SelectedFileNames.IsEmpty())
            {
                var messageBoxResult = Show(
                    ReplaceFilesMessageBoxText,
                    "Replace Files?",
                    YesNo);

                if (messageBoxResult == Yes)
                {
                    SelectedFileNames.Clear();
                }
            }

            var openFileDialog = new OpenFileDialog
            {
                Multiselect = true,
                Filter = SelectFilesFilter
            };

            openFileDialog.ShowDialog();

            foreach (var item in openFileDialog.FileNames)
            {
                SelectedFileNames.Add(new CheckedListItem<string>(item, true));
            }
        }

        private void ExecuteSelectScript()
        {
            var openFileDialog = new OpenFileDialog
            {
                Filter = "JavaScript File (*.js)|*.js"
            };

            openFileDialog.ShowDialog();
            SelectedScript = openFileDialog.FileName;
        }

        private async void ExecuteTask(
            Field field = null, Script script = null)
        {
            IsBusy = true;
            HideMessage();
            var fileNames = from x in SelectedFileNames select x.Item;

            FileProcessor = new FileProcessor(
                fileNames.ToList(), Progress, field, script);

            try
            {
                await FileProcessor.Execute();
            }
            catch (OperationCanceledException)
            {
                ShowMessage("The operation was cancelled.");
            }

            IsBusy = false;
        }

        private void ExecuteTimeStampDay()
        {
            ExecuteTask(TimeStampField, TimeStampOnPrintDay);
        }

        private void ExecuteTimeStampMonth()
        {
            ExecuteTask(TimeStampField, TimeStampOnPrintMonth);
        }

        private IEnumerable<int> GetCustomPageNumbers()
        {
            if (SelectedFieldPages != Custom ||
                CustomPageNumbers.IsNullOrWhiteSpace())
            {
                return null;
            }

            var customPageNumbers = new List<int>();
            var customPageNumberStrings = CustomPageNumbers.Split(',');

            foreach (var customPageNumber in customPageNumberStrings)
            {
                int result;

                if (customPageNumber.TryParse(out result))
                {
                    customPageNumbers.Add(result);
                }
            }

            return customPageNumbers;
        }

        private void HandleProgressReport(
            ProgressReport progressReport)
        {
            var current = progressReport.Item1;
            var total = progressReport.Item2;
            ProgressPercent = current * 100 / total;
            ProgressText = $"{current} / {total}";
        }

        private void HideMessage()
        {
            Message = string.Empty;
            MessageIsVisible = false;
            MessageZIndex = -1;
        }

        private void NotifyProeprtyChanged(
            [CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(
                this, new PropertyChangedEventArgs(propertyName));
        }

        private void ShowMessage(string message)
        {
            Message = message + "\n\nDouble-click to dismiss.";
            MessageIsVisible = true;
            MessageZIndex = 1;
        }
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ Reviewing in some few hours \$\endgroup\$
    – Tolani
    Aug 10, 2016 at 16:16

1 Answer 1

2
\$\begingroup\$

A few comments on the FileProcessor...


Your code is really hard to follow because as to my taste you completely overuse the using static trick.


ConvertToPdf Method

var processingFileName = GetFileNameWithoutExtension(fileName) +                       PdfExtension;

var processingPath = Combine(ProcessingFolderPath, processingFileName);

var extension = GetExtension(fileName)?.ToLower();

if (extension.IsNullOrWhiteSpace())

You first try to get the file name without extension and then you check whether it has any... this can go wrong because if your file contains other period in its name the last part will be interpreted as an extension. You should also check the extension itself.


var extensionMapping = new Dictionary<string, Action>
{
  [WordExtension] = () =>
  {
      ConvertWordToPdf(fileName, processingPath);
  },
  [WordXmlExtension] = () =>
  {
      ConvertWordToPdf(fileName, processingPath);
  },
  [ExcelExtension] = () =>
  {
      ConvertExcelToPdf(fileName, processingPath);
  },
  [ExcelXmlExtension] = () =>
  {
      ConvertExcelToPdf(fileName, processingPath);
  },
  [PowerPointExtension] = () =>
  {
      ConvertPowerPointToPdf(fileName, processingPath);
  },
  [PowerPointXmlExtension] = () =>
  {
      ConvertPowerPointToPdf(fileName, processingPath);
  }
};

All these methods should be separate modules passed to the file processor via DI.


private static readonly string OutputFolderPath = Combine(
  GetFolderPath(MyDocuments), FolderName);

private static readonly string ProcessingFolderPath = Combine(
  GetFolderPath(ApplicationData), FolderName);

These should be parameters. You cannot test it reasonably with fixed paths.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.