Esempio n. 1
0
        public ExifToolResponse SetExifInto(string path, Dictionary <string, string> data, bool overwriteOriginal = true)
        {
            // Check the arguments for null
            if (data == null)
            {
                // this should not happen
                TracePrint.PrintStackTrace(1);
                // throw new ArgumentNullException(nameof(data));
                // try this to indicate the failure case
                return(new ExifToolResponse(false, "data dictionary is null"));
            }

            if (!File.Exists(path))
            {
                return(new ExifToolResponse(false, $"'{path}' not found"));
            }

            var cmd = new StringBuilder();

            foreach (KeyValuePair <string, string> kv in data)
            {
                cmd.AppendFormat("-{0}={1}\n", kv.Key, kv.Value);
            }

            if (overwriteOriginal)
            {
                cmd.Append("-overwrite_original\n");
            }

            cmd.Append(path);
            var cmdRes = this.SendCommand(cmd.ToString());

            //if failed return as it is, if it's success must check the response
            return(cmdRes ? new ExifToolResponse(cmdRes.Result) : cmdRes);
        }
Esempio n. 2
0
        // All bitmap laoding eventually invokes this static function
        public static BitmapSource GetBitmapFromImageFile(string filePath, Nullable <int> desiredWidthOrHeight, ImageDisplayIntentEnum displayIntent, ImageDimensionEnum imageDimension, out bool isCorruptOrMissing)
        {
            isCorruptOrMissing = true;

            // BitmapCacheOption.None is significantly faster than other options.
            // However, it locks the file as it is being accessed (rather than a memory copy being created when using a cache)
            // This means we cannot do any file operations on it (such as deleting the currently displayed image) as it will produce an access violation.
            // This is ok for TransientLoading, which just temporarily displays the image
            BitmapCacheOption bitmapCacheOption = (displayIntent == ImageDisplayIntentEnum.Ephemeral) ? BitmapCacheOption.None : BitmapCacheOption.OnLoad;

            if (!System.IO.File.Exists(filePath))
            {
                return(Constant.ImageValues.FileNoLongerAvailable.Value);
            }
            try
            {
                // Exception workarounds to consider: see  http://faithlife.codes/blog/2010/07/exceptions_thrown_by_bitmapimage_and_bitmapframe/
                if (desiredWidthOrHeight.HasValue == false)
                {
                    // returns the full size bitmap
                    BitmapFrame frame = BitmapFrame.Create(new Uri(filePath), BitmapCreateOptions.None, bitmapCacheOption);
                    frame.Freeze();
                    isCorruptOrMissing = false;
                    return(frame);
                }

                BitmapImage bitmap = new BitmapImage();
                bitmap.BeginInit();
                if (imageDimension == ImageDimensionEnum.UseWidth)
                {
                    bitmap.DecodePixelWidth = desiredWidthOrHeight.Value;
                }
                else
                {
                    bitmap.DecodePixelHeight = desiredWidthOrHeight.Value;
                }
                bitmap.CacheOption = bitmapCacheOption;
                bitmap.UriSource   = new Uri(filePath);
                bitmap.EndInit();
                bitmap.Freeze();

                isCorruptOrMissing = false;
                return(bitmap);
            }
            catch (Exception exception)
            {
                // Optional messages for eventual debugging of catch errors,
                if (exception is InsufficientMemoryException)
                {
                    TracePrint.PrintMessage(String.Format("ImageRow/LoadBitmap: exception getting bitmap from file: {0}\n.** Insufficient Memory Exception: {1}.\n--------------\n**StackTrace: {2}.\nXXXXXXXXXXXXXX\n\n", filePath, exception.Message, exception.StackTrace));
                }
                else
                {
                    // TraceDebug.PrintMessage(String.Format("ImageRow/LoadBitmap: General exception: {0}\n.**Unkonwn exception getting bitmap from file: {1}.\n--------------\n**StackTrace: {2}.\nXXXXXXXXXXXXXX\n\n", filePath, exception.Message, exception.StackTrace));
                }
                isCorruptOrMissing = true;
                return(Constant.ImageValues.Corrupt.Value);
            }
        }
 private async Task FilesSelectAndShowAsync()
 {
     if (this.DataHandler == null || this.DataHandler.FileDatabase == null)
     {
         TracePrint.PrintMessage("FilesSelectAndShow: Expected a file database to be available.");
     }
     await this.FilesSelectAndShowAsync(this.DataHandler.FileDatabase.ImageSet.FileSelection).ConfigureAwait(true);
 }
Esempio n. 4
0
        public DataEntryChoice(ControlRow control, DataEntryControls styleProvider)
            : base(control, styleProvider, ControlContentStyleEnum.ChoiceComboBox, ControlLabelStyleEnum.DefaultLabel)
        {
            // The behaviour of the combo box
            this.ContentControl.Focusable           = true;
            this.ContentControl.IsEditable          = false;
            this.ContentControl.IsTextSearchEnabled = true;

            // Callback used to allow Enter to select the highlit item
            this.ContentControl.PreviewKeyDown += this.ContentCtl_PreviewKeyDown;

            // Add items to the combo box. If we have an  EmptyChoiceItem, then  add an 'empty string' to the end
            // Check the arguments for null
            List <string> choiceList;
            bool          includesEmptyChoice;

            if (control == null)
            {
                // this should not happen
                TracePrint.PrintStackTrace(1);
                choiceList          = new List <string>();
                includesEmptyChoice = true;
            }
            else
            {
                choiceList = control.GetChoices(out includesEmptyChoice);
            }
            ComboBoxItem cbi;

            foreach (string choice in choiceList)
            {
                cbi = new ComboBoxItem()
                {
                    Content = choice
                };
                this.ContentControl.Items.Add(cbi);
            }
            if (includesEmptyChoice)
            {
                // put empty choice at the beginning of the control below a separator for visual clarity
                cbi = new ComboBoxItem()
                {
                    Content = String.Empty
                };
                this.ContentControl.Items.Insert(0, cbi);
            }
            // We include an invisible ellipsis menu item. This allows us to display an ellipsis in the combo box text field
            // when multiple images with different values are selected
            cbi = new ComboBoxItem()
            {
                Content = Constant.Unicode.Ellipsis
            };
            this.ContentControl.Items.Insert(0, cbi);
            ((ComboBoxItem)this.ContentControl.Items[0]).Visibility = System.Windows.Visibility.Collapsed;
            this.ContentControl.SelectedIndex = 1;
        }
        public void RemoveMarker(Marker marker)
        {
            int index = this.Markers.IndexOf(marker);

            if (index == -1)
            {
                TracePrint.PrintMessage("RemoveMarker: Expected marker to be present in list, but its not there.");
                return;
            }
            this.Markers.RemoveAt(index);
        }
Esempio n. 6
0
        // Delete the file, where we also try to back it up by moving it into the Deleted folder
        // TODO File deletion backups is problematic as files in different relative paths could have the same file name (overwritting possible, ambiguity). Perhaps mirror the file structure as otherwise a previously deleted file could be overwritten
        // CODECLEANUP Should this method really be part of an image row?
        public bool TryMoveFileToDeletedFilesFolder(string folderPath)
        {
            string sourceFilePath = this.GetFilePath(folderPath);

            if (!System.IO.File.Exists(sourceFilePath))
            {
                return(false);  // If there is no source file, its a missing file so we can't back it up
            }

            // Create a new target folder, if necessary.
            string deletedFilesFolderPath = Path.Combine(folderPath, Constant.File.DeletedFilesFolder);

            if (!Directory.Exists(deletedFilesFolderPath))
            {
                Directory.CreateDirectory(deletedFilesFolderPath);
            }

            // Move the file to the backup location.
            string destinationFilePath = Path.Combine(deletedFilesFolderPath, this.File);

            if (System.IO.File.Exists(destinationFilePath))
            {
                try
                {
                    // Because move doesn't allow overwriting, delete the destination file if it already exists.
                    System.IO.File.Delete(sourceFilePath);
                    return(true);
                }
                catch (UnauthorizedAccessException exception)
                {
                    TracePrint.PrintMessage("Could not delete " + sourceFilePath + Environment.NewLine + exception.Message + ": " + exception.ToString());
                    return(false);
                }
            }
            try
            {
                System.IO.File.Move(sourceFilePath, destinationFilePath);
                return(true);
            }
            catch (Exception exception)
            {
                // This may occur if for some reason we could not move the file, for example, if we have loaded the image in a way that it locks the file.
                // I've changed image loading to avoid this, but its something to watch out for.
                TracePrint.PrintMessage("Could not move " + sourceFilePath + Environment.NewLine + exception.Message + ": " + exception.ToString());
                return(false);
            }
        }
        // Get the root folder name from the database, and check to see if its the same as the actual root folder.
        // If not, ask the user if he/she wants to update the database.
        private void CheckAndCorrectRootFolder(FileDatabase fileDatabase)
        {
            // Check the arguments for null
            if (fileDatabase == null)
            {
                // this should not happen
                // System.Diagnostics.Debug.Print("The fielDatabase was null and it shouldn't be");
                TracePrint.PrintStackTrace(1);
                // No-op
                return;
            }
            List <object> allRootFolderPaths = fileDatabase.GetDistinctValuesInColumn(Constant.DBTables.FileData, Constant.DatabaseColumn.Folder);

            if (allRootFolderPaths.Count < 1)
            {
                // System.Diagnostics.Debug.Print("Checking the root folder name in the database, but no entries were found. Perhaps the database is empty?");
                return;
            }

            // retrieve and compare the db and actual root folder path names. While there really should be only one entry in the allRootFolderPaths,
            // we still do a check in case there is more than one. If even one entry doesn't match, we use that entry to ask the user if he/she
            // wants to update the root folder to match the actual location of the root folder containing the template, data and image files.
            string actualRootFolderName = fileDatabase.FolderPath.Split(Path.DirectorySeparatorChar).Last();

            foreach (string databaseRootFolderName in allRootFolderPaths)
            {
                if (databaseRootFolderName.Equals(actualRootFolderName))
                {
                    continue;
                }
                else
                {
                    // We have at least one entry where there is a mismatch between the actual root folder and the stored root folder
                    // Consequently, ask the user if he/she wants to update the db entry
                    Dialog.UpdateRootFolder renameRootFolderDialog;
                    renameRootFolderDialog = new Dialog.UpdateRootFolder(this, databaseRootFolderName, actualRootFolderName);
                    bool?result = renameRootFolderDialog.ShowDialog();
                    if (result == true)
                    {
                        ColumnTuple columnToUpdate = new ColumnTuple(Constant.DatabaseColumn.Folder, actualRootFolderName);
                        fileDatabase.UpdateFiles(columnToUpdate);
                    }
                    return;
                }
            }
        }
Esempio n. 8
0
        public ExifToolResponse(string response)
        {
            // Check the arguments for null
            if (response == null)
            {
                // this should not happen
                TracePrint.PrintStackTrace(1);
                // throw new ArgumentNullException(nameof(response));
                // Treat it as a failure case?
                this.IsSuccess = false;
                this.Result    = String.Empty;
                return;
            }

            this.IsSuccess = response.ToLowerInvariant().Contains(ExifToolWrapper.SuccessMessage);
            this.Result    = response;
        }
        // Delete sub-menu opening
        private void MenuItemDelete_SubmenuOpening(object sender, RoutedEventArgs e)
        {
            try
            {
                // Temporarily set the DeleteFlag search term so that it will be used to chec for DeleteFlag = true
                SearchTerm currentSearchTerm = this.DataHandler.FileDatabase.CustomSelection.SearchTerms.First(term => term.DataLabel == Constant.DatabaseColumn.DeleteFlag);
                SearchTerm tempSearchTerm    = currentSearchTerm.Clone();
                currentSearchTerm.DatabaseValue   = "true";
                currentSearchTerm.UseForSearching = true;
                currentSearchTerm.Operator        = "=";

                //bool deletedImages = this.DataHandler.FileDatabase.ExistsRowThatMatchesSelectionForAllFilesOrConstrainedRelativePathFiles(FileSelectionEnum.MarkedForDeletion);
                //bool deletedImages = this.DataHandler.FileDatabase.CountAllFilesMatchingSelectionCondition(FileSelectionEnum.Custom) > 0;
                bool deletedImages = this.DataHandler.FileDatabase.ExistsFilesMatchingSelectionCondition(FileSelectionEnum.Custom);

                // Reset  the DeleteFlag search term to its previous values
                currentSearchTerm.DatabaseValue   = tempSearchTerm.DatabaseValue;
                currentSearchTerm.UseForSearching = tempSearchTerm.UseForSearching;
                currentSearchTerm.Operator        = tempSearchTerm.Operator;

                this.MenuItemDeleteFiles.IsEnabled        = deletedImages;
                this.MenuItemDeleteFilesAndData.IsEnabled = deletedImages;
                this.MenuItemDeleteFilesData.IsEnabled    = deletedImages;

                // Enable the delete current file option only if we are not on the thumbnail grid
                this.MenuItemDeleteCurrentFileAndData.IsEnabled = this.MarkableCanvas.IsThumbnailGridVisible == false; // Only show this option if the thumbnail grid is visible
                this.MenuItemDeleteCurrentFile.IsEnabled        = this.MarkableCanvas.IsThumbnailGridVisible == false && this.DataHandler.ImageCache.Current.IsDisplayable(this.FolderPath);
                this.MenuItemDeleteCurrentData.IsEnabled        = this.MarkableCanvas.IsThumbnailGridVisible == false;
            }
            catch (Exception exception)
            {
                TracePrint.PrintMessage(String.Format("Delete submenu failed to open in Delete_SubmenuOpening. {0}", exception.ToString()));

                // This function was blowing up on one user's machine, but not others.
                // I couldn't figure out why, so I just put this fallback in here to catch that unusual case.
                this.MenuItemDeleteFiles.IsEnabled              = true;
                this.MenuItemDeleteFilesAndData.IsEnabled       = true;
                this.MenuItemDeleteFilesData.IsEnabled          = true;
                this.MenuItemDeleteCurrentFile.IsEnabled        = true;
                this.MenuItemDeleteCurrentFileAndData.IsEnabled = true;
                this.MenuItemDeleteCurrentData.IsEnabled        = true;
            }
        }
Esempio n. 10
0
        private void MenuItemExportThisImage_Click(object sender, RoutedEventArgs e)
        {
            if (!this.DataHandler.ImageCache.Current.IsDisplayable(this.FolderPath))
            {
                // Can't export the currently displayed image as a file
                Dialogs.MenuFileCantExportCurrentImageDialog(this);
                return;
            }
            // Get the file name of the current image
            string sourceFile = this.DataHandler.ImageCache.Current.File;

            // Set up a Folder Browser with some instructions
            using (SaveFileDialog dialog = new SaveFileDialog()
            {
                Title = "Export a copy of the currently displayed file",
                Filter = String.Format("*{0}|*{0}", Path.GetExtension(this.DataHandler.ImageCache.Current.File)),
                FileName = sourceFile,
                OverwritePrompt = true
            })
            {
                // Display the Folder Browser dialog
                DialogResult result = dialog.ShowDialog();
                if (result == System.Windows.Forms.DialogResult.OK)
                {
                    // Set the source and destination file names, including the complete path
                    string sourcePath   = this.DataHandler.ImageCache.Current.GetFilePath(this.FolderPath);
                    string destFileName = dialog.FileName;

                    // Try to copy the source file to the destination, overwriting the destination file if it already exists.
                    // And giving some feedback about its success (or failure)
                    try
                    {
                        File.Copy(sourcePath, destFileName, true);
                        this.StatusBar.SetMessage(sourceFile + " copied to " + destFileName);
                    }
                    catch (Exception exception)
                    {
                        TracePrint.PrintMessage(String.Format("Copy of '{0}' to '{1}' failed. {2}", sourceFile, destFileName, exception.ToString()));
                        this.StatusBar.SetMessage(String.Format("Could not copy '{0}' for some reason.", sourceFile));
                    }
                }
            }
        }
Esempio n. 11
0
        /// <summary>
        /// Update the list of recent databases displayed under File -> Recent Databases.
        /// </summary>
        private void RecentFileSets_Refresh()
        {
            // remove image sets which are no longer present from the most recently used list
            // probably overkill to perform this check on every refresh rather than once at application launch, but it's not particularly expensive
            List <string> invalidPaths = new List <string>();

            foreach (string recentImageSetPath in this.State.MostRecentImageSets)
            {
                if (File.Exists(recentImageSetPath) == false)
                {
                    invalidPaths.Add(recentImageSetPath);
                }
            }

            foreach (string path in invalidPaths)
            {
                bool result = this.State.MostRecentImageSets.TryRemove(path);
                if (!result)
                {
                    TracePrint.PrintMessage(String.Format("Removal of image set '{0}' no longer present on disk unexpectedly failed.", path));
                }
            }

            // Enable the menu only when there are items in it and only if the load menu is also enabled (i.e., that we haven't loaded anything yet)
            this.MenuItemRecentImageSets.IsEnabled = this.State.MostRecentImageSets.Count > 0 && this.MenuItemLoadFiles.IsEnabled;
            this.MenuItemRecentImageSets.Items.Clear();

            // add menu items most recently used image sets
            int index = 1;

            foreach (string recentImageSetPath in this.State.MostRecentImageSets)
            {
                // Create a menu item for each path
                MenuItem recentImageSetItem = new MenuItem();
                recentImageSetItem.Click  += this.MenuItemRecentImageSet_Click;
                recentImageSetItem.Header  = String.Format("_{0} {1}", index++, recentImageSetPath);
                recentImageSetItem.ToolTip = recentImageSetPath;
                this.MenuItemRecentImageSets.Items.Add(recentImageSetItem);
            }
        }
Esempio n. 12
0
        // Transform the XML string (stored in the ImageSetTable) into a QuickPasteEntries data structure
        // Compare it to the actual controls, and alter the data structure if needed
        public static List <QuickPasteEntry> QuickPasteEntriesFromXML(FileDatabase fileDatabase, string xml)
        {
            List <QuickPasteEntry> quickPasteEntries = new List <QuickPasteEntry>();

            // Check the arguments for null
            if (fileDatabase == null)
            {
                // this should not happen
                TracePrint.PrintStackTrace(1);
                return(quickPasteEntries);
                // Not sure if the above return is effective. We could do the following instead
                // throw new ArgumentNullException(nameof(fileDatabase));
            }

            XDocument xDocument = XDocument.Parse(xml);

            IEnumerable entries =
                from r in xDocument.Descendants("Entry")
                select new QuickPasteEntry
            {
                Title = (string)r.Element("Title"),
                Items = (from v in r.Elements("Item")
                         select new QuickPasteItem
                {
                    DataLabel = (string)v.Element("DataLabel"),
                    Label = (string)v.Element("Label"),
                    Value = (string)v.Element("Value"),
                    Use = (bool)v.Element("Use"),
                    ControlType = (string)v.Element("ControlType")
                }).ToList()
            };


            foreach (QuickPasteEntry quickPasteEntry in entries)
            {
                quickPasteEntries.Add(quickPasteEntry);
            }
            quickPasteEntries = CheckAndSyncQuickPasteItemIfNeeded(fileDatabase, quickPasteEntries);
            return(quickPasteEntries);
        }
        public void LayoutAnchorable_PropertyChanging(object sender, System.ComponentModel.PropertyChangingEventArgs e)
        {
            // Check the arguments for null
            if (sender == null || e == null)
            {
                // this should not happen
                TracePrint.PrintStackTrace(1);
                // throw new ArgumentNullException(nameof(sender));
                // Try treating this as a no-op instead of a throw
                return;
            }

            LayoutAnchorable la = sender as LayoutAnchorable;

            if (la.ContentId == "ContentIDDataEntryControlPanel" && (e.PropertyName == Constant.AvalonDockValues.FloatingWindowFloatingHeightProperty || e.PropertyName == Constant.AvalonDockValues.FloatingWindowFloatingWidthProperty))
            {
                this.DockingManager_FloatingDataEntryWindowLimitSize();
            }
            // SAULXXX NOT SURE WHY I ADDED THIS HERE< BUT IT SEEMS TO HIDE THE FINDBOX WHEN THE USER FIRST INVOKES IT
            // IF IT BEHAVES OK< DELETE THIS COMMENTED OUT LINE
            // this.FindBoxSetVisibility(false);
        }
Esempio n. 14
0
        // Delete sub-menu opening
        private void MenuItemDelete_SubmenuOpening(object sender, RoutedEventArgs e)
        {
            try
            {
                bool deletedImages = this.DataHandler.FileDatabase.RowExistsWhere(FileSelectionEnum.MarkedForDeletion);
                this.MenuItemDeleteFiles.IsEnabled        = deletedImages;
                this.MenuItemDeleteFilesAndData.IsEnabled = deletedImages;

                // Enable the delete current file option only if we are not on the thumbnail grid
                this.MenuItemDeleteCurrentFileAndData.IsEnabled = this.MarkableCanvas.IsThumbnailGridVisible == false; // Only show this option if the thumbnail grid is visible
                this.MenuItemDeleteCurrentFile.IsEnabled        = this.MarkableCanvas.IsThumbnailGridVisible == false && this.DataHandler.ImageCache.Current.IsDisplayable(this.FolderPath);
            }
            catch (Exception exception)
            {
                TracePrint.PrintMessage(String.Format("Delete submenu failed to open in Delete_SubmenuOpening. {0}", exception.ToString()));

                // This function was blowing up on one user's machine, but not others.
                // I couldn't figure out why, so I just put this fallback in here to catch that unusual case.
                this.MenuItemDeleteFiles.IsEnabled              = true;
                this.MenuItemDeleteFilesAndData.IsEnabled       = true;
                this.MenuItemDeleteCurrentFile.IsEnabled        = true;
                this.MenuItemDeleteCurrentFileAndData.IsEnabled = true;
            }
        }
        // Returns:
        // - the list of files whose dates have changed
        // - a collection of feedback information for each file whose dates were changed, each row detailing the file name and how the dates were changed
        // - the number of missing Files, if any
        private List <ImageRow> GetImageRowsWithChangedDates(IProgress <ProgressBarArguments> progress, int count, TimeZoneInfo imageSetTimeZone, ObservableCollection <DateTimeFeedbackTuple> feedbackRows, out int missingFiles)
        {
            List <ImageRow> filesToAdjust = new List <ImageRow>();

            missingFiles = 0;
            for (int fileIndex = 0; fileIndex < count; ++fileIndex)
            {
                if (Token.IsCancellationRequested)
                {
                    // A cancel was requested. Clear all pending changes and abort
                    feedbackRows.Clear();
                    break;
                }

                // We will store the various times here
                ImageRow       file             = this.fileDatabase.FileTable[fileIndex];
                DateTimeOffset originalDateTime = file.DateTimeIncorporatingOffset;
                string         feedbackMessage  = string.Empty;

                try
                {
                    // Get the image (if its there), get the new dates/times, and add it to the list of images to be updated
                    // Note that if the image can't be created, we will just to the catch.
                    bool usingMetadataTimestamp = true;
                    if (file.FileExists(this.fileDatabase.FolderPath) == false)
                    {
                        // The file does not exist. Generate a feedback message
                        missingFiles++;
                    }
                    else
                    {
                        // Read the date from the file, and check to see if its different from the recorded date
                        DateTimeAdjustmentEnum dateTimeAdjustment = file.TryReadDateTimeOriginalFromMetadata(this.fileDatabase.FolderPath, imageSetTimeZone);
                        if (dateTimeAdjustment == DateTimeAdjustmentEnum.MetadataNotUsed)
                        {
                            // We couldn't read the metadata, so get a candidate date/time from the file info instead
                            file.SetDateTimeOffsetFromFileInfo(this.fileDatabase.FolderPath);
                            usingMetadataTimestamp = false;
                        }
                        DateTimeOffset rescannedDateTime = file.DateTimeIncorporatingOffset;
                        bool           sameDate          = rescannedDateTime.Date == originalDateTime.Date;
                        bool           sameTime          = rescannedDateTime.TimeOfDay == originalDateTime.TimeOfDay;
                        bool           sameUTCOffset     = rescannedDateTime.Offset == originalDateTime.Offset;

                        if (!(sameDate && sameTime && sameUTCOffset))
                        {
                            // Date has been updated - add it to the queue of files to be processed, and generate a feedback message.
                            filesToAdjust.Add(file);
                            feedbackMessage  = "\x2713"; // Checkmark
                            feedbackMessage += DateTimeHandler.ToStringDisplayDateTime(originalDateTime) + " \x2192 " + DateTimeHandler.ToStringDisplayDateTime(rescannedDateTime);
                            feedbackMessage += usingMetadataTimestamp ? " (read from metadata)" : " (read from file)";
                            feedbackRows.Add(new DateTimeFeedbackTuple(file.File, feedbackMessage));
                        }
                    }
                }
                catch (Exception exception)
                {
                    // This shouldn't happen, but just in case.
                    TracePrint.PrintMessage(string.Format("Unexpected exception processing '{0}' in DateTimeReread. {1}", file.File, exception.ToString()));
                    feedbackMessage += string.Format("\x2716 skipping: {0}", exception.Message);
                    feedbackRows.Add(new DateTimeFeedbackTuple(file.File, feedbackMessage));
                    break;
                }

                // Update the progress bar every time interval to indicate what file we are working on
                TimeSpan intervalFromLastRefresh = DateTime.Now - this.lastRefreshDateTime;
                if (intervalFromLastRefresh > Constant.ThrottleValues.ProgressBarRefreshInterval)
                {
                    int percentDone = Convert.ToInt32(fileIndex / Convert.ToDouble(count) * 100.0);
                    progress.Report(new ProgressBarArguments(percentDone, String.Format("Pass 1: Checking dates for {0} / {1} files", fileIndex, count), true, false));
                    Thread.Sleep(Constant.ThrottleValues.RenderingBackoffTime);
                    this.lastRefreshDateTime = DateTime.Now;
                }
            }
            return(filesToAdjust);
        }
Esempio n. 16
0
        /// <summary>
        /// Generate the controls based upon the control descriptions found in the template
        /// </summary>>
        public void CreateControls(FileDatabase database, DataEntryHandler dataEntryPropagator)
        {
            // Check the arguments for null
            ThrowIf.IsNullArgument(dataEntryPropagator, nameof(dataEntryPropagator));
            ThrowIf.IsNullArgument(database, nameof(database));

            // Depending on how the user interacts with the file import process image set loading can be aborted after controls are generated and then
            // another image set loaded.  Any existing controls therefore need to be cleared.
            this.Controls.Clear();
            this.ControlsByDataLabel.Clear();
            this.ControlGrid.Inlines.Clear();

            foreach (ControlRow control in database.Controls)
            {
                // no point in generating a control if it doesn't render in the UX
                if (control.Visible == false)
                {
                    continue;
                }

                DataEntryControl controlToAdd;
                if (control.Type == Constant.DatabaseColumn.DateTime)
                {
                    DataEntryDateTime dateTimeControl = new DataEntryDateTime(control, this);
                    controlToAdd = dateTimeControl;
                }
                else if (control.Type == Constant.DatabaseColumn.File ||
                         control.Type == Constant.DatabaseColumn.RelativePath ||
                         control.Type == Constant.DatabaseColumn.Folder ||
                         control.Type == Constant.DatabaseColumn.Date ||
                         control.Type == Constant.DatabaseColumn.Time ||
                         control.Type == Constant.Control.Note)
                {
                    // standard controls rendering as notes aren't editable by the user, so we don't need autocompletions on tht
                    Dictionary <string, string> autocompletions = null;
                    bool readOnly = control.Type != Constant.Control.Note;
                    if (readOnly == false)
                    {
                        autocompletions = new Dictionary <string, string>();
                    }
                    DataEntryNote noteControl = new DataEntryNote(control, autocompletions, this)
                    {
                        ContentReadOnly = readOnly
                    };
                    controlToAdd = noteControl;
                }
                else if (control.Type == Constant.Control.Flag || control.Type == Constant.DatabaseColumn.DeleteFlag)
                {
                    DataEntryFlag flagControl = new DataEntryFlag(control, this);
                    controlToAdd = flagControl;
                }
                else if (control.Type == Constant.Control.Counter)
                {
                    DataEntryCounter counterControl = new DataEntryCounter(control, this);
                    controlToAdd = counterControl;
                }
                else if (control.Type == Constant.Control.FixedChoice)
                {
                    DataEntryChoice choiceControl = new DataEntryChoice(control, this);
                    controlToAdd = choiceControl;
                }
                else if (control.Type == Constant.DatabaseColumn.ImageQuality)
                {
                    DataEntryChoice choiceControl = new DataEntryChoice(control, this);
                    choiceControl.HideItems(new List <string> {
                        FileSelectionEnum.Corrupted.ToString(), FileSelectionEnum.Missing.ToString()
                    });
                    controlToAdd = choiceControl;
                }
                else if (control.Type == Constant.DatabaseColumn.UtcOffset)
                {
                    DataEntryUtcOffset utcOffsetControl = new DataEntryUtcOffset(control, this)
                    {
                        ContentReadOnly = true
                    };
                    controlToAdd = utcOffsetControl;
                }
                else
                {
                    TracePrint.PrintMessage(String.Format("Unhandled control type {0} in CreateControls.", control.Type));
                    continue;
                }
                this.ControlGrid.Inlines.Add(controlToAdd.Container);
                this.Controls.Add(controlToAdd);
                this.ControlsByDataLabel.Add(control.DataLabel, controlToAdd);
            }
            // Redundant check as for some reason CA1062 was still showing up as a warning.
            ThrowIf.IsNullArgument(dataEntryPropagator, nameof(dataEntryPropagator));
            dataEntryPropagator.SetDataEntryCallbacks(this.ControlsByDataLabel);
            this.dataEntryHandler = dataEntryPropagator;
        }
        // PEFORMANCE FILES SELECT AND SHOW CALLED TOO OFTEN, GIVEN THAT IT IS A SLOW OPERATION
        private async Task FilesSelectAndShowAsync(long imageID, FileSelectionEnum selection)
        {
            // change selection
            // if the data grid is bound the file database automatically updates its contents on SelectFiles()
            if (this.DataHandler == null)
            {
                TracePrint.PrintMessage("FilesSelectAndShow() should not be reachable with a null data handler.  Is a menu item wrongly enabled?");;
            }
            if (this.DataHandler.FileDatabase == null)
            {
                TracePrint.PrintMessage("FilesSelectAndShow() should not be reachable with a null database.  Is a menu item wrongly enabled?");
            }

            // Select the files according to the given selection
            // Note that our check for missing actually checks to see if the file exists,
            // which is why its a different operation
            // PEFORMANCE - TWO  SLOW OPERATIONS: FilesSelectAndShow invoking this.dataHandler.FileDatabase.SelectFile / .SelectMissingFilesFromCurrentlySelectedFiles
            Mouse.OverrideCursor = Cursors.Wait;
            if (selection == FileSelectionEnum.Missing)
            {
                // PERFORMANCE this can be slow if there are many files, as it checks every single file in the current database selection to see if it exists
                // However, it is not a mainstream operation so can be considered a lower priority place for optimization
                bool anyFilesMissing = this.DataHandler.FileDatabase.SelectMissingFilesFromCurrentlySelectedFiles();
                if (anyFilesMissing == false)
                {
                    // No files were missing. Inform the user, and don't change anything.
                    Mouse.OverrideCursor = null;
                    Dialogs.FileSelectionNoFilesAreMissingDialog(this);
                    return;
                }
            }
            else
            {
                // If its a folder selection, record it so we can save it later in the image set table
                this.DataHandler.FileDatabase.ImageSet.SelectedFolder = selection == FileSelectionEnum.Folders
                    ? this.DataHandler.FileDatabase.GetSelectedFolder()
                    : String.Empty;
                // PERFORMANCE Select Files is a very slow operation as it runs a query over all files and returns everything it finds as datatables stored in memory.
                this.BusyCancelIndicator.EnableForSelection(true);

                await this.DataHandler.FileDatabase.SelectFilesAsync(selection).ConfigureAwait(true);

                this.BusyCancelIndicator.EnableForSelection(false);
                this.DataHandler.FileDatabase.BindToDataGrid();
            }
            Mouse.OverrideCursor = null;

            if ((this.DataHandler.FileDatabase.CountAllCurrentlySelectedFiles < 1) && (selection != FileSelectionEnum.All))
            {
                // Tell the user that we are resetting the selection to all files
                Dialogs.FileSelectionResettngSelectionToAllFilesDialog(this, selection);

                this.StatusBar.SetMessage("Resetting selection to All files.");
                selection = FileSelectionEnum.All;

                // PEFORMANCE: The standard select files operation in FilesSelectAndShow
                this.BusyCancelIndicator.EnableForSelection(true);
                await this.DataHandler.FileDatabase.SelectFilesAsync(selection).ConfigureAwait(true);

                this.BusyCancelIndicator.EnableForSelection(false);

                this.DataHandler.FileDatabase.BindToDataGrid();
            }

            // Change the selection to reflect what the user selected. Update the menu state accordingly
            // Set the checked status of the radio button menu items to the selection.
            string status;

            switch (selection)
            {
            case FileSelectionEnum.All:
                status = "All files";
                break;

            case FileSelectionEnum.Custom:
                status = "Custom selection";
                break;

            case FileSelectionEnum.Dark:
                status = "Dark files";
                break;

            case FileSelectionEnum.MarkedForDeletion:
                status = "Files marked for deletion";
                break;

            case FileSelectionEnum.Folders:
                status = "Files in a specific folder";
                break;

            case FileSelectionEnum.Missing:
                status = "Missing files";
                break;

            case FileSelectionEnum.Ok:
                status = "Non-dark files";
                break;

            default:
                throw new NotSupportedException(String.Format("Unhandled file selection {0}.", selection));
            }
            // Show feedback of the status description in both the status bar and the data entry control panel title
            this.StatusBar.SetView(status);
            this.DataEntryControlPanel.Title = "Data entry for " + status;

            // Reset the Episodes, as it may change based on the current selection
            Episodes.Reset();

            // Display the specified file or, if it's no longer selected, the next closest one
            // FileShow() handles empty image sets, so those don't need to be checked for here.
            // After a selection changes, set the slider to represent the index and the count of the current selection
            this.FileNavigatorSlider_EnableOrDisableValueChangedCallback(false);
            this.FileNavigatorSlider.Maximum = this.DataHandler.FileDatabase.CountAllCurrentlySelectedFiles;  // Reset the slider to the size of images in this set
            if (this.FileNavigatorSlider.Maximum <= 50)
            {
                this.FileNavigatorSlider.IsSnapToTickEnabled = true;
                this.FileNavigatorSlider.TickFrequency       = 1.0;
            }
            else
            {
                this.FileNavigatorSlider.IsSnapToTickEnabled = false;
                this.FileNavigatorSlider.TickFrequency       = 0.02 * this.FileNavigatorSlider.Maximum;
            }

            // Reset the ThumbnailGrid selection after every change in the selection
            if (this.IsDisplayingMultipleImagesInOverview())
            {
                this.MarkableCanvas.ThumbnailGrid.SelectInitialCellOnly();
            }

            this.DataEntryControls.AutocompletionPopulateAllNotesWithFileTableValues(this.DataHandler.FileDatabase);

            // Always force an update after a selection
            this.FileShow(this.DataHandler.FileDatabase.GetFileOrNextFileIndex(imageID), true);

            // Update the status bar accordingly
            this.StatusBar.SetCurrentFile(this.DataHandler.ImageCache.CurrentRow + 1);  // We add 1 because its a 0-based list
            this.StatusBar.SetCount(this.DataHandler.FileDatabase.CountAllCurrentlySelectedFiles);
            this.FileNavigatorSlider_EnableOrDisableValueChangedCallback(true);
            this.DataHandler.FileDatabase.ImageSet.FileSelection = selection;    // Remember the current selection
        }
Esempio n. 18
0
        /// <summary>
        /// Add user interface event handler callbacks for (possibly invisible) controls
        /// </summary>
        private void SetUserInterfaceCallbacks()
        {
            // Add data entry callbacks to all editable controls. When the user changes an image's attribute using a particular control,
            // the callback updates the matching field for that image in the database.
            DataEntryNote     date     = null;
            DataEntryDateTime dateTime = null;
            DataEntryNote     time     = null;

            foreach (KeyValuePair <string, DataEntryControl> pair in this.DataEntryControls.ControlsByDataLabel)
            {
                string controlType = this.DataHandler.FileDatabase.FileTableColumnsByDataLabel[pair.Key].ControlType;
                switch (controlType)
                {
                case Constant.Control.Counter:
                    DataEntryCounter counter = (DataEntryCounter)pair.Value;
                    counter.ContentControl.PreviewMouseDown += this.ContentControl_MouseDown;
                    counter.ContentControl.PreviewKeyDown   += this.ContentCtl_PreviewKeyDown;
                    counter.Container.MouseEnter            += this.CounterControl_MouseEnter;
                    counter.Container.MouseLeave            += this.CounterControl_MouseLeave;
                    counter.LabelControl.Click += this.CounterControl_Click;
                    break;

                case Constant.Control.Flag:
                case Constant.DatabaseColumn.DeleteFlag:
                    DataEntryFlag flag = (DataEntryFlag)pair.Value;
                    flag.ContentControl.PreviewMouseDown += this.ContentControl_MouseDown;
                    flag.ContentControl.PreviewKeyDown   += this.ContentCtl_PreviewKeyDown;
                    break;

                case Constant.Control.FixedChoice:
                case Constant.DatabaseColumn.ImageQuality:
                    DataEntryChoice choice = (DataEntryChoice)pair.Value;
                    choice.ContentControl.PreviewMouseDown += this.ContentControl_MouseDown;
                    choice.ContentControl.PreviewKeyDown   += this.ContentCtl_PreviewKeyDown;
                    break;

                case Constant.Control.Note:
                case Constant.DatabaseColumn.Date:
                case Constant.DatabaseColumn.File:
                case Constant.DatabaseColumn.Folder:
                case Constant.DatabaseColumn.RelativePath:
                case Constant.DatabaseColumn.Time:
                    DataEntryNote note = (DataEntryNote)pair.Value;
                    note.ContentControl.PreviewMouseDown += this.ContentControl_MouseDown;
                    note.ContentControl.PreviewKeyDown   += this.ContentCtl_PreviewKeyDown;
                    if (controlType == Constant.DatabaseColumn.Date)
                    {
                        date = note;
                    }
                    if (controlType == Constant.DatabaseColumn.Time)
                    {
                        time = note;
                    }
                    break;

                case Constant.DatabaseColumn.DateTime:
                    dateTime = (DataEntryDateTime)pair.Value;
                    dateTime.ContentControl.PreviewMouseDown += this.ContentControl_MouseDown;
                    dateTime.ContentControl.PreviewKeyDown   += this.ContentCtl_PreviewKeyDown;
                    break;

                case Constant.DatabaseColumn.UtcOffset:
                    DataEntryUtcOffset utcOffset = (DataEntryUtcOffset)pair.Value;
                    utcOffset.ContentControl.PreviewMouseDown += this.ContentControl_MouseDown;
                    utcOffset.ContentControl.PreviewKeyDown   += this.ContentCtl_PreviewKeyDown;
                    break;

                default:
                    TracePrint.PrintMessage(String.Format("Unhandled control type '{0}' in SetUserInterfaceCallbacks.", controlType));
                    break;
                }
            }

            // if needed, link date and time controls to datetime control
            if (dateTime != null && date != null)
            {
                dateTime.DateControl = date;
            }
            if (dateTime != null && time != null)
            {
                dateTime.TimeControl = time;
            }
        }