diff --git a/NAPS2.Lib.WinForms/Update/UpdateOperation.cs b/NAPS2.Lib.WinForms/Update/UpdateOperation.cs index ec0e20a8b..0072449e0 100644 --- a/NAPS2.Lib.WinForms/Update/UpdateOperation.cs +++ b/NAPS2.Lib.WinForms/Update/UpdateOperation.cs @@ -12,9 +12,9 @@ namespace NAPS2.Update; public class UpdateOperation : OperationBase { - private readonly ImageContext _imageContext; private readonly ErrorOutput _errorOutput; private readonly DesktopController _desktopController; + private readonly DesktopFormProvider _desktopFormProvider; private readonly ManualResetEvent _waitHandle = new ManualResetEvent(false); private WebClient? _client; @@ -35,11 +35,12 @@ public class UpdateOperation : OperationBase } } - public UpdateOperation(ImageContext imageContext, ErrorOutput errorOutput, DesktopController desktopController) + public UpdateOperation(ErrorOutput errorOutput, DesktopController desktopController, + DesktopFormProvider desktopFormProvider) { - _imageContext = imageContext; _errorOutput = errorOutput; _desktopController = desktopController; + _desktopFormProvider = desktopFormProvider; ProgressTitle = MiscResources.UpdateProgress; AllowBackground = true; @@ -56,7 +57,8 @@ public class UpdateOperation : OperationBase _update = updateInfo; _tempFolder = Path.Combine(Paths.Temp, Path.GetRandomFileName()); Directory.CreateDirectory(_tempFolder); - _tempPath = Path.Combine(_tempFolder, updateInfo.DownloadUrl.Substring(updateInfo.DownloadUrl.LastIndexOf('/') + 1)); + _tempPath = Path.Combine(_tempFolder, + updateInfo.DownloadUrl.Substring(updateInfo.DownloadUrl.LastIndexOf('/') + 1)); _client = new WebClient(); _client.DownloadProgressChanged += DownloadProgress; @@ -119,12 +121,8 @@ public class UpdateOperation : OperationBase InvokeFinished(); _waitHandle.Set(); } - var desktop = Application.OpenForms.OfType().FirstOrDefault(); - if (desktop != null) - { - _desktopController.SkipRecoveryCleanup = true; - desktop.Close(); - } + _desktopController.SkipRecoveryCleanup = true; + _desktopFormProvider.DesktopForm.Close(); } private void InstallExe() @@ -181,14 +179,14 @@ public class UpdateOperation : OperationBase private bool VerifySignature() { var cert = new X509Certificate2(ClientCreds.naps2_public); - var csp = (RSACryptoServiceProvider)cert.PublicKey.Key; + var csp = (RSACryptoServiceProvider) cert.PublicKey.Key; return csp.VerifyHash(_update.Sha1, CryptoConfig.MapNameToOID("SHA1"), _update.Signature); } private void DownloadProgress(object sender, DownloadProgressChangedEventArgs e) { - Status.CurrentProgress = (int)e.BytesReceived; - Status.MaxProgress = (int)e.TotalBytesToReceive; + Status.CurrentProgress = (int) e.BytesReceived; + Status.MaxProgress = (int) e.TotalBytesToReceive; InvokeStatusChanged(); } } \ No newline at end of file diff --git a/NAPS2.Lib.WinForms/WinForms/DesktopController.cs b/NAPS2.Lib.WinForms/WinForms/DesktopController.cs index 002790f5c..585aeee2e 100644 --- a/NAPS2.Lib.WinForms/WinForms/DesktopController.cs +++ b/NAPS2.Lib.WinForms/WinForms/DesktopController.cs @@ -1,6 +1,5 @@ using System.Threading; using System.Windows.Forms; -using NAPS2.EtoForms.Ui; using NAPS2.ImportExport; using NAPS2.ImportExport.Images; using NAPS2.Platform.Windows; @@ -8,7 +7,6 @@ using NAPS2.Recovery; using NAPS2.Remoting; using NAPS2.Scan; using NAPS2.Update; -using NAPS2.Wia; namespace NAPS2.WinForms; @@ -28,24 +26,26 @@ public class DesktopController private readonly Naps2Config _config; private readonly IOperationFactory _operationFactory; private readonly StillImage _stillImage; - private readonly IFormFactory _formFactory; - private readonly IProfileManager _profileManager; - private readonly IScanPerformer _scanPerformer; private readonly UpdateChecker _updateChecker; private readonly NotificationManager _notify; private readonly ImageTransfer _imageTransfer; private readonly ImageClipboard _imageClipboard; private readonly ImageListActions _imageListActions; private readonly WinFormsExportHelper _exportHelper; + private readonly DesktopImagesController _desktopImagesController; + private readonly DesktopScanController _desktopScanController; + private readonly DesktopFormProvider _desktopFormProvider; private bool _closed; public DesktopController(ScanningContext scanningContext, UiImageList imageList, RecoveryStorageManager recoveryStorageManager, ThumbnailRenderQueue thumbnailRenderQueue, OperationProgress operationProgress, Naps2Config config, IOperationFactory operationFactory, - StillImage stillImage, IFormFactory formFactory, IProfileManager profileManager, IScanPerformer scanPerformer, + StillImage stillImage, UpdateChecker updateChecker, NotificationManager notify, ImageTransfer imageTransfer, - ImageClipboard imageClipboard, ImageListActions imageListActions, WinFormsExportHelper exportHelper) + ImageClipboard imageClipboard, ImageListActions imageListActions, WinFormsExportHelper exportHelper, + DesktopImagesController desktopImagesController, DesktopScanController desktopScanController, + DesktopFormProvider desktopFormProvider) { _scanningContext = scanningContext; _imageList = imageList; @@ -55,21 +55,17 @@ public class DesktopController _config = config; _operationFactory = operationFactory; _stillImage = stillImage; - _formFactory = formFactory; - _profileManager = profileManager; - _scanPerformer = scanPerformer; _updateChecker = updateChecker; _notify = notify; _imageTransfer = imageTransfer; _imageClipboard = imageClipboard; _imageListActions = imageListActions; _exportHelper = exportHelper; + _desktopImagesController = desktopImagesController; + _desktopScanController = desktopScanController; + _desktopFormProvider = desktopFormProvider; } - public Form Form { get; set; } - - public Action SafeInvoke { get; set; } - public bool SkipRecoveryCleanup { get; set; } public async Task Initialize() @@ -124,7 +120,7 @@ public class DesktopController var update = task.Result; if (update != null) { - SafeInvoke(() => _notify.UpdateAvailable(_updateChecker, update)); + _notify.UpdateAvailable(_updateChecker, update); } }).AssertNoAwait(); } @@ -147,7 +143,7 @@ public class DesktopController // If NAPS2 was started by the scanner button, do the appropriate actions automatically if (_stillImage.ShouldScan) { - await ScanWithDevice(_stillImage.DeviceID!); + await _desktopScanController.ScanWithDevice(_stillImage.DeviceID!); } } @@ -216,8 +212,8 @@ public class DesktopController if (_operationProgress.ActiveOperations.Any()) { _operationProgress.ActiveOperations.ForEach(op => op.Cancel()); - Form.Hide(); - Form.ShowInTaskbar = false; + _desktopFormProvider.DesktopForm.Hide(); + _desktopFormProvider.DesktopForm.ShowInTaskbar = false; Task.Run(() => { var timeoutCts = new CancellationTokenSource(); @@ -230,7 +226,7 @@ public class DesktopController { } _closed = true; - SafeInvoke(Form.Close); + _desktopFormProvider.DesktopForm.SafeInvoke(_desktopFormProvider.DesktopForm.Close); }); return false; } @@ -245,18 +241,19 @@ public class DesktopController { if (msg.StartsWith(Pipes.MSG_SCAN_WITH_DEVICE, StringComparison.InvariantCulture)) { - SafeInvoke(async () => await ScanWithDevice(msg.Substring(Pipes.MSG_SCAN_WITH_DEVICE.Length))); + _desktopFormProvider.DesktopForm.SafeInvoke(async () => + await _desktopScanController.ScanWithDevice(msg.Substring(Pipes.MSG_SCAN_WITH_DEVICE.Length))); } if (msg.Equals(Pipes.MSG_ACTIVATE)) { - SafeInvoke(() => + _desktopFormProvider.DesktopForm.SafeInvoke(() => { - var form = Application.OpenForms.Cast
().Last(); - if (form.WindowState == FormWindowState.Minimized) + var formOnTop = Application.OpenForms.Cast().Last(); + if (formOnTop.WindowState == FormWindowState.Minimized) { - Win32.ShowWindow(form.Handle, Win32.ShowWindowCommands.Restore); + Win32.ShowWindow(formOnTop.Handle, Win32.ShowWindowCommands.Restore); } - form.Activate(); + formOnTop.Activate(); }); } }); @@ -277,7 +274,7 @@ public class DesktopController { // Allow scanned images to be recovered in case of an unexpected close var op = _operationFactory.Create(); - if (op.Start(ReceiveScannedImage(), + if (op.Start(_desktopImagesController.ReceiveScannedImage(), new RecoveryParams { ThumbnailSize = _config.Get(c => c.ThumbnailSize) })) { _operationProgress.ShowProgress(op); @@ -290,145 +287,10 @@ public class DesktopController _thumbnailRenderQueue.StartRendering(_imageList); } - private ScanParams DefaultScanParams() => - new ScanParams - { - NoAutoSave = _config.Get(c => c.DisableAutoSave), - DoOcr = _config.Get(c => c.EnableOcr) && _config.Get(c => c.OcrAfterScanning), - ThumbnailSize = _config.Get(c => c.ThumbnailSize) - }; - - private async Task ScanWithDevice(string deviceID) - { - Form.Activate(); - ScanProfile profile; - if (_profileManager.DefaultProfile?.Device?.ID == deviceID) - { - // Try to use the default profile if it has the right device - profile = _profileManager.DefaultProfile; - } - else - { - // Otherwise just pick any old profile with the right device - // Not sure if this is the best way to do it, but it's hard to prioritize profiles - profile = _profileManager.Profiles.FirstOrDefault(x => x.Device != null && x.Device.ID == deviceID); - } - if (profile == null) - { - if (_config.Get(c => c.NoUserProfiles) && _profileManager.Profiles.Any(x => x.IsLocked)) - { - return; - } - - // No profile for the device we're scanning with, so prompt to create one - var editSettingsForm = _formFactory.Create(); - editSettingsForm.ScanProfile = _config.Get(c => c.DefaultProfileSettings); - try - { - // Populate the device field automatically (because we can do that!) - using var deviceManager = new WiaDeviceManager(); - using var device = deviceManager.FindDevice(deviceID); - editSettingsForm.CurrentDevice = new ScanDevice(deviceID, device.Name()); - } - catch (WiaException) - { - } - editSettingsForm.ShowDialog(); - if (!editSettingsForm.Result) - { - return; - } - profile = editSettingsForm.ScanProfile; - _profileManager.Mutate(new ListMutation.Append(profile), - ListSelection.Empty()); - _profileManager.DefaultProfile = profile; - } - if (profile != null) - { - // We got a profile, yay, so we can actually do the scan now - var source = await _scanPerformer.PerformScan(profile, DefaultScanParams(), Form.Handle); - await source.ForEach(ReceiveScannedImage()); - Form.Activate(); - } - } - - public async Task ScanDefault() - { - if (_profileManager.DefaultProfile != null) - { - var source = - await _scanPerformer.PerformScan(_profileManager.DefaultProfile, DefaultScanParams(), Form.Handle); - await source.ForEach(ReceiveScannedImage()); - Form.Activate(); - } - else if (_profileManager.Profiles.Count == 0) - { - await ScanWithNewProfile(); - } - else - { - ShowProfilesForm(); - } - } - - public async Task ScanWithNewProfile() - { - var editSettingsForm = _formFactory.Create(); - editSettingsForm.ScanProfile = _config.Get(c => c.DefaultProfileSettings); - editSettingsForm.ShowDialog(); - if (!editSettingsForm.Result) - { - return; - } - _profileManager.Mutate(new ListMutation.Append(editSettingsForm.ScanProfile), - ListSelection.Empty()); - _profileManager.DefaultProfile = editSettingsForm.ScanProfile; - - var source = await _scanPerformer.PerformScan(editSettingsForm.ScanProfile, DefaultScanParams(), Form.Handle); - await source.ForEach(ReceiveScannedImage()); - Form.Activate(); - } - - /// - /// Constructs a receiver for scanned images. - /// This keeps images from the same source together, even if multiple sources are providing images at the same time. - /// - /// - private Action ReceiveScannedImage() - { - UiImage? last = null; - return scannedImage => - { - SafeInvoke(() => - { - lock (_imageList) - { - var uiImage = new UiImage(scannedImage); - _imageList.Mutate(new ImageListMutation.InsertAfter(uiImage, last)); - last = uiImage; - } - }); - }; - } - - public void ShowProfilesForm() - { - var form = _formFactory.Create(); - form.ImageCallback = ReceiveScannedImage(); - form.ShowModal(); - } - - public void ShowBatchScanForm() - { - var form = _formFactory.Create(); - form.ImageCallback = ReceiveScannedImage(); - form.ShowDialog(); - } - public void ImportFiles(IEnumerable files) { var op = _operationFactory.Create(); - if (op.Start(OrderFiles(files), ReceiveScannedImage(), + if (op.Start(OrderFiles(files), _desktopImagesController.ReceiveScannedImage(), new ImportParams { ThumbnailSize = _config.Get(c => c.ThumbnailSize) })) { _operationProgress.ShowProgress(op); @@ -446,22 +308,13 @@ public class DesktopController public void ImportDirect(ImageTransferData data, bool copy) { var op = _operationFactory.Create(); - if (op.Start(data, copy, ReceiveScannedImage(), + if (op.Start(data, copy, _desktopImagesController.ReceiveScannedImage(), new DirectImportParams { ThumbnailSize = _config.Get(c => c.ThumbnailSize) })) { _operationProgress.ShowProgress(op); } } - public async Task ScanWithProfile(ScanProfile profile) - { - _profileManager.DefaultProfile = profile; - - var source = await _scanPerformer.PerformScan(profile, DefaultScanParams(), Form.Handle); - await source.ForEach(ReceiveScannedImage()); - Form.Activate(); - } - public void Paste() { if (_imageTransfer.IsInClipboard()) @@ -503,28 +356,6 @@ public class DesktopController } } - public void PreviewImage() - { - if (_imageList.Selection.Any()) - { - using var viewer = _formFactory.Create(); - viewer.ImageList = _imageList; - // TODO: Fix this - // viewer.ImageIndex = SelectedIndices.First(); - // viewer.DeleteCallback = UpdateThumbnails; - viewer.SelectCallback = i => - { - if (_imageList.Selection.Count <= 1) - { - // TODO: Fix this - // SelectedIndices = new[] { i }; - //thumbnailList1.Items[i].EnsureVisible(); - } - }; - viewer.ShowDialog(); - } - } - public void ResetImage() { if (_imageList.Selection.Any()) @@ -538,16 +369,6 @@ public class DesktopController } } - public void OpenAbout() - { - _formFactory.Create().ShowModal(); - } - - public void OpenSettings() - { - // FormFactory.Create().ShowDialog(); - } - public async Task SavePDF(List images) { using var imagesToSave = images.Select(x => x.GetClonedImage()).ToDisposableList(); @@ -555,10 +376,7 @@ public class DesktopController { if (_config.Get(c => c.DeleteAfterSaving)) { - SafeInvoke(() => - { - _imageList.Mutate(new ImageListMutation.DeleteSelected(), ListSelection.From(images)); - }); + _imageList.Mutate(new ImageListMutation.DeleteSelected(), ListSelection.From(images)); } } } @@ -587,6 +405,7 @@ public class DesktopController { Multiselect = true, CheckFileExists = true, + // TODO: Move filter logic somewhere common Filter = MiscResources.FileTypeAllFiles + @"|*.*|" + MiscResources.FileTypePdf + @"|*.pdf|" + MiscResources.FileTypeImageFiles + diff --git a/NAPS2.Lib.WinForms/WinForms/DesktopFormProvider.cs b/NAPS2.Lib.WinForms/WinForms/DesktopFormProvider.cs new file mode 100644 index 000000000..1e347f2aa --- /dev/null +++ b/NAPS2.Lib.WinForms/WinForms/DesktopFormProvider.cs @@ -0,0 +1,6 @@ +namespace NAPS2.WinForms; + +public class DesktopFormProvider +{ + public FormBase DesktopForm { get; set; } +} \ No newline at end of file diff --git a/NAPS2.Lib.WinForms/WinForms/DesktopImagesController.cs b/NAPS2.Lib.WinForms/WinForms/DesktopImagesController.cs new file mode 100644 index 000000000..0626953b2 --- /dev/null +++ b/NAPS2.Lib.WinForms/WinForms/DesktopImagesController.cs @@ -0,0 +1,31 @@ +namespace NAPS2.WinForms; + +public class DesktopImagesController +{ + private readonly UiImageList _imageList; + + public DesktopImagesController(UiImageList imageList) + { + _imageList = imageList; + } + + /// + /// Constructs a receiver for scanned images. + /// This keeps images from the same source together, even if multiple sources are providing images at the same time. + /// + /// + public Action ReceiveScannedImage() + { + var lockObj = new object(); + UiImage? last = null; + return scannedImage => + { + lock (lockObj) + { + var uiImage = new UiImage(scannedImage); + _imageList.Mutate(new ImageListMutation.InsertAfter(uiImage, last)); + last = uiImage; + } + }; + } +} \ No newline at end of file diff --git a/NAPS2.Lib.WinForms/WinForms/DesktopScanController.cs b/NAPS2.Lib.WinForms/WinForms/DesktopScanController.cs new file mode 100644 index 000000000..c69a65a20 --- /dev/null +++ b/NAPS2.Lib.WinForms/WinForms/DesktopScanController.cs @@ -0,0 +1,134 @@ +using NAPS2.Scan; +using NAPS2.Wia; + +namespace NAPS2.WinForms; + +public class DesktopScanController +{ + private readonly Naps2Config _config; + private readonly IProfileManager _profileManager; + private readonly IFormFactory _formFactory; + private readonly IScanPerformer _scanPerformer; + private readonly DesktopImagesController _desktopImagesController; + private readonly DesktopSubFormController _desktopSubFormController; + private readonly DesktopFormProvider _desktopFormProvider; + + public DesktopScanController(Naps2Config config, IProfileManager profileManager, IFormFactory formFactory, + IScanPerformer scanPerformer, DesktopImagesController desktopImagesController, + DesktopSubFormController desktopSubFormController, DesktopFormProvider desktopFormProvider) + { + _config = config; + _profileManager = profileManager; + _formFactory = formFactory; + _scanPerformer = scanPerformer; + _desktopImagesController = desktopImagesController; + _desktopSubFormController = desktopSubFormController; + _desktopFormProvider = desktopFormProvider; + } + + private ScanParams DefaultScanParams() => + new() + { + NoAutoSave = _config.Get(c => c.DisableAutoSave), + DoOcr = _config.Get(c => c.EnableOcr) && _config.Get(c => c.OcrAfterScanning), + ThumbnailSize = _config.Get(c => c.ThumbnailSize) + }; + + public async Task ScanWithDevice(string deviceID) + { + _desktopFormProvider.DesktopForm.Activate(); + ScanProfile? profile; + if (_profileManager.DefaultProfile?.Device?.ID == deviceID) + { + // Try to use the default profile if it has the right device + profile = _profileManager.DefaultProfile; + } + else + { + // Otherwise just pick any old profile with the right device + // Not sure if this is the best way to do it, but it's hard to prioritize profiles + profile = _profileManager.Profiles.FirstOrDefault(x => x.Device != null && x.Device.ID == deviceID); + } + if (profile == null) + { + if (_config.Get(c => c.NoUserProfiles) && _profileManager.Profiles.Any(x => x.IsLocked)) + { + return; + } + + // No profile for the device we're scanning with, so prompt to create one + var editSettingsForm = _formFactory.Create(); + editSettingsForm.ScanProfile = _config.Get(c => c.DefaultProfileSettings); + try + { + // Populate the device field automatically (because we can do that!) + using var deviceManager = new WiaDeviceManager(); + using var device = deviceManager.FindDevice(deviceID); + editSettingsForm.CurrentDevice = new ScanDevice(deviceID, device.Name()); + } + catch (WiaException) + { + } + editSettingsForm.ShowDialog(); + if (!editSettingsForm.Result) + { + return; + } + profile = editSettingsForm.ScanProfile; + _profileManager.Mutate(new ListMutation.Append(profile), + ListSelection.Empty()); + _profileManager.DefaultProfile = profile; + } + if (profile != null) + { + // We got a profile, yay, so we can actually do the scan now + await DoScan(profile); + } + } + + public async Task ScanDefault() + { + if (_profileManager.DefaultProfile != null) + { + await DoScan(_profileManager.DefaultProfile); + } + else if (_profileManager.Profiles.Count == 0) + { + await ScanWithNewProfile(); + } + else + { + _desktopSubFormController.ShowProfilesForm(); + } + } + + public async Task ScanWithNewProfile() + { + var editSettingsForm = _formFactory.Create(); + editSettingsForm.ScanProfile = _config.Get(c => c.DefaultProfileSettings); + editSettingsForm.ShowDialog(); + if (!editSettingsForm.Result) + { + return; + } + _profileManager.Mutate(new ListMutation.Append(editSettingsForm.ScanProfile), + ListSelection.Empty()); + _profileManager.DefaultProfile = editSettingsForm.ScanProfile; + + await DoScan(editSettingsForm.ScanProfile); + } + + public async Task ScanWithProfile(ScanProfile profile) + { + _profileManager.DefaultProfile = profile; + await DoScan(profile); + } + + private async Task DoScan(ScanProfile profile) + { + var source = + await _scanPerformer.PerformScan(profile, DefaultScanParams(), _desktopFormProvider.DesktopForm.Handle); + await source.ForEach(_desktopImagesController.ReceiveScannedImage()); + _desktopFormProvider.DesktopForm.Activate(); + } +} \ No newline at end of file diff --git a/NAPS2.Lib.WinForms/WinForms/DesktopSubFormController.cs b/NAPS2.Lib.WinForms/WinForms/DesktopSubFormController.cs new file mode 100644 index 000000000..f12557a8c --- /dev/null +++ b/NAPS2.Lib.WinForms/WinForms/DesktopSubFormController.cs @@ -0,0 +1,76 @@ +using NAPS2.EtoForms.Ui; + +namespace NAPS2.WinForms; + +public class DesktopSubFormController +{ + private readonly IFormFactory _formFactory; + private readonly UiImageList _imageList; + private readonly DesktopImagesController _desktopImagesController; + + public DesktopSubFormController(IFormFactory formFactory, UiImageList imageList, + DesktopImagesController desktopImagesController) + { + _formFactory = formFactory; + _imageList = imageList; + _desktopImagesController = desktopImagesController; + } + + public void ShowImageForm() where T : ImageForm + { + var selection = _imageList.Selection.ToList(); + if (selection.Any()) + { + var form = _formFactory.Create(); + form.Image = selection.First(); + form.SelectedImages = selection.ToList(); + form.ShowDialog(); + } + } + + public void ShowProfilesForm() + { + var form = _formFactory.Create(); + form.ImageCallback = _desktopImagesController.ReceiveScannedImage(); + form.ShowModal(); + } + + public void ShowBatchScanForm() + { + var form = _formFactory.Create(); + form.ImageCallback = _desktopImagesController.ReceiveScannedImage(); + form.ShowDialog(); + } + + public void ShowViewerForm() + { + if (_imageList.Selection.Any()) + { + using var viewer = _formFactory.Create(); + viewer.ImageList = _imageList; + // TODO: Fix this + // viewer.ImageIndex = SelectedIndices.First(); + // viewer.DeleteCallback = UpdateThumbnails; + viewer.SelectCallback = i => + { + if (_imageList.Selection.Count <= 1) + { + // TODO: Fix this + // SelectedIndices = new[] { i }; + //thumbnailList1.Items[i].EnsureVisible(); + } + }; + viewer.ShowDialog(); + } + } + + public void ShowAboutForm() + { + _formFactory.Create().ShowModal(); + } + + public void ShowSettingsForm() + { + // FormFactory.Create().ShowDialog(); + } +} \ No newline at end of file diff --git a/NAPS2.Lib.WinForms/WinForms/FDesktop.cs b/NAPS2.Lib.WinForms/WinForms/FDesktop.cs index 730d01847..8cac53610 100644 --- a/NAPS2.Lib.WinForms/WinForms/FDesktop.cs +++ b/NAPS2.Lib.WinForms/WinForms/FDesktop.cs @@ -29,7 +29,10 @@ namespace NAPS2.WinForms private readonly ThumbnailRenderQueue _thumbnailRenderQueue; private readonly UiThumbnailProvider _thumbnailProvider; private readonly DesktopController _desktopController; + private readonly DesktopScanController _desktopScanController; private readonly ImageListActions _imageListActions; + private readonly DesktopFormProvider _desktopFormProvider; + private readonly DesktopSubFormController _desktopSubFormController; private WinFormsListView _listView; private ImageListSyncer? _imageListSyncer; @@ -51,7 +54,9 @@ namespace NAPS2.WinForms ThumbnailRenderQueue thumbnailRenderQueue, UiThumbnailProvider thumbnailProvider, DesktopController desktopController, - ImageListActions imageListActions) + DesktopScanController desktopScanController, + ImageListActions imageListActions, + DesktopFormProvider desktopFormProvider, DesktopSubFormController desktopSubFormController) { _toolbarFormatter = toolbarFormatter; _tesseractLanguageManager = tesseractLanguageManager; @@ -66,7 +71,10 @@ namespace NAPS2.WinForms _thumbnailRenderQueue = thumbnailRenderQueue; _thumbnailProvider = thumbnailProvider; _desktopController = desktopController; + _desktopScanController = desktopScanController; _imageListActions = imageListActions; + _desktopFormProvider = desktopFormProvider; + _desktopSubFormController = desktopSubFormController; InitializeComponent(); notify.ParentForm = this; @@ -82,6 +90,7 @@ namespace NAPS2.WinForms }); }; _profileManager.ProfilesUpdated += (_, _) => UpdateScanButton(); + _desktopFormProvider.DesktopForm = this; } protected override void OnLoad(object sender, EventArgs args) => PostInitializeComponent(); @@ -213,8 +222,6 @@ namespace NAPS2.WinForms new Eto.Forms.Application(Eto.Platforms.WinForms).Attach(); UpdateToolbar(); - _desktopController.Form = this; - _desktopController.SafeInvoke = SafeInvoke; await _desktopController.Initialize(); } @@ -304,7 +311,7 @@ namespace NAPS2.WinForms ImageScaling = ToolStripItemImageScaling.None }; AssignProfileShortcut(i, item); - item.Click += async (_, _) => await _desktopController.ScanWithProfile(profile); + item.Click += async (_, _) => await _desktopScanController.ScanWithProfile(profile); tsScan.DropDownItems.Insert(tsScan.DropDownItems.Count - staticButtonCount, item); i++; @@ -353,7 +360,7 @@ namespace NAPS2.WinForms _ksm.Assign("Ctrl+Down", _imageListActions.MoveDown); _ksm.Assign("Ctrl+Right", _imageListActions.MoveDown); _ksm.Assign("Ctrl+Shift+Del", tsClear); - _ksm.Assign("F1", _desktopController.OpenAbout); + _ksm.Assign("F1", _desktopSubFormController.ShowAboutForm); _ksm.Assign("Ctrl+OemMinus", btnZoomOut); _ksm.Assign("Ctrl+Oemplus", btnZoomIn); _ksm.Assign("Del", ctxDelete); @@ -365,7 +372,7 @@ namespace NAPS2.WinForms var ks = Config.Get(c => c.KeyboardShortcuts); - _ksm.Assign(ks.About, _desktopController.OpenAbout); + _ksm.Assign(ks.About, _desktopSubFormController.ShowAboutForm); _ksm.Assign(ks.BatchScan, tsBatchScan); _ksm.Assign(ks.Clear, tsClear); _ksm.Assign(ks.Delete, tsDelete); @@ -478,13 +485,13 @@ namespace NAPS2.WinForms #region Event Handlers - Toolbar - private async void tsScan_ButtonClick(object sender, EventArgs e) => await _desktopController.ScanDefault(); + private async void tsScan_ButtonClick(object sender, EventArgs e) => await _desktopScanController.ScanDefault(); - private async void tsNewProfile_Click(object sender, EventArgs e) => await _desktopController.ScanWithNewProfile(); + private async void tsNewProfile_Click(object sender, EventArgs e) => + await _desktopScanController.ScanWithNewProfile(); - private void tsBatchScan_Click(object sender, EventArgs e) => _desktopController.ShowBatchScanForm(); - - private void tsProfiles_Click(object sender, EventArgs e) => _desktopController.ShowProfilesForm(); + private void tsBatchScan_Click(object sender, EventArgs e) => _desktopSubFormController.ShowBatchScanForm(); + private void tsProfiles_Click(object sender, EventArgs e) => _desktopSubFormController.ShowProfilesForm(); private void tsOcr_Click(object sender, EventArgs e) { @@ -580,19 +587,25 @@ namespace NAPS2.WinForms private void tsClear_Click(object sender, EventArgs e) => _desktopController.Clear(); - private void tsAbout_Click(object sender, EventArgs e) => _desktopController.OpenAbout(); + private void tsAbout_Click(object sender, EventArgs e) => _desktopSubFormController.ShowAboutForm(); - private void tsSettings_Click(object sender, EventArgs e) => _desktopController.OpenSettings(); + private void tsSettings_Click(object sender, EventArgs e) => _desktopSubFormController.ShowSettingsForm(); #endregion #region Event Handlers - Save/Email Menus - private async void tsSavePDFAll_Click(object sender, EventArgs e) => await _desktopController.SavePDF(_imageList.Images); - private async void tsSavePDFSelected_Click(object sender, EventArgs e) => await _desktopController.SavePDF(_imageList.Selection.ToList()); - private async void tsPDFSettings_Click(object sender, EventArgs e) => FormFactory.Create().ShowDialog(); + private async void tsSavePDFAll_Click(object sender, EventArgs e) => + await _desktopController.SavePDF(_imageList.Images); - private async void tsSaveImagesAll_Click(object sender, EventArgs e) => await _desktopController.SaveImages(_imageList.Images); + private async void tsSavePDFSelected_Click(object sender, EventArgs e) => + await _desktopController.SavePDF(_imageList.Selection.ToList()); + + private async void tsPDFSettings_Click(object sender, EventArgs e) => + FormFactory.Create().ShowDialog(); + + private async void tsSaveImagesAll_Click(object sender, EventArgs e) => + await _desktopController.SaveImages(_imageList.Images); private async void tsSaveImagesSelected_Click(object sender, EventArgs e) => await _desktopController.SaveImages(_imageList.Selection.ToList()); @@ -600,8 +613,11 @@ namespace NAPS2.WinForms private void tsImageSettings_Click(object sender, EventArgs e) => FormFactory.Create().ShowDialog(); - private async void tsEmailPDFAll_Click(object sender, EventArgs e) => await _desktopController.EmailPDF(_imageList.Images); - private async void tsEmailPDFSelected_Click(object sender, EventArgs e) => await _desktopController.EmailPDF(_imageList.Selection.ToList()); + private async void tsEmailPDFAll_Click(object sender, EventArgs e) => + await _desktopController.EmailPDF(_imageList.Images); + + private async void tsEmailPDFSelected_Click(object sender, EventArgs e) => + await _desktopController.EmailPDF(_imageList.Selection.ToList()); private void tsPdfSettings2_Click(object sender, EventArgs e) => FormFactory.Create().ShowDialog(); @@ -613,25 +629,19 @@ namespace NAPS2.WinForms #region Event Handlers - Image Menu - private void tsView_Click(object sender, EventArgs e) => _desktopController.PreviewImage(); + private void tsView_Click(object sender, EventArgs e) => _desktopSubFormController.ShowViewerForm(); + private void tsCrop_Click(object sender, EventArgs e) => _desktopSubFormController.ShowImageForm(); - private void ShowImageForm() where T : ImageForm - { - var selection = _imageList.Selection.ToList(); - if (selection.Any()) - { - var form = FormFactory.Create(); - form.Image = selection.First(); - form.SelectedImages = selection.ToList(); - form.ShowDialog(); - } - } + private void tsBrightnessContrast_Click(object sender, EventArgs e) => + _desktopSubFormController.ShowImageForm(); - private void tsCrop_Click(object sender, EventArgs e) => ShowImageForm(); - private void tsBrightnessContrast_Click(object sender, EventArgs e) => ShowImageForm(); - private void tsHueSaturation_Click(object sender, EventArgs e) => ShowImageForm(); - private void tsBlackWhite_Click(object sender, EventArgs e) => ShowImageForm(); - private void tsSharpen_Click(object sender, EventArgs e) => ShowImageForm(); + private void tsHueSaturation_Click(object sender, EventArgs e) => + _desktopSubFormController.ShowImageForm(); + + private void tsBlackWhite_Click(object sender, EventArgs e) => + _desktopSubFormController.ShowImageForm(); + + private void tsSharpen_Click(object sender, EventArgs e) => _desktopSubFormController.ShowImageForm(); private void tsReset_Click(object sender, EventArgs e) => _desktopController.ResetImage(); #endregion @@ -642,7 +652,7 @@ namespace NAPS2.WinForms private async void tsRotateRight_Click(object sender, EventArgs e) => await _imageListActions.RotateRight(); private async void tsFlip_Click(object sender, EventArgs e) => await _imageListActions.Flip(); private void tsDeskew_Click(object sender, EventArgs e) => _imageListActions.Deskew(); - private void tsCustomRotation_Click(object sender, EventArgs e) => ShowImageForm(); + private void tsCustomRotation_Click(object sender, EventArgs e) => _desktopSubFormController.ShowImageForm(); #endregion @@ -669,7 +679,7 @@ namespace NAPS2.WinForms } private void ctxSelectAll_Click(object sender, EventArgs e) => _imageListActions.SelectAll(); - private void ctxView_Click(object sender, EventArgs e) => _desktopController.PreviewImage(); + private void ctxView_Click(object sender, EventArgs e) => _desktopSubFormController.ShowViewerForm(); private void ctxDelete_Click(object sender, EventArgs e) => _desktopController.Delete(); private async void ctxCopy_Click(object sender, EventArgs e) => await _desktopController.Copy(); @@ -735,7 +745,7 @@ namespace NAPS2.WinForms #region Drag/Drop - private void ListViewItemClicked(object? sender, EventArgs e) => _desktopController.PreviewImage(); + private void ListViewItemClicked(object? sender, EventArgs e) => _desktopSubFormController.ShowViewerForm(); private void ListViewSelectionChanged(object? sender, EventArgs e) { diff --git a/NAPS2.Lib.WinForms/WinForms/ImageForm.cs b/NAPS2.Lib.WinForms/WinForms/ImageForm.cs index dda766662..c00acdded 100644 --- a/NAPS2.Lib.WinForms/WinForms/ImageForm.cs +++ b/NAPS2.Lib.WinForms/WinForms/ImageForm.cs @@ -5,7 +5,7 @@ using Timer = System.Threading.Timer; namespace NAPS2.WinForms { - partial class ImageForm : FormBase + public partial class ImageForm : FormBase { private readonly ImageContext _imageContext; diff --git a/NAPS2.Lib.WinForms/WinForms/WinFormsDialogHelper.cs b/NAPS2.Lib.WinForms/WinForms/WinFormsDialogHelper.cs index f68190f90..8f15583da 100644 --- a/NAPS2.Lib.WinForms/WinForms/WinFormsDialogHelper.cs +++ b/NAPS2.Lib.WinForms/WinForms/WinFormsDialogHelper.cs @@ -17,6 +17,7 @@ public class WinFormsDialogHelper : DialogHelper { OverwritePrompt = false, AddExtension = true, + // TODO: Move filter logic somewhere common Filter = MiscResources.FileTypePdf + @"|*.pdf|" + MiscResources.FileTypeBmp + @"|*.bmp|" + MiscResources.FileTypeEmf + @"|*.emf|" + @@ -62,6 +63,7 @@ public class WinFormsDialogHelper : DialogHelper { OverwritePrompt = false, AddExtension = true, + // TODO: Move filter logic somewhere common Filter = MiscResources.FileTypeBmp + @"|*.bmp|" + MiscResources.FileTypeEmf + @"|*.emf|" + MiscResources.FileTypeExif + @"|*.exif|" + diff --git a/NAPS2.Lib.WinForms/WinForms/WinFormsExportHelper.cs b/NAPS2.Lib.WinForms/WinForms/WinFormsExportHelper.cs index e13997a08..3ea7acd64 100644 --- a/NAPS2.Lib.WinForms/WinForms/WinFormsExportHelper.cs +++ b/NAPS2.Lib.WinForms/WinForms/WinFormsExportHelper.cs @@ -6,6 +6,7 @@ using NAPS2.ImportExport.Pdf; namespace NAPS2.WinForms; +// TODO: Rename this ImageExportController or something public class WinFormsExportHelper { private readonly DialogHelper _dialogHelper; diff --git a/NAPS2.Sdk/Threading/Invoker.cs b/NAPS2.Sdk/Threading/Invoker.cs index a22516f79..92ed7433a 100644 --- a/NAPS2.Sdk/Threading/Invoker.cs +++ b/NAPS2.Sdk/Threading/Invoker.cs @@ -1,5 +1,6 @@ namespace NAPS2.Threading; +// TODO: Can we get rid of this static context? /// /// Synchronized access to the UI thread. ///