/// <summary>
 /// Get and display the episode text if various conditions are met
 /// </summary>
 private void DisplayEpisodeTextInImageIfWarranted(int fileIndex)
 {
     if (Episodes.ShowEpisodes && this.IsDisplayingSingleImage())
     {
         if (Episodes.EpisodesDictionary.ContainsKey(fileIndex) == false)
         {
             Episodes.EpisodeGetEpisodesInRange(this.DataHandler.FileDatabase.FileTable, this.DataHandler.ImageCache.CurrentRow);
         }
         Tuple <int, int> episode = Episodes.EpisodesDictionary[fileIndex];
         if (episode.Item1 == int.MaxValue)
         {
             this.EpisodeText.Text = "Episode \u221E";
         }
         else
         {
             this.EpisodeText.Text = (episode.Item2 == 1) ? "Single" : String.Format("Episode {0}/{1}", episode.Item1, episode.Item2);
         }
         this.EpisodeText.Foreground = (episode.Item1 == 1) ? Brushes.Red : Brushes.Black;
         this.EpisodeText.Visibility = Visibility.Visible;
     }
     else
     {
         this.EpisodeText.Visibility = Visibility.Hidden;
     }
 }
Exemple #2
0
        public static void EpisodeGetEpisodesInRange(FileTable fileTable, int fileTableIndex, int maxRangeToSearch)
        {
            if (Episodes.EpisodesDictionary == null)
            {
                Episodes.Reset();
            }
            int index = fileTableIndex;

            // Ensure the argument is valid
            if (fileTable == null || index < 0 || index >= fileTable.RowCount)
            {
                return;
            }

            bool inRange = Episodes.EpisodeGetAroundIndex(fileTable, fileTableIndex, maxRangeToSearch, out int first, out int count);

            // foreach fileindex within the episode, ranging from first to last, add its episode information to the episode dictionary
            for (int i = 1; i <= count; i++)
            {
                int currentFileIndex = first + i - 1;
                if (!Episodes.EpisodesDictionary.ContainsKey(currentFileIndex))
                {
                    Tuple <int, int> tuple = inRange ? new Tuple <int, int>(i, count) : new Tuple <int, int>(int.MaxValue, int.MaxValue);
                    Episodes.EpisodesDictionary.Add(currentFileIndex, tuple);
                }
            }
        }
Exemple #3
0
        // View Episode helper function
        private void EpisodeShowNextOrPrevious_Click(DirectionEnum direction)
        {
            long currentFileID = this.DataHandler.ImageCache.Current.ID;
            bool result        = Episodes.GetIncrementToNextEpisode(this.DataHandler.FileDatabase.FileTable, this.DataHandler.FileDatabase.GetFileOrNextFileIndex(currentFileID), direction, out int increment);

            if (result == true)
            {
                if (Episodes.ShowEpisodes == false)
                {
                    // turn on Episode display if its not already on
                    this.EpisodeShowHide(true);
                }
                // At this point, the episodes should be showing and the increment amount should be reset (see the out parameter above)
                this.TryFileShowWithoutSliderCallback(direction, increment);
            }
        }
Exemple #4
0
        private void MenuItemEpisodeOptions_Click(object sender, RoutedEventArgs e)
        {
            EpisodeOptions episodeOptions = new EpisodeOptions(this.State.EpisodeTimeThreshold, this);
            bool?          result         = episodeOptions.ShowDialog();

            if (result == true)
            {
                // the time threshold has changed, so save its new state
                this.State.EpisodeTimeThreshold = episodeOptions.EpisodeTimeThreshold;
                Episodes.TimeThreshold          = this.State.EpisodeTimeThreshold; // so we don't have to pass it as a parameter
                Episodes.Reset();
            }

            if (this.IsDisplayingMultipleImagesInOverview())
            {
                this.MarkableCanvas.RefreshIfMultipleImagesAreDisplayed(false);
            }
            else
            {
                this.DisplayEpisodeTextInImageIfWarranted(this.DataHandler.ImageCache.CurrentRow);
            }
        }
        // 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
        }
Exemple #6
0
        public void Handle_PreviewKeyDown(KeyEventArgs currentKey, bool forceSendToMainWindow)
        {
            // Check the arguments for null
            ThrowIf.IsNullArgument(currentKey, nameof(currentKey));

            // First, try to interpret key as a possible valid quickpaste shortcut key.
            // If so, send it to the Quickpaste window and mark the event as handled.
            if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) &&
                ((currentKey.Key >= Key.D0 && currentKey.Key <= Key.D9) || (currentKey.Key >= Key.NumPad0 && currentKey.Key <= Key.NumPad9)))
            {
                if (this.quickPasteWindow != null && this.quickPasteWindow.Visibility == Visibility.Visible)
                {
                    // The quickpaste window is visible, and thus able to take shortcuts.
                    string key = new KeyConverter().ConvertToString(currentKey.Key);
                    if (key.StartsWith("NumPad"))
                    {
                        key = key.Remove(0, 6);
                    }
                    if (Int32.TryParse(key, out int shortcutIndex) && shortcutIndex != 0)
                    {
                        this.quickPasteWindow.TryQuickPasteShortcut(shortcutIndex);
                        currentKey.Handled = true;
                    }
                }
                return;
            }

            // Next, - but only if forceSendToMainWindow is true,
            // don't interpret keyboard shortcuts if the focus is on a control in the control grid, as the text entered may be directed
            // to the controls within it. That is, if a textbox or combo box has the focus, then take no as this is normal text input
            // and NOT a shortcut key.  Similarly, if a menu is displayed keys should be directed to the menu rather than interpreted as
            // shortcuts.
            if (forceSendToMainWindow == false && this.SendKeyToDataEntryControlOrMenu(currentKey))
            {
                return;
            }

            // Finally, test for other shortcut keys and take the appropriate action as needed
            DirectionEnum direction;
            int           keyRepeatCount = this.State.GetKeyRepeatCount(currentKey);

            switch (currentKey.Key)
            {
            case Key.B:                     // Save a Bookmark of the current pan / zoom level of the image
                this.MarkableCanvas.SetBookmark();
                break;

            case Key.Escape:
                this.TrySetKeyboardFocusToMarkableCanvas(false, currentKey);
                break;

            case Key.OemPlus:               // Restore the zoom level / pan coordinates of the bookmark
                this.MarkableCanvas.ApplyBookmark();
                break;

            case Key.OemMinus:              // Restore the zoom level / pan coordinates of the bookmark
                this.MarkableCanvas.ZoomOutAllTheWay();
                break;

            case Key.M:                     // Toggle the magnifying glass on and off
                this.MenuItemDisplayMagnifyingGlass_Click(this, null);
                break;

            case Key.U:                     // Increase the magnifing glass zoom level
                this.FilePlayer_Stop();     // In case the FilePlayer is going
                this.MarkableCanvas.MagnifierOrOffsetChangeZoomLevel(ZoomDirection.ZoomIn);
                break;

            case Key.D:                     // Decrease the magnifing glass zoom level
                this.FilePlayer_Stop();     // In case the FilePlayer is going
                this.MarkableCanvas.MagnifierOrOffsetChangeZoomLevel(ZoomDirection.ZoomOut);
                break;

            case Key.Right:                 // next /previous image
            case Key.Left:                  // previous image
                int increment = 1;
                this.FilePlayer_Stop();     // In case the FilePlayer is going
                direction = currentKey.Key == Key.Right ? DirectionEnum.Next : DirectionEnum.Previous;
                if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.LeftCtrl))
                {
                    long currentFileID = this.DataHandler.ImageCache.Current.ID;
                    bool result        = Episodes.GetIncrementToNextEpisode(this.DataHandler.FileDatabase.FileTable, this.DataHandler.FileDatabase.GetFileOrNextFileIndex(currentFileID), direction, out increment);
                    if (result == true)
                    {
                        if (Episodes.ShowEpisodes == false)
                        {
                            // turn on Episode display if its not already on
                            this.EpisodeShowHide(true);
                        }
                        // At this point, the episodes should be showing and the increment amount should be reset (see the out parameter above)
                    }
                }
                if (currentKey.IsRepeat == false || (currentKey.IsRepeat == true && keyRepeatCount % this.State.Throttles.RepeatedKeyAcceptanceInterval == 0))
                {
                    this.TryFileShowWithoutSliderCallback(direction, increment);
                }
                break;

            case Key.Up:                    // show visual difference to next image
                if (this.IsDisplayingMultipleImagesInOverview())
                {
                    this.FilePlayer.Direction = DirectionEnum.Previous;
                    this.FilePlayer_ScrollRow();
                }
                else
                {
                    this.FilePlayer_Stop();     // In case the FilePlayer is going
                    this.TryViewPreviousOrNextDifference();
                }
                break;

            case Key.Down:                  // show visual difference to previous image
                if (this.IsDisplayingMultipleImagesInOverview())
                {
                    this.FilePlayer.Direction = DirectionEnum.Next;
                    this.FilePlayer_ScrollRow();
                }
                else
                {
                    this.FilePlayer_Stop();     // In case the FilePlayer is going
                    this.TryViewCombinedDifference();
                }
                break;

            case Key.C:
                if (this.State.IsViewOnly == false)
                {
                    this.CopyPreviousValues_Click();
                }
                break;

            case Key.E:
                this.MenuItemEpisodeShowHide_Click(null, null);
                break;

            case Key.Q:
                // Toggle the QuickPaste window
                if (this.quickPasteWindow == null || (this.quickPasteWindow.Visibility != Visibility.Visible))
                {
                    if (this.State.IsViewOnly == false)
                    {
                        this.QuickPasteWindowShow();
                    }
                }
                else
                {
                    this.QuickPasteWindowHide();
                }
                break;

            case Key.Tab:
                this.FilePlayer_Stop();     // In case the FilePlayer is going
                this.MoveFocusToNextOrPreviousControlOrCopyPreviousButton(Keyboard.Modifiers == ModifierKeys.Shift);
                break;

            case Key.PageDown:
            case Key.PageUp:
                direction = currentKey.Key == Key.PageDown ? DirectionEnum.Next : DirectionEnum.Previous;
                if (this.IsDisplayingMultipleImagesInOverview())
                {
                    this.FilePlayer.Direction = direction;
                    this.FilePlayer_ScrollPage();
                }
                else
                {
                    this.FilePlayer_Stop();          // In case the FilePlayer is going
                    if (currentKey.IsRepeat == false || (currentKey.IsRepeat == true && keyRepeatCount % this.State.Throttles.RepeatedKeyAcceptanceInterval == 0))
                    {
                        this.TryFileShowWithoutSliderCallback(direction);
                    }
                }
                break;

            case Key.Home:
            case Key.End:
            {
                this.DataGridPane.IsActive = true;
                break;
            }

            default:
                return;
            }

            if (currentKey != null)
            {
                currentKey.Handled = true;
            }
        }