mirror of
https://github.com/cyanfish/naps2.git
synced 2024-08-16 18:50:45 +03:00
Fix various warnings
This commit is contained in:
parent
2fdc5fbbf9
commit
3cc922ecdd
@ -6,11 +6,12 @@ using Xunit;
|
||||
|
||||
namespace NAPS2.App.Tests.Appium;
|
||||
|
||||
#pragma warning disable CS0162
|
||||
[Collection("appium")]
|
||||
public class ScanAndSaveTests : AppiumTests
|
||||
{
|
||||
private const string WIA_DEVICE_NAME = "";
|
||||
private const string TWAIN_DEVICE_NAME = "Canon MP495 ser";
|
||||
private const string TWAIN_DEVICE_NAME = "";
|
||||
|
||||
[VerifyTheory(AllowDebug = true)]
|
||||
[ClassData(typeof(AppiumTestData))]
|
||||
|
@ -69,7 +69,7 @@ public class EsclClient
|
||||
response.EnsureSuccessStatusCode();
|
||||
return new EsclJob
|
||||
{
|
||||
Uri = response.Headers.Location
|
||||
Uri = response.Headers.Location!
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace NAPS2.Util;
|
||||
|
||||
#pragma warning disable CS0162
|
||||
public class LeakTracer
|
||||
{
|
||||
private const bool ENABLE_TRACING = false;
|
||||
|
@ -52,7 +52,7 @@ public class ProfileManagerTests : ContextualTests
|
||||
Assert.Single(profiles);
|
||||
|
||||
Assert.Equal("test_driver", profiles[0].DriverName);
|
||||
Assert.Equal("test_id", profiles[0].Device?.ID);
|
||||
Assert.Equal("test_id", profiles[0].Device?.Id);
|
||||
Assert.Equal(2, profiles[0].Version);
|
||||
Assert.Null(profiles[0].UpgradedFrom);
|
||||
}
|
||||
@ -67,7 +67,7 @@ public class ProfileManagerTests : ContextualTests
|
||||
Assert.Single(profiles);
|
||||
|
||||
Assert.Equal("wia", profiles[0].DriverName);
|
||||
Assert.Equal("test_id", profiles[0].Device?.ID);
|
||||
Assert.Equal("test_id", profiles[0].Device?.Id);
|
||||
Assert.Equal(ScanDpi.Dpi200, profiles[0].Resolution);
|
||||
Assert.Equal(2, profiles[0].Version);
|
||||
Assert.Equal(0, profiles[0].UpgradedFrom);
|
||||
@ -83,7 +83,7 @@ public class ProfileManagerTests : ContextualTests
|
||||
Assert.Single(profiles);
|
||||
|
||||
Assert.Equal("wia", profiles[0].DriverName);
|
||||
Assert.Equal("test_id", profiles[0].Device?.ID);
|
||||
Assert.Equal("test_id", profiles[0].Device?.Id);
|
||||
Assert.Equal(ScanDpi.Dpi200, profiles[0].Resolution);
|
||||
Assert.Equal(2, profiles[0].Version);
|
||||
Assert.Equal(1, profiles[0].UpgradedFrom);
|
||||
@ -99,7 +99,7 @@ public class ProfileManagerTests : ContextualTests
|
||||
Assert.Single(profiles);
|
||||
|
||||
Assert.Equal("twain", profiles[0].DriverName);
|
||||
Assert.Equal("test_id", profiles[0].Device?.ID);
|
||||
Assert.Equal("test_id", profiles[0].Device?.Id);
|
||||
Assert.True(profiles[0].UseNativeUI);
|
||||
Assert.Equal(2, profiles[0].Version);
|
||||
Assert.Equal(1, profiles[0].UpgradedFrom);
|
||||
|
@ -50,7 +50,7 @@ public static class WinFormsEntryPoint
|
||||
application.MainForm = desktop;
|
||||
desktop.Show();
|
||||
var appContext = new wf.ApplicationContext(desktop.ToNative());
|
||||
Invoker.Current = new WinFormsInvoker(appContext);
|
||||
Invoker.Current = new WinFormsInvoker(() => appContext.MainForm!);
|
||||
WinFormsDesktopForm.ApplicationContext = appContext;
|
||||
var setOptionsMethod =
|
||||
typeof(ApplicationHandler).GetMethod("SetOptions", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using NAPS2.EtoForms.WinForms;
|
||||
using NAPS2.Modules;
|
||||
using NAPS2.Scan.Internal.Twain;
|
||||
using NAPS2.WinForms;
|
||||
@ -22,7 +23,7 @@ public static class WindowsWorkerEntryPoint
|
||||
// Set up a form for the worker process
|
||||
// A parent form is needed for some operations, namely 64-bit TWAIN scanning
|
||||
var form = new BackgroundForm();
|
||||
Invoker.Current = form;
|
||||
Invoker.Current = new WinFormsInvoker(() => form);
|
||||
TwainHandleManager.Factory = () => new WinFormsTwainHandleManager(form);
|
||||
|
||||
return WorkerEntryPoint.Run(args, new GdiModule(), () => Application.Run(form), () => form.Close());
|
||||
|
@ -13,13 +13,12 @@ namespace NAPS2.EtoForms.Ui;
|
||||
|
||||
public class WinFormsDesktopForm : DesktopForm
|
||||
{
|
||||
public static wf.ApplicationContext ApplicationContext { get; set; }
|
||||
public static wf.ApplicationContext? ApplicationContext { get; set; }
|
||||
|
||||
private readonly ToolbarFormatter _toolbarFormatter = new(new StringWrapper());
|
||||
private readonly wf.Form _form;
|
||||
private wf.ToolStrip _toolStrip = null!;
|
||||
private wf.ToolStripContainer _container = null!;
|
||||
private wf.Button btnZoomIn, btnZoomOut, btnZoomMouseCatcher;
|
||||
|
||||
public WinFormsDesktopForm(
|
||||
Naps2Config config,
|
||||
@ -67,14 +66,14 @@ public class WinFormsDesktopForm : DesktopForm
|
||||
// Disabled buttons don't prevent click events from being sent to the listview below the button, so without this
|
||||
// "mouse catcher" control you could e.g. spam click zoom out until it's maxed and then accidentally keep
|
||||
// clicking and change the listview selection.
|
||||
btnZoomMouseCatcher = new wf.Button
|
||||
var mouseCatcher = new wf.Button
|
||||
{
|
||||
BackColor = Color.White,
|
||||
Size = new Size(45, 23),
|
||||
FlatStyle = wf.FlatStyle.Flat
|
||||
};
|
||||
return L.Overlay(
|
||||
btnZoomMouseCatcher.ToEto(),
|
||||
mouseCatcher.ToEto(),
|
||||
base.GetZoomButtons()
|
||||
);
|
||||
}
|
||||
@ -84,6 +83,11 @@ public class WinFormsDesktopForm : DesktopForm
|
||||
protected override void SetMainForm(Form newMainForm)
|
||||
{
|
||||
base.SetMainForm(newMainForm);
|
||||
if (ApplicationContext == null)
|
||||
{
|
||||
Log.Error("ApplicationContext should not be null");
|
||||
return;
|
||||
}
|
||||
ApplicationContext.MainForm = newMainForm.ToSWF();
|
||||
}
|
||||
|
||||
|
@ -4,22 +4,22 @@ namespace NAPS2.EtoForms.WinForms;
|
||||
|
||||
public class WinFormsInvoker : IInvoker
|
||||
{
|
||||
private readonly ApplicationContext _appContext;
|
||||
private readonly Func<Form> _formFunc;
|
||||
|
||||
public WinFormsInvoker(ApplicationContext appContext)
|
||||
public WinFormsInvoker(Func<Form> formFunc)
|
||||
{
|
||||
_appContext = appContext;
|
||||
_formFunc = formFunc;
|
||||
}
|
||||
|
||||
public void Invoke(Action action)
|
||||
{
|
||||
_appContext.MainForm.Invoke(action);
|
||||
_formFunc().Invoke(action);
|
||||
}
|
||||
|
||||
// TODO: Maybe these can be extension methods?
|
||||
public T InvokeGet<T>(Func<T> func)
|
||||
{
|
||||
T value = default;
|
||||
T value = default!;
|
||||
Invoke(() => value = func());
|
||||
return value;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ public class WinFormsListView<T> : IListView<T> where T : notnull
|
||||
|
||||
private bool UseCustomRendering => !_behavior.ShowLabels && !_behavior.Checkboxes;
|
||||
|
||||
private void CustomRenderItem(object sender, DrawListViewItemEventArgs e)
|
||||
private void CustomRenderItem(object? sender, DrawListViewItemEventArgs e)
|
||||
{
|
||||
int width, height;
|
||||
var image = ImageList.Get(e.Item);
|
||||
|
@ -39,7 +39,8 @@ public class PrintDocumentPrinter : IScannedImagePrinter
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> Print(PrinterSettings printerSettings, IList<ProcessedImage> images, IList<ProcessedImage> selectedImages)
|
||||
public async Task<bool> Print(PrinterSettings printerSettings, IList<ProcessedImage> images,
|
||||
IList<ProcessedImage> selectedImages)
|
||||
{
|
||||
IList<ProcessedImage> imagesToPrint;
|
||||
switch (printerSettings.PrintRange)
|
||||
@ -87,7 +88,7 @@ public class PrintDocumentPrinter : IScannedImagePrinter
|
||||
? new Rectangle(pb.Left, pb.Top, image.Width * pb.Height / image.Height, pb.Height)
|
||||
: new Rectangle(pb.Left, pb.Top, pb.Width, image.Height * pb.Width / image.Width);
|
||||
|
||||
e.Graphics.DrawImage(image.AsBitmap(), rect);
|
||||
e.Graphics!.DrawImage(image.AsBitmap(), rect);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -98,7 +99,7 @@ public class PrintDocumentPrinter : IScannedImagePrinter
|
||||
};
|
||||
printDocument.PrinterSettings = printerSettings;
|
||||
printDocument.Print();
|
||||
|
||||
|
||||
Log.Event(EventType.Print, new EventParams
|
||||
{
|
||||
Name = MiscResources.Print,
|
||||
|
@ -44,7 +44,10 @@ internal static class TwainApi
|
||||
do
|
||||
{
|
||||
string? name = tw.GetCurrentName();
|
||||
result.Add(new ScanDevice(name, name));
|
||||
if (name != null)
|
||||
{
|
||||
result.Add(new ScanDevice(name, name));
|
||||
}
|
||||
} while (tw.GetNext());
|
||||
return result;
|
||||
}
|
||||
@ -56,7 +59,7 @@ internal static class TwainApi
|
||||
{
|
||||
throw new DeviceNotFoundException();
|
||||
}
|
||||
if (!tw.SelectByName(device.ID!))
|
||||
if (!tw.SelectByName(device.Id!))
|
||||
{
|
||||
throw new DeviceNotFoundException();
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ internal class TwImageInfo
|
||||
public int ImageLength;
|
||||
public short SamplesPerPixel;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public short[] BitsPerSample;
|
||||
public short[]? BitsPerSample;
|
||||
public short BitsPerPixel;
|
||||
public short Planar;
|
||||
public short PixelType;
|
||||
|
@ -5,7 +5,7 @@ namespace NAPS2.WinForms;
|
||||
/// <summary>
|
||||
/// A basic implementation of an invisible form.
|
||||
/// </summary>
|
||||
public class BackgroundForm : FormBase
|
||||
public class BackgroundForm : Form
|
||||
{
|
||||
public BackgroundForm()
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ public class DragScrollListView : ListView
|
||||
|
||||
private int EdgeSize => Font.Height;
|
||||
|
||||
private void ListViewBase_DragOver(object sender, DragEventArgs e)
|
||||
private void ListViewBase_DragOver(object? sender, DragEventArgs e)
|
||||
{
|
||||
Point position = PointToClient(new Point(e.X, e.Y));
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace NAPS2.WinForms;
|
||||
|
||||
// TODO: Do we want to migrate this to Eto? Ideally we can figure out why Twain Legacy is needed for some circumstances
|
||||
// and remove this form entirely...
|
||||
internal partial class FTwainGui : FormBase
|
||||
internal partial class FTwainGui : Form
|
||||
{
|
||||
public FTwainGui()
|
||||
{
|
||||
InitializeComponent();
|
||||
SaveFormState = false;
|
||||
RestoreFormState = false;
|
||||
label1.Text = UiStrings.WaitingForTwain;
|
||||
}
|
||||
}
|
@ -1,208 +0,0 @@
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Windows.Forms;
|
||||
using NAPS2.EtoForms;
|
||||
using NAPS2.Scan;
|
||||
|
||||
namespace NAPS2.WinForms;
|
||||
|
||||
// TODO: Remove ConfigScopes.User dependency from reusable forms
|
||||
public class FormBase : Form, IInvoker, IFormBase
|
||||
{
|
||||
private bool _loaded;
|
||||
private FormState _formState;
|
||||
|
||||
public FormBase()
|
||||
{
|
||||
UpdateRTL();
|
||||
|
||||
RestoreFormState = true;
|
||||
SaveFormState = true;
|
||||
|
||||
Load += OnLoadInternal;
|
||||
Closed += OnClosed;
|
||||
Resize += OnResize;
|
||||
Move += OnMove;
|
||||
}
|
||||
|
||||
public FormStateController FormStateController => throw new NotSupportedException();
|
||||
|
||||
public IFormFactory FormFactory { get; set; }
|
||||
|
||||
public Naps2Config Config { get; set; }
|
||||
|
||||
protected bool RestoreFormState { get; set; }
|
||||
|
||||
protected bool SaveFormState { get; set; }
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
protected void AddEnumItems<T>(ComboBox combo)
|
||||
{
|
||||
AddEnumItems<T>(combo, Combo_Format);
|
||||
}
|
||||
|
||||
protected void AddEnumItems<T>(ComboBox combo, Func<T, string> format)
|
||||
{
|
||||
AddEnumItems<T>(combo, (sender, e) => e.Value = format((T) e.ListItem));
|
||||
}
|
||||
|
||||
protected void AddEnumItems<T>(ComboBox combo, ListControlConvertEventHandler format)
|
||||
{
|
||||
foreach (object item in Enum.GetValues(typeof(T)))
|
||||
{
|
||||
combo.Items.Add(item);
|
||||
}
|
||||
combo.Format += format;
|
||||
}
|
||||
|
||||
void Combo_Format(object sender, ListControlConvertEventArgs e)
|
||||
{
|
||||
e.Value = ((Enum)e.ListItem).Description();
|
||||
}
|
||||
|
||||
public void Invoke(Action action)
|
||||
{
|
||||
((Control) this).Invoke(action);
|
||||
}
|
||||
|
||||
public T InvokeGet<T>(Func<T> func)
|
||||
{
|
||||
T value = default;
|
||||
Invoke(() => value = func());
|
||||
return value;
|
||||
}
|
||||
|
||||
public void SafeInvoke(Action action)
|
||||
{
|
||||
try
|
||||
{
|
||||
Invoke(action);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void SafeInvokeAsync(Action action)
|
||||
{
|
||||
try
|
||||
{
|
||||
BeginInvoke(action);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected void UpdateRTL()
|
||||
{
|
||||
bool isRTL = CultureInfo.CurrentCulture.TextInfo.IsRightToLeft;
|
||||
RightToLeft = isRTL ? RightToLeft.Yes : RightToLeft.No;
|
||||
RightToLeftLayout = isRTL;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Descendant forms should override this instead of subscribing to the Load event when logic needs
|
||||
/// to be performed before the form is resized (e.g. setting up LayoutManager).
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="eventArgs"></param>
|
||||
protected virtual void OnLoad(object sender, EventArgs eventArgs)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void AfterLoad(object sender, EventArgs eventArgs)
|
||||
{
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
private void OnLoadInternal(object sender, EventArgs eventArgs)
|
||||
{
|
||||
OnLoad(this, EventArgs.Empty);
|
||||
if (DesignMode)
|
||||
{
|
||||
RestoreFormState = SaveFormState = false;
|
||||
}
|
||||
|
||||
if (RestoreFormState || SaveFormState)
|
||||
{
|
||||
var formStates = Config.Get(c => c.FormStates);
|
||||
_formState = formStates.SingleOrDefault(x => x.Name == Name) ?? new FormState {Name = Name};
|
||||
}
|
||||
|
||||
if (RestoreFormState)
|
||||
{
|
||||
DoRestoreFormState();
|
||||
}
|
||||
_loaded = true;
|
||||
AfterLoad(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected void DoRestoreFormState()
|
||||
{
|
||||
var location = new Point(_formState.Location.X, _formState.Location.Y);
|
||||
var size = new Size(_formState.Size.Width, _formState.Size.Height);
|
||||
if (!location.IsEmpty)
|
||||
{
|
||||
if (Screen.AllScreens.Any(x => x.WorkingArea.Contains(location)))
|
||||
{
|
||||
// Only move to the specified location if it's onscreen
|
||||
// It might be offscreen if the user has disconnected a monitor
|
||||
Location = location;
|
||||
}
|
||||
}
|
||||
if (!size.IsEmpty)
|
||||
{
|
||||
Size = size;
|
||||
}
|
||||
if (_formState.Maximized)
|
||||
{
|
||||
WindowState = FormWindowState.Maximized;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnResize(object sender, EventArgs eventArgs)
|
||||
{
|
||||
if (_loaded && SaveFormState)
|
||||
{
|
||||
_formState.Maximized = (WindowState == FormWindowState.Maximized);
|
||||
if (WindowState == FormWindowState.Normal)
|
||||
{
|
||||
_formState.Size = new FormState.FormSize(Size.Width, Size.Height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMove(object sender, EventArgs eventArgs)
|
||||
{
|
||||
if (_loaded && SaveFormState)
|
||||
{
|
||||
if (WindowState == FormWindowState.Normal)
|
||||
{
|
||||
_formState.Location = new FormState.FormLocation(Location.X, Location.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClosed(object sender, EventArgs eventArgs)
|
||||
{
|
||||
if (SaveFormState && _formState != null)
|
||||
{
|
||||
var formStates = Config.Get(c => c.FormStates);
|
||||
formStates = formStates.RemoveAll(fs => fs.Name == Name).Add(_formState);
|
||||
Config.User.Set(c => c.FormStates, formStates);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
@ -13,7 +13,7 @@ public class NotificationManager : INotificationManager
|
||||
private const int SPACING_Y = 20;
|
||||
|
||||
private readonly Naps2Config _config;
|
||||
private readonly List<NotifyWidgetBase> _slots = new();
|
||||
private readonly List<NotifyWidgetBase?> _slots = new();
|
||||
private wf.Form? _parentForm;
|
||||
|
||||
public NotificationManager(Naps2Config config, DesktopFormProvider desktopFormProvider)
|
||||
@ -68,9 +68,10 @@ public class NotificationManager : INotificationManager
|
||||
_slots.Clear();
|
||||
for (int i = 0; i < old.Count; i++)
|
||||
{
|
||||
if (old[i] != null)
|
||||
var slot = old[i];
|
||||
if (slot != null)
|
||||
{
|
||||
Show(old[i].Clone());
|
||||
Show(slot.Clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,13 +94,14 @@ public class NotificationManager : INotificationManager
|
||||
});
|
||||
}
|
||||
|
||||
private void parentForm_Resize(object sender, EventArgs e)
|
||||
private void parentForm_Resize(object? sender, EventArgs e)
|
||||
{
|
||||
for (int i = 0; i < _slots.Count; i++)
|
||||
{
|
||||
if (_slots[i] != null)
|
||||
var slot = _slots[i];
|
||||
if (slot != null)
|
||||
{
|
||||
_slots[i].Location = GetPosition(_slots[i], i);
|
||||
slot.Location = GetPosition(slot, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,10 @@ namespace NAPS2.WinForms;
|
||||
|
||||
public partial class NotifyWidget : NotifyWidgetBase
|
||||
{
|
||||
private readonly string _linkTarget;
|
||||
private readonly string? _linkTarget;
|
||||
private readonly string? _folderTarget;
|
||||
|
||||
public NotifyWidget(string title, string linkLabel, string linkTarget, string? folderTarget)
|
||||
public NotifyWidget(string title, string linkLabel, string? linkTarget, string? folderTarget)
|
||||
{
|
||||
_linkTarget = linkTarget;
|
||||
_folderTarget = folderTarget;
|
||||
@ -66,6 +66,11 @@ public partial class NotifyWidget : NotifyWidgetBase
|
||||
|
||||
protected virtual void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
if (_linkTarget == null)
|
||||
{
|
||||
Log.Error("Link target should not be null");
|
||||
return;
|
||||
}
|
||||
if (e.Button == MouseButtons.Right)
|
||||
{
|
||||
contextMenuStrip1.Show(linkLabel1, linkLabel1.Location);
|
||||
|
@ -4,35 +4,16 @@ namespace NAPS2.WinForms;
|
||||
|
||||
public class NotifyWidgetBase : UserControl
|
||||
{
|
||||
public event EventHandler HideNotify;
|
||||
public event EventHandler? HideNotify;
|
||||
|
||||
protected void InvokeHideNotify()
|
||||
{
|
||||
SafeInvoke(() => HideNotify?.Invoke(this, new EventArgs()));
|
||||
Invoker.Current.SafeInvoke(() => HideNotify?.Invoke(this, EventArgs.Empty));
|
||||
}
|
||||
|
||||
public virtual void ShowNotify()
|
||||
{
|
||||
}
|
||||
|
||||
public void Invoke(Action action)
|
||||
{
|
||||
((Control)this).Invoke(action);
|
||||
}
|
||||
|
||||
public void SafeInvoke(Action action)
|
||||
{
|
||||
try
|
||||
{
|
||||
Invoke(action);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public virtual NotifyWidgetBase Clone() => throw new NotImplementedException();
|
||||
}
|
@ -47,23 +47,23 @@ public partial class OperationProgressNotifyWidget : NotifyWidgetBase
|
||||
InvokeHideNotify();
|
||||
}
|
||||
|
||||
private void Op_StatusChanged(object sender, EventArgs e)
|
||||
private void Op_StatusChanged(object? sender, EventArgs e)
|
||||
{
|
||||
SafeInvoke(DisplayProgress);
|
||||
Invoker.Current.SafeInvoke(DisplayProgress);
|
||||
}
|
||||
|
||||
private void Op_Finished(object sender, EventArgs e)
|
||||
private void Op_Finished(object? sender, EventArgs e)
|
||||
{
|
||||
DoHideNotify();
|
||||
}
|
||||
|
||||
private void cancelToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
private void cancelToolStripMenuItem_Click(object? sender, EventArgs e)
|
||||
{
|
||||
_op.Cancel();
|
||||
cancelToolStripMenuItem.Enabled = false;
|
||||
}
|
||||
|
||||
private void OperationProgressNotifyWidget_Click(object sender, MouseEventArgs e)
|
||||
private void OperationProgressNotifyWidget_Click(object? sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ public class SelectableListView<T> : ISelectable<T> where T : notnull
|
||||
|
||||
public event EventHandler? SelectionChanged;
|
||||
|
||||
private void ListViewOnSelectedIndexChanged(object sender, EventArgs e)
|
||||
private void ListViewOnSelectedIndexChanged(object? sender, EventArgs e)
|
||||
{
|
||||
if (!_refreshing)
|
||||
{
|
||||
|
@ -8,29 +8,27 @@ public class ToolStripDoubleButton : ToolStripButton
|
||||
{
|
||||
private int _currentButton = -1;
|
||||
|
||||
public ToolStripDoubleButton()
|
||||
{
|
||||
}
|
||||
public event EventHandler? FirstClick;
|
||||
public event EventHandler? SecondClick;
|
||||
|
||||
public event EventHandler FirstClick;
|
||||
public event EventHandler SecondClick;
|
||||
|
||||
public Image FirstImage { get; set; }
|
||||
public Image SecondImage { get; set; }
|
||||
public required Image FirstImage { get; init; }
|
||||
public required Image SecondImage { get; init; }
|
||||
|
||||
[Localizable(true)]
|
||||
public string FirstText { get; set; }
|
||||
[Localizable(true)]
|
||||
public string SecondText { get; set; }
|
||||
public required string FirstText { get; init; }
|
||||
|
||||
public int MaxTextWidth { get; set; }
|
||||
[Localizable(true)]
|
||||
public required string SecondText { get; init; }
|
||||
|
||||
public int MaxTextWidth { get; init; }
|
||||
|
||||
public override Size GetPreferredSize(Size constrainingSize)
|
||||
{
|
||||
bool wrap = false;
|
||||
var sumWidth = Padding.Left + Padding.Right
|
||||
+ Math.Max(FirstImage?.Width ?? 0, SecondImage?.Width ?? 0)
|
||||
+ Math.Max(MeasureTextWidth(FirstText, ref wrap), MeasureTextWidth(SecondText, ref wrap));
|
||||
+ Math.Max(MeasureTextWidth(FirstText, ref wrap),
|
||||
MeasureTextWidth(SecondText, ref wrap));
|
||||
var sumHeight = Padding.Top + Padding.Bottom
|
||||
+ (FirstImage?.Height ?? 0) + (SecondImage?.Height ?? 0)
|
||||
+ 16 + (wrap ? 12 : 0);
|
||||
@ -40,7 +38,7 @@ public class ToolStripDoubleButton : ToolStripButton
|
||||
private int MeasureTextWidth(string text, ref bool wrap)
|
||||
{
|
||||
using var g = Graphics.FromImage(new Bitmap(1, 1));
|
||||
var width = (int)Math.Ceiling(g.MeasureString(text, Font).Width);
|
||||
var width = (int) Math.Ceiling(g.MeasureString(text, Font).Width);
|
||||
if (MaxTextWidth > 0 && width > MaxTextWidth)
|
||||
{
|
||||
var words = text.Split(' ');
|
||||
@ -48,7 +46,7 @@ public class ToolStripDoubleButton : ToolStripButton
|
||||
{
|
||||
var left = string.Join(" ", words.Take(words.Length - i));
|
||||
var right = string.Join(" ", words.Skip(words.Length - i));
|
||||
var wrappedWidth = (int)Math.Ceiling(g.MeasureString(left + "\n" + right, Font).Width);
|
||||
var wrappedWidth = (int) Math.Ceiling(g.MeasureString(left + "\n" + right, Font).Width);
|
||||
if (wrappedWidth < width)
|
||||
{
|
||||
width = wrappedWidth;
|
||||
@ -83,35 +81,31 @@ public class ToolStripDoubleButton : ToolStripButton
|
||||
flags |= TextFormatFlags.WordBreak;
|
||||
}
|
||||
|
||||
if (FirstImage != null && FirstText != null)
|
||||
if (Enabled)
|
||||
{
|
||||
if (Enabled)
|
||||
{
|
||||
e.Graphics.DrawImage(FirstImage, new Point(Padding.Left, Height / 4 - FirstImage.Height / 2 + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
ControlPaint.DrawImageDisabled(e.Graphics, FirstImage, Padding.Left, Height / 4 - FirstImage.Height / 2 + 1, Color.Transparent);
|
||||
}
|
||||
|
||||
var textRectangle = new Rectangle(Padding.Left + FirstImage.Width, 0, textWidth, Height / 2);
|
||||
renderer.DrawItemText(new ToolStripItemTextRenderEventArgs(e.Graphics, this, FirstText, textRectangle, ForeColor, Font, flags));
|
||||
e.Graphics.DrawImage(FirstImage, new Point(Padding.Left, Height / 4 - FirstImage.Height / 2 + 1));
|
||||
}
|
||||
|
||||
if (SecondImage != null && SecondText != null)
|
||||
else
|
||||
{
|
||||
if (Enabled)
|
||||
{
|
||||
e.Graphics.DrawImage(SecondImage, new Point(Padding.Left, Height * 3 / 4 - SecondImage.Height / 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
ControlPaint.DrawImageDisabled(e.Graphics, SecondImage, Padding.Left, Height * 3 / 4 - SecondImage.Height / 2, Color.Transparent);
|
||||
}
|
||||
|
||||
var textRectangle = new Rectangle(Padding.Left + SecondImage.Width, Height / 2, textWidth, Height / 2);
|
||||
renderer.DrawItemText(new ToolStripItemTextRenderEventArgs(e.Graphics, this, SecondText, textRectangle, ForeColor, Font, flags));
|
||||
ControlPaint.DrawImageDisabled(e.Graphics, FirstImage, Padding.Left, Height / 4 - FirstImage.Height / 2 + 1,
|
||||
Color.Transparent);
|
||||
}
|
||||
var textRectangle1 = new Rectangle(Padding.Left + FirstImage.Width, 0, textWidth, Height / 2);
|
||||
renderer.DrawItemText(new ToolStripItemTextRenderEventArgs(e.Graphics, this, FirstText, textRectangle1,
|
||||
ForeColor, Font, flags));
|
||||
|
||||
if (Enabled)
|
||||
{
|
||||
e.Graphics.DrawImage(SecondImage, new Point(Padding.Left, Height * 3 / 4 - SecondImage.Height / 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
ControlPaint.DrawImageDisabled(e.Graphics, SecondImage, Padding.Left,
|
||||
Height * 3 / 4 - SecondImage.Height / 2, Color.Transparent);
|
||||
}
|
||||
var textRectangle2 = new Rectangle(Padding.Left + SecondImage.Width, Height / 2, textWidth, Height / 2);
|
||||
renderer.DrawItemText(new ToolStripItemTextRenderEventArgs(e.Graphics, this, SecondText, textRectangle2,
|
||||
ForeColor, Font, flags));
|
||||
|
||||
Image = null;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class DesktopScanController : IDesktopScanController
|
||||
{
|
||||
_desktopFormProvider.DesktopForm.BringToFront();
|
||||
ScanProfile? profile;
|
||||
if (_profileManager.DefaultProfile?.Device?.ID == deviceID)
|
||||
if (_profileManager.DefaultProfile?.Device?.Id == deviceID)
|
||||
{
|
||||
// Try to use the default profile if it has the right device
|
||||
profile = _profileManager.DefaultProfile;
|
||||
@ -53,7 +53,7 @@ public class DesktopScanController : IDesktopScanController
|
||||
{
|
||||
// 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);
|
||||
profile = _profileManager.Profiles.FirstOrDefault(x => x.Device != null && x.Device.Id == deviceID);
|
||||
}
|
||||
if (profile == null)
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ public class SelectDeviceForm : EtoDialogBase
|
||||
{
|
||||
_devices.Items.Add(new ListItem
|
||||
{
|
||||
Key = device.ID,
|
||||
Key = device.Id,
|
||||
Text = device.Name
|
||||
});
|
||||
}
|
||||
@ -54,6 +54,6 @@ public class SelectDeviceForm : EtoDialogBase
|
||||
_devices.Focus();
|
||||
return;
|
||||
}
|
||||
SelectedDevice = DeviceList.FirstOrDefault(x => x.ID == _devices.SelectedKey);
|
||||
SelectedDevice = DeviceList.FirstOrDefault(x => x.Id == _devices.SelectedKey);
|
||||
}
|
||||
}
|
@ -251,7 +251,7 @@ internal class ScanPerformer : IScanPerformer
|
||||
private async Task<bool> PopulateDevice(ScanProfile scanProfile, ScanOptions options)
|
||||
{
|
||||
// If a device wasn't specified, prompt the user to pick one
|
||||
if (string.IsNullOrEmpty(scanProfile.Device?.ID))
|
||||
if (string.IsNullOrEmpty(scanProfile.Device?.Id))
|
||||
{
|
||||
options.Device = await PromptForDevice(options);
|
||||
if (options.Device == null)
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6;net462</TargetFrameworks>
|
||||
<!-- As these are just samples, no need for "windows only api" warnings for GdiImageContext -->
|
||||
<NoWarn>CA1416</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\NAPS2.Setup\targets\CommonTargets.targets" />
|
||||
|
@ -23,12 +23,12 @@ public class RemoteScanControllerTests : ContextualTests
|
||||
|
||||
var deviceList = await controller.GetDeviceList(new ScanOptions { Driver = Driver.Wia });
|
||||
Assert.Equal(2, deviceList.Count);
|
||||
Assert.Equal("test_id1", deviceList[0].ID);
|
||||
Assert.Equal("WIA-test_id2", deviceList[1].ID);
|
||||
Assert.Equal("test_id1", deviceList[0].Id);
|
||||
Assert.Equal("WIA-test_id2", deviceList[1].Id);
|
||||
|
||||
deviceList = await controller.GetDeviceList(new ScanOptions { Driver = Driver.Twain });
|
||||
Assert.Single(deviceList);
|
||||
Assert.Equal("test_id1", deviceList[0].ID);
|
||||
Assert.Equal("test_id1", deviceList[0].Id);
|
||||
|
||||
deviceList = await controller.GetDeviceList(new ScanOptions
|
||||
{ Driver = Driver.Twain, TwainOptions = { IncludeWiaDevices = true } });
|
||||
|
@ -45,7 +45,7 @@ public class ScanErrorHandling : ContextualTests
|
||||
controller.PropagateErrors = true;
|
||||
|
||||
bridgeFactory.Setup(factory => factory.Create(It.IsAny<ScanOptions>())).Throws<InvalidOperationException>();
|
||||
var source = controller.Scan(new ScanOptions { Device = new ScanDevice { ID = "blah" } });
|
||||
var source = controller.Scan(new ScanOptions { Device = new ScanDevice("foo", "bar") });
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () => await source.ToListAsync());
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ public class ScanErrorHandling : ContextualTests
|
||||
localPostProcessor.Setup(pp =>
|
||||
pp.PostProcess(It.IsAny<ProcessedImage>(), It.IsAny<ScanOptions>(), It.IsAny<PostProcessingContext>()))
|
||||
.Throws<InvalidOperationException>();
|
||||
var source = controller.Scan(new ScanOptions { Device = new ScanDevice { ID = "blah" } });
|
||||
var source = controller.Scan(new ScanOptions { Device = new ScanDevice("foo", "bar") });
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () => await source.ToListAsync());
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ public class ScanErrorHandling : ContextualTests
|
||||
controller.PropagateErrors = true;
|
||||
|
||||
bridgeFactory.Setup(factory => factory.Create(It.IsAny<ScanOptions>())).Returns(bridge);
|
||||
var source = controller.Scan(new ScanOptions { Device = new ScanDevice { ID = "blah" } });
|
||||
var source = controller.Scan(new ScanOptions { Device = new ScanDevice("foo", "bar") });
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () => await source.ToListAsync());
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ public class WorkerChannelTests : ContextualTests
|
||||
var deviceList = await channel.Client.GetDeviceList(new ScanOptions());
|
||||
|
||||
Assert.Single(deviceList);
|
||||
Assert.Equal("test_id", deviceList[0].ID);
|
||||
Assert.Equal("test_id", deviceList[0].Id);
|
||||
Assert.Equal("test_name", deviceList[0].Name);
|
||||
remoteScanController.Verify(rsc => rsc.GetDeviceList(It.IsAny<ScanOptions>()));
|
||||
remoteScanController.VerifyNoOtherCalls();
|
||||
|
@ -19,7 +19,10 @@ internal class AppleScanDriver : IScanDriver
|
||||
using var reader = new DeviceReader();
|
||||
reader.Start();
|
||||
await Task.Delay(2000);
|
||||
return reader.Devices.Select(x => new ScanDevice(x.Uuid, x.Name)).ToList();
|
||||
return reader.Devices
|
||||
.Where(x => x.Uuid != null && x.Name != null)
|
||||
.Select(x => new ScanDevice(x.Uuid!, x.Name!))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public async Task Scan(ScanOptions options, CancellationToken cancelToken, IScanEvents scanEvents,
|
||||
@ -37,7 +40,7 @@ internal class AppleScanDriver : IScanDriver
|
||||
var tcs = new TaskCompletionSource<ICScannerDevice>();
|
||||
reader.DeviceFound += (_, args) =>
|
||||
{
|
||||
if (args.Device.Uuid == scanDevice.ID)
|
||||
if (args.Device.Uuid == scanDevice.Id)
|
||||
{
|
||||
tcs.TrySetResult(args.Device);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ internal class DeviceOperator : ICScannerDeviceDelegate
|
||||
|
||||
public override void DidEncounterError(ICDevice device, NSError? error)
|
||||
{
|
||||
var ex = new DeviceException(error.Description);
|
||||
var ex = error != null ? new DeviceException(error.Description) : new DeviceException();
|
||||
// TODO: Put these in a list or something
|
||||
_openSessionTcs.TrySetException(ex);
|
||||
_readyTcs.TrySetException(ex);
|
||||
|
@ -23,7 +23,7 @@ internal class RemoteScanController : IRemoteScanController
|
||||
var deviceList = await _scanDriverFactory.Create(options).GetDeviceList(options);
|
||||
if (options.Driver == Driver.Twain && !options.TwainOptions.IncludeWiaDevices)
|
||||
{
|
||||
deviceList = deviceList.Where(x => !x.ID.StartsWith("WIA-", StringComparison.InvariantCulture)).ToList();
|
||||
deviceList = deviceList.Where(x => !x.Id.StartsWith("WIA-", StringComparison.InvariantCulture)).ToList();
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ internal class SaneScanDriver : IScanDriver
|
||||
{
|
||||
using var client = new SaneClient();
|
||||
if (cancelToken.IsCancellationRequested) return;
|
||||
using var device = client.OpenDevice(options.Device!.ID!);
|
||||
using var device = client.OpenDevice(options.Device!.Id!);
|
||||
if (cancelToken.IsCancellationRequested) return;
|
||||
SetOptions(device, options);
|
||||
// TODO: We apparently need to cancel even upon normal completion, i.e. one sane_cancel per sane_start
|
||||
|
@ -18,7 +18,7 @@ public class ScanOptionsValidator
|
||||
|
||||
if (requireDevice)
|
||||
{
|
||||
if (string.IsNullOrEmpty(options.Device?.ID))
|
||||
if (string.IsNullOrEmpty(options.Device?.Id))
|
||||
{
|
||||
throw new ArgumentException("ScanOptions.Device.ID must be specified");
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ internal class TwainProgressEstimator
|
||||
|
||||
private static TimingKey GetTimingKey(ScanOptions options)
|
||||
{
|
||||
return new TimingKey(options.Device!.ID!, options.BitDepth, options.PageSize!);
|
||||
return new TimingKey(options.Device!.Id!, options.BitDepth, options.PageSize!);
|
||||
}
|
||||
|
||||
public TwainProgressEstimator(ScanOptions options, IScanEvents scanEvents)
|
||||
|
@ -67,7 +67,7 @@ internal class TwainSessionScanRunner
|
||||
}
|
||||
|
||||
Debug.WriteLine("NAPS2.TW - Finding source");
|
||||
_source = _session.FirstOrDefault(x => x.Name == _options.Device!.ID);
|
||||
_source = _session.FirstOrDefault(x => x.Name == _options.Device!.Id);
|
||||
if (_source == null)
|
||||
{
|
||||
throw new DeviceNotFoundException();
|
||||
|
@ -79,7 +79,7 @@ internal class WiaScanDriver : IScanDriver
|
||||
public async Task Scan(WiaVersion wiaVersion)
|
||||
{
|
||||
using var deviceManager = new WiaDeviceManager(wiaVersion);
|
||||
using var device = deviceManager.FindDevice(_options.Device!.ID!);
|
||||
using var device = deviceManager.FindDevice(_options.Device!.Id!);
|
||||
if (device.Version == WiaVersion.Wia20 && _options.UseNativeUI)
|
||||
{
|
||||
await DoWia20NativeTransfer(deviceManager, device);
|
||||
|
@ -1,22 +1,6 @@
|
||||
namespace NAPS2.Scan;
|
||||
|
||||
// TODO: Can we make this a record and/or make properties non-nullable?
|
||||
/// <summary>
|
||||
/// The representation of a scanning device identified by a driver.
|
||||
/// </summary>
|
||||
public class ScanDevice
|
||||
{
|
||||
public ScanDevice(string? id, string? name)
|
||||
{
|
||||
ID = id;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public ScanDevice()
|
||||
{
|
||||
}
|
||||
|
||||
public string? ID { get; set; }
|
||||
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
public record ScanDevice(string Id, string Name);
|
@ -29,7 +29,7 @@ public class AssemblyHelper
|
||||
|
||||
private static string GetAssemblyAttributeValue<T>(Func<T, string> selector)
|
||||
{
|
||||
object[] attributes = Assembly.GetEntryAssembly().GetCustomAttributes(typeof(T), false);
|
||||
object[] attributes = Assembly.GetEntryAssembly()!.GetCustomAttributes(typeof(T), false);
|
||||
if (attributes.Length == 0)
|
||||
{
|
||||
return "";
|
||||
@ -37,20 +37,9 @@ public class AssemblyHelper
|
||||
return selector((T) attributes[0]);
|
||||
}
|
||||
|
||||
public static string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
string title = GetAssemblyAttributeValue<AssemblyTitleAttribute>(x => x.Title);
|
||||
if (string.IsNullOrEmpty(title))
|
||||
{
|
||||
title = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().CodeBase);
|
||||
}
|
||||
return title;
|
||||
}
|
||||
}
|
||||
public static string Title => GetAssemblyAttributeValue<AssemblyTitleAttribute>(x => x.Title);
|
||||
|
||||
public static string Version => Assembly.GetEntryAssembly().GetName().Version.ToString();
|
||||
public static string Version => Assembly.GetEntryAssembly()!.GetName().Version!.ToString();
|
||||
|
||||
public static string Description => GetAssemblyAttributeValue<AssemblyDescriptionAttribute>(x => x.Description);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user