/// <summary>Correct for drifting clock times. Correction applied only to selected files.</summary>
 private async void MenuEditDateTimeLinearCorrection_Click(object sender, RoutedEventArgs e)
 {
     DateTimeLinearCorrection linearDateCorrection = new DateTimeLinearCorrection(this.dataHandler.FileDatabase, this);
     if (linearDateCorrection.Abort)
     {
         MessageBox messageBox = new MessageBox("Can't correct for clock drift.", this);
         messageBox.Message.Problem = "Can't correct for clock drift.";
         messageBox.Message.Reason = "All of the files selected have date/time fields whose contents are not recognizable as dates or times." + Environment.NewLine;
         messageBox.Message.Reason += "\u2022 dates should look like dd-MMM-yyyy e.g., 16-Jan-2016" + Environment.NewLine;
         messageBox.Message.Reason += "\u2022 times should look like HH:mm:ss using 24 hour time e.g., 01:05:30 or 13:30:00";
         messageBox.Message.Result = "Date correction will be aborted and nothing will be changed.";
         messageBox.Message.Hint = "Check the format of your dates and times. You may also want to change your selection if you're not viewing All files.";
         messageBox.Message.StatusImage = MessageBoxImage.Error;
         messageBox.ShowDialog();
         return;
     }
     await this.ShowBulkFileEditDialogAsync(linearDateCorrection);
 }
        public void Carnassial()
        {
            // open, do nothing, close
            using (CarnassialWindow carnassial = new CarnassialWindow())
            {
                carnassial.Show();
                this.WaitForRenderingComplete();
                carnassial.Close();
                this.WaitForRenderingComplete();
            }

            // create template database and remove any image database from previous test executions
            string templateDatabaseFilePath;
            using (TemplateDatabase templateDatabase = this.CreateTemplateDatabase(TestConstant.File.DefaultTemplateDatabaseFileName))
            {
                templateDatabaseFilePath = templateDatabase.FilePath;
            }

            string fileDatabaseFilePath = Path.Combine(Path.GetDirectoryName(templateDatabaseFilePath), Path.GetFileNameWithoutExtension(templateDatabaseFilePath) + Constant.File.FileDatabaseFileExtension);
            if (File.Exists(fileDatabaseFilePath))
            {
                File.Delete(fileDatabaseFilePath);
            }

            // open, load database by scanning folder, move through images, close
            // The threading model for this is somewhat involved.  The test thread is the UI thread and therefore must drive the dispatcher.  This means the test
            // thread locks into UI message pumping when modal dialog is displayed, such as when loading files from a directory pops the file count summary upon
            // completion.  The test must therefore spin up a separate thread to close the dialogs and allow the main test thread to return from the dispatcher
            // and resume test execution.  If something jams up on the dialog handler thread Visual Studio may still consider the test running when also attached
            // as a debugger even if the test thread has completed.
            using (CarnassialWindow carnassial = new CarnassialWindow())
            {
                // show main window
                carnassial.Show();
                this.WaitForRenderingComplete();

                // start thread for handling file dialogs
                CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
                Task dialogDismissal = Task.Run(() =>
                {
                    AutomationElement carnassialAutomation = AutomationElement.RootElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.AutomationIdProperty, TestConstant.CarnassialAutomationID));
                    InvokePattern ambiguousDatesOkButton;
                    if (this.TryFindDialogOkButton(carnassialAutomation, cancellationTokenSource.Token, TestConstant.MessageBoxAutomationID, out ambiguousDatesOkButton))
                    {
                        ambiguousDatesOkButton.Invoke();
                    }

                    InvokePattern fileCountsOkButton;
                    if (this.TryFindDialogOkButton(carnassialAutomation, cancellationTokenSource.Token, TestConstant.FileCountsAutomationID, out fileCountsOkButton))
                    {
                        fileCountsOkButton.Invoke();
                    }
                }, cancellationTokenSource.Token);

                // import files from directory
                Task<bool> loadFolder = null;
                Dispatcher.CurrentDispatcher.Invoke(() =>
                {
                    loadFolder = carnassial.TryOpenTemplateAndBeginLoadFoldersAsync(templateDatabaseFilePath);
                });
                this.WaitForFolderLoadComplete(loadFolder);

                // verify import succeeded
                PrivateObject carnassialAccessor = new PrivateObject(carnassial);
                DataEntryHandler dataHandler = (DataEntryHandler)carnassialAccessor.GetField(TestConstant.DataHandlerFieldName);
                Assert.IsTrue(dataHandler.FileDatabase.CurrentlySelectedFileCount == 2);
                Assert.IsNotNull(dataHandler.ImageCache.Current);

                // verify forward and backward moves of the displayed image
                DispatcherOperation<Task> moveForward = carnassial.Dispatcher.InvokeAsync(async () =>
                {
                    await carnassial.ShowFileWithoutSliderCallbackAsync(true, ModifierKeys.None);
                    await carnassial.ShowFileWithoutSliderCallbackAsync(true, ModifierKeys.None);
                });
                this.WaitForRenderingComplete();
                DispatcherOperation<Task> moveBackwards = carnassial.Dispatcher.InvokeAsync(async () =>
                {
                    await carnassial.ShowFileWithoutSliderCallbackAsync(false, ModifierKeys.None);
                    await carnassial.ShowFileWithoutSliderCallbackAsync(false, ModifierKeys.None);
                });
                this.WaitForRenderingComplete();

                if (cancellationTokenSource.Token.CanBeCanceled)
                {
                    cancellationTokenSource.Cancel();
                }
                carnassial.Close();
            }

            // open, load existing database, pop dialogs, close
            using (CarnassialWindow carnassial = new CarnassialWindow())
            {
                carnassial.Show();
                this.WaitForRenderingComplete();

                Task<bool> loadFolder = null;
                Dispatcher.CurrentDispatcher.Invoke(() =>
                {
                    loadFolder = carnassial.TryOpenTemplateAndBeginLoadFoldersAsync(templateDatabaseFilePath);
                });
                this.WaitForFolderLoadComplete(loadFolder);

                PrivateObject carnassialAccessor = new PrivateObject(carnassial);
                DataEntryHandler dataHandler = (DataEntryHandler)carnassialAccessor.GetField(TestConstant.DataHandlerFieldName);
                Assert.IsTrue(dataHandler.FileDatabase.CurrentlySelectedFileCount > 0);
                Assert.IsNotNull(dataHandler.ImageCache.Current);

                this.ShowDialog(new About(carnassial));
                CarnassialState state = (CarnassialState)carnassialAccessor.GetField("state");
                this.ShowDialog(new AdvancedCarnassialOptions(state, carnassial.MarkableCanvas, carnassial));
                this.ShowDialog(new ChooseFileDatabase(new string[] { TestConstant.File.DefaultNewFileDatabaseFileName }, TestConstant.File.DefaultTemplateDatabaseFileName, carnassial));

                this.ShowDialog(new Dialog.CustomSelection(dataHandler.FileDatabase, carnassial));
                using (DarkImagesThreshold darkThreshold = new DarkImagesThreshold(dataHandler.FileDatabase, dataHandler.ImageCache.CurrentRow, new CarnassialState(), carnassial))
                {
                    this.ShowDialog(darkThreshold);
                }

                this.ShowDialog(new DateCorrectAmbiguous(dataHandler.FileDatabase, carnassial));
                this.ShowDialog(new DateDaylightSavingsTimeCorrection(dataHandler.FileDatabase, dataHandler.ImageCache, carnassial));

                DateTimeFixedCorrection clockSetCorrection = new DateTimeFixedCorrection(dataHandler.FileDatabase, dataHandler.ImageCache.Current, carnassial);
                this.ShowDialog(clockSetCorrection);

                DateTimeLinearCorrection clockDriftCorrection = new DateTimeLinearCorrection(dataHandler.FileDatabase, carnassial);
                Assert.IsTrue(clockDriftCorrection.Abort == (dataHandler.ImageCache.Current == null));
                this.ShowDialog(clockDriftCorrection);

                this.ShowDialog(new DateTimeRereadFromFiles(dataHandler.FileDatabase, carnassial));
                this.ShowDialog(new DateTimeSetTimeZone(dataHandler.FileDatabase, dataHandler.ImageCache.Current, carnassial));
                this.ShowDialog(new FileCountsByQuality(dataHandler.FileDatabase.GetFileCountsBySelection(), carnassial));
                this.ShowDialog(new EditLog(dataHandler.FileDatabase.ImageSet.Log, carnassial));

                this.ShowDialog(new PopulateFieldWithMetadata(dataHandler.FileDatabase, dataHandler.ImageCache.Current.GetFilePath(dataHandler.FileDatabase.FolderPath), carnassial));
                this.ShowDialog(new RenameFileDatabaseFile(dataHandler.FileDatabase.FileName, carnassial));
                this.ShowDialog(new TemplateSynchronization(dataHandler.FileDatabase.ControlSynchronizationIssues, carnassial));

                MessageBox okMessageBox = this.CreateMessageBox(carnassial, MessageBoxButton.OK, MessageBoxImage.Error);
                this.ShowDialog(okMessageBox);
                MessageBox okCancelMessageBox = this.CreateMessageBox(carnassial, MessageBoxButton.OKCancel, MessageBoxImage.Information);
                this.ShowDialog(okCancelMessageBox);
                MessageBox yesNoMessageBox = this.CreateMessageBox(carnassial, MessageBoxButton.YesNo, MessageBoxImage.Question);
                this.ShowDialog(yesNoMessageBox);

                carnassial.Close();
            }
        }