Fixes and mapping
This commit is contained in:
parent
fc7175c2f7
commit
ba965e8266
10 changed files with 449 additions and 284 deletions
|
|
@ -96,7 +96,7 @@ namespace MaddoShared
|
|||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "Error in reporting update");
|
||||
throw;
|
||||
// Don't rethrow - continue processing other images
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
|
||||
<PackageReference Include="AutoMapper" Version="16.0.0" />
|
||||
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
||||
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
|
|
|||
53
imagecatalog/Commands/ButtonCommandBinder.cs
Normal file
53
imagecatalog/Commands/ButtonCommandBinder.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace ImageCatalog_2.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to bind WinForms Button controls to ICommand implementations
|
||||
/// </summary>
|
||||
public static class ButtonCommandBinder
|
||||
{
|
||||
/// <summary>
|
||||
/// Binds a Button's Click event to an ICommand
|
||||
/// </summary>
|
||||
/// <param name="button">The button to bind</param>
|
||||
/// <param name="command">The command to execute</param>
|
||||
/// <param name="commandParameter">Optional parameter to pass to the command</param>
|
||||
public static void BindCommand(this Button button, ICommand command, object commandParameter = null)
|
||||
{
|
||||
if (button == null) throw new ArgumentNullException(nameof(button));
|
||||
if (command == null) throw new ArgumentNullException(nameof(command));
|
||||
|
||||
// Wire up the Click event to execute the command
|
||||
button.Click += (sender, e) =>
|
||||
{
|
||||
if (command.CanExecute(commandParameter))
|
||||
{
|
||||
command.Execute(commandParameter);
|
||||
}
|
||||
};
|
||||
|
||||
// Wire up CanExecuteChanged to enable/disable the button
|
||||
command.CanExecuteChanged += (sender, e) =>
|
||||
{
|
||||
button.Enabled = command.CanExecute(commandParameter);
|
||||
};
|
||||
|
||||
// Set initial enabled state
|
||||
button.Enabled = command.CanExecute(commandParameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds multiple buttons to commands at once
|
||||
/// </summary>
|
||||
public static void BindCommands(params (Button button, ICommand command, object parameter)[] bindings)
|
||||
{
|
||||
foreach (var (button, command, parameter) in bindings)
|
||||
{
|
||||
button.BindCommand(command, parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,19 @@
|
|||
using ImageCatalog_2.Commands;
|
||||
using ImageCatalog_2.Services;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing.Text;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Input;
|
||||
using AutoMapper;
|
||||
using MaddoShared;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ImageCatalog_2
|
||||
|
|
@ -29,17 +34,25 @@ namespace ImageCatalog_2
|
|||
private readonly ITestService _service;
|
||||
private readonly ILogger<DataModel> _logger;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly ImageCreationStuff _imageCreationService;
|
||||
private readonly PicSettings _picSettings;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
// ComboBox collections
|
||||
public List<string> AvailableFonts { get; }
|
||||
public List<string> VerticalPositions { get; } = new() { "Alto", "Centro", "Basso" };
|
||||
public List<string> HorizontalAlignments { get; } = new() { "Sinistra", "Centro", "Destra" };
|
||||
|
||||
public DataModel(ITestService testService, ISettingsService settingsService, ILogger<DataModel> logger)
|
||||
public DataModel(ITestService testService, ISettingsService settingsService,
|
||||
ImageCreationStuff imageCreationService, PicSettings picSettings,
|
||||
IMapper mapper, ILogger<DataModel> logger)
|
||||
{
|
||||
_service = testService;
|
||||
_logger = logger;
|
||||
_settingsService = settingsService;
|
||||
_imageCreationService = imageCreationService;
|
||||
_picSettings = picSettings;
|
||||
_mapper = mapper;
|
||||
|
||||
TestCommand = new RelayCommand(Test);
|
||||
AsyncTestCommand = new AsyncCommand(TestAsync);
|
||||
|
|
@ -774,6 +787,67 @@ namespace ImageCatalog_2
|
|||
}
|
||||
}
|
||||
|
||||
// Image processing progress and status
|
||||
private string _processingStatus = "";
|
||||
public string ProcessingStatus
|
||||
{
|
||||
get => _processingStatus;
|
||||
set
|
||||
{
|
||||
_processingStatus = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private int _processedImagesCount = 0;
|
||||
public int ProcessedImagesCount
|
||||
{
|
||||
get => _processedImagesCount;
|
||||
set
|
||||
{
|
||||
_processedImagesCount = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private int _totalImagesCount = 0;
|
||||
public int TotalImagesCount
|
||||
{
|
||||
get => _totalImagesCount;
|
||||
set
|
||||
{
|
||||
_totalImagesCount = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private int _progressBarValue = 0;
|
||||
public int ProgressBarValue
|
||||
{
|
||||
get => _progressBarValue;
|
||||
set
|
||||
{
|
||||
_progressBarValue = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private int _progressBarMaximum = 100;
|
||||
public int ProgressBarMaximum
|
||||
{
|
||||
get => _progressBarMaximum;
|
||||
set
|
||||
{
|
||||
_progressBarMaximum = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private ConcurrentBag<string> _results = new();
|
||||
private int _currentAmount = 0;
|
||||
private int _previousAmount = 0;
|
||||
private System.Threading.Timer? _speedTimer;
|
||||
|
||||
private void Test(object parameter)
|
||||
{
|
||||
Debug.WriteLine("Yep");
|
||||
|
|
@ -787,6 +861,123 @@ namespace ImageCatalog_2
|
|||
|
||||
private async Task ProcessImages()
|
||||
{
|
||||
_logger.LogInformation("Avvio elaborazione...");
|
||||
UiEnabled = false;
|
||||
|
||||
MainToken?.Dispose();
|
||||
MainToken = new CancellationTokenSource();
|
||||
var token = MainToken.Token;
|
||||
|
||||
// Fix paths
|
||||
FixPaths();
|
||||
|
||||
// Reset counters
|
||||
ProcessingStatus = "Elaborazione in corso...";
|
||||
TotalImagesCount = 0;
|
||||
ProcessedImagesCount = 0;
|
||||
SpeedCounter = "-f/m";
|
||||
ProgressBarValue = 0;
|
||||
ProgressBarMaximum = 100;
|
||||
|
||||
// Update PicSettings from DataModel using AutoMapper
|
||||
_mapper.Map(this, _picSettings);
|
||||
|
||||
var imageCreationOptions = new ImageCreationStuff.Options
|
||||
{
|
||||
AggiornaSottodirectory = UpdateSubdirectories,
|
||||
CreaSottocartelle = CreateSubfolders,
|
||||
FilePerCartella = FilesPerFolder,
|
||||
SuffissoCartelle = FolderSuffix,
|
||||
CifreContatore = CounterDigits,
|
||||
NumerazioneType = UseProgressiveNumbering ? NumerazioneType.Progressiva : NumerazioneType.Files,
|
||||
SourcePath = SourcePath,
|
||||
DestinationPath = DestinationPath,
|
||||
MaxThreads = ThreadsCount,
|
||||
ChunksSize = ChunkSize,
|
||||
LinearExecution = UseSequentialProcessing
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
_results = new ConcurrentBag<string>();
|
||||
_currentAmount = 0;
|
||||
_previousAmount = 0;
|
||||
|
||||
// Start speed timer (every minute)
|
||||
_speedTimer = new System.Threading.Timer(UpdateSpeedCounter, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
||||
|
||||
var time = await _imageCreationService.CreaCatalogoParallel(
|
||||
imageCreationOptions,
|
||||
_results,
|
||||
OnImageProcessed,
|
||||
token);
|
||||
|
||||
SpeedCounter = time;
|
||||
_speedTimer?.Dispose();
|
||||
_speedTimer = null;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.LogInformation("Operazione Cancellata");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Errore durante l'elaborazione delle immagini");
|
||||
ProcessingStatus = $"Errore: {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
MainToken?.Dispose();
|
||||
MainToken = null;
|
||||
_speedTimer?.Dispose();
|
||||
_speedTimer = null;
|
||||
}
|
||||
|
||||
ProcessingStatus = "Finito";
|
||||
UiEnabled = true;
|
||||
}
|
||||
|
||||
private void UpdateSpeedCounter(object? state)
|
||||
{
|
||||
_previousAmount = _currentAmount;
|
||||
_currentAmount = _results.Count;
|
||||
int diff = _currentAmount - _previousAmount;
|
||||
SpeedCounter = $"{diff} f/m";
|
||||
}
|
||||
|
||||
private void OnImageProcessed(object? sender, Tuple<string, int> args)
|
||||
{
|
||||
ProcessedImagesCount = _results.Count;
|
||||
TotalImagesCount = args.Item2;
|
||||
ProgressBarMaximum = args.Item2;
|
||||
ProgressBarValue = _results.Count;
|
||||
ProcessingStatus = args.Item1;
|
||||
}
|
||||
|
||||
private void FixPaths()
|
||||
{
|
||||
SourcePath = FixPath(SourcePath);
|
||||
DestinationPath = FixPath(DestinationPath);
|
||||
}
|
||||
|
||||
private string FixPath(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// Trim leading/trailing quotes
|
||||
path = path.Trim().Trim('"');
|
||||
|
||||
// Normalize directory separators
|
||||
path = path.Replace('/', System.IO.Path.DirectorySeparatorChar)
|
||||
.Replace('\\', System.IO.Path.DirectorySeparatorChar);
|
||||
|
||||
// Remove trailing separators then add one back
|
||||
path = path.TrimEnd(System.IO.Path.DirectorySeparatorChar) + System.IO.Path.DirectorySeparatorChar;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private async Task CancelOperation()
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
<ProjectReference Include="..\MaddoShared\MaddoShared.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="16.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.2" />
|
||||
|
|
|
|||
10
imagecatalog/MainForm.Designer.cs
generated
10
imagecatalog/MainForm.Designer.cs
generated
|
|
@ -1835,7 +1835,6 @@ namespace ImageCatalog
|
|||
_btnCreaCatalogoAsync.TabIndex = 68;
|
||||
_btnCreaCatalogoAsync.Text = "CREA";
|
||||
_btnCreaCatalogoAsync.UseVisualStyleBackColor = true;
|
||||
_btnCreaCatalogoAsync.Click += Button1_Click;
|
||||
//
|
||||
// dataModelBindingSource1
|
||||
//
|
||||
|
|
@ -2268,16 +2267,7 @@ namespace ImageCatalog
|
|||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
set
|
||||
{
|
||||
if (_btnCreaCatalogoAsync != null)
|
||||
{
|
||||
_btnCreaCatalogoAsync.Click -= Button1_Click;
|
||||
}
|
||||
|
||||
_btnCreaCatalogoAsync = value;
|
||||
if (_btnCreaCatalogoAsync != null)
|
||||
{
|
||||
_btnCreaCatalogoAsync.Click += Button1_Click;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using ImageCatalog_2;
|
||||
using ImageCatalog_2.Commands;
|
||||
using ImageCatalog_2.Services;
|
||||
using MaddoShared;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ImageCatalog;
|
||||
|
||||
|
|
@ -25,8 +27,6 @@ public partial class MainForm
|
|||
|
||||
private readonly ILogger<MainForm> _logger;
|
||||
|
||||
private readonly ImageCreationStuff _imageCreationService;
|
||||
|
||||
private readonly ParametriSetup _parametriSetup;
|
||||
private readonly PicSettings _picSettings;
|
||||
|
||||
|
|
@ -34,7 +34,6 @@ public partial class MainForm
|
|||
ParametriSetup parametriSetup, ILogger<MainForm> logger)
|
||||
{
|
||||
Model = model;
|
||||
_imageCreationService = imageCreationStuff;
|
||||
_parametriSetup = parametriSetup;
|
||||
_picSettings = picSettings;
|
||||
_logger = logger;
|
||||
|
|
@ -42,77 +41,37 @@ public partial class MainForm
|
|||
_logger.LogDebug("Start");
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
// Set this form as the control for thread marshalling in the DataModel
|
||||
Model.SetControl(this);
|
||||
|
||||
BindControls();
|
||||
|
||||
// Subscribe to DataModel events
|
||||
var version = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
_Label27.Text = $"Version: {version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
|
||||
}
|
||||
|
||||
protected void BindControls()
|
||||
{
|
||||
// Bind buttons to ViewModel commands using command binding
|
||||
_btnCreaCatalogoAsync.BindCommand(Model.ProcessImagesCommand);
|
||||
button1.BindCommand(Model.ProcessImagesCommand);
|
||||
_Button2.BindCommand(Model.SelectSourceFolderCommand);
|
||||
_Button3.BindCommand(Model.SelectDestinationFolderCommand);
|
||||
_Button4.BindCommand(Model.SelectLogoFileCommand);
|
||||
_Button5.BindCommand(Model.SaveSettingsCommand);
|
||||
_Button6.BindCommand(Model.LoadSettingsCommand);
|
||||
_Button8.BindCommand(Model.SelectColorCommand);
|
||||
|
||||
// Subscribe to ViewModel events for UI dialogs (these need UI context)
|
||||
Model.SelectSourceFolderRequested += OnSelectSourceFolderRequested;
|
||||
Model.SelectDestinationFolderRequested += OnSelectDestinationFolderRequested;
|
||||
Model.SelectLogoFileRequested += OnSelectLogoFileRequested;
|
||||
Model.SaveSettingsRequested += OnSaveSettingsRequested;
|
||||
Model.LoadSettingsRequested += OnLoadSettingsRequested;
|
||||
Model.SelectColorRequested += OnSelectColorRequested;
|
||||
|
||||
var version = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
_Label27.Text = $"Version: {version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
|
||||
|
||||
_results = [];
|
||||
UiUpdateEvent += OnUiUpdateEvent;
|
||||
}
|
||||
|
||||
protected void BindControls()
|
||||
{
|
||||
// Wire up buttons to ViewModel commands
|
||||
_Button2.Click += (s, e) => Model.SelectSourceFolderCommand.Execute(null);
|
||||
_Button3.Click += (s, e) => Model.SelectDestinationFolderCommand.Execute(null);
|
||||
_Button4.Click += (s, e) => Model.SelectLogoFileCommand.Execute(null);
|
||||
_Button5.Click += (s, e) => Model.SaveSettingsCommand.Execute(null);
|
||||
_Button6.Click += (s, e) => Model.LoadSettingsCommand.Execute(null);
|
||||
_Button8.Click += (s, e) => Model.SelectColorCommand.Execute(null);
|
||||
}
|
||||
|
||||
private event EventHandler<Tuple<string, int>> UiUpdateEvent;
|
||||
|
||||
delegate void SetTextCallback(Label target, string text);
|
||||
|
||||
private void SetText(Label target, string text)
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
var d = new SetTextCallback(SetText);
|
||||
this.Invoke(d, new object[] { target, text });
|
||||
}
|
||||
else
|
||||
{
|
||||
target.Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
private delegate void SetProgressCallback(ProgressBar target, int amount, int maximum);
|
||||
|
||||
private void SetProgress(ProgressBar target, int amount, int maximum)
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
var d = new SetProgressCallback(SetProgress);
|
||||
this.Invoke(d, new object[] { target, amount, maximum });
|
||||
}
|
||||
else
|
||||
{
|
||||
target.Maximum = maximum;
|
||||
target.Value = amount;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUiUpdateEvent(object sender, Tuple<string, int> args)
|
||||
{
|
||||
SetProgress(ProgressBar1, _results.Count, args.Item2);
|
||||
SetText(Label18, _results.Count.ToString());
|
||||
SetText(Label10, args.Item1);
|
||||
SetText(lblFotoTotaliNum, args.Item2.ToString());
|
||||
}
|
||||
|
||||
private ConcurrentBag<string> _results;
|
||||
|
||||
private void SetDefaults()
|
||||
{
|
||||
// Bind ComboBoxes to Model using proper data binding
|
||||
|
|
@ -135,6 +94,19 @@ public partial class MainForm
|
|||
ComboBox5.DataSource = new List<string> { "Alto", "Centro", "Basso" };
|
||||
ComboBox5.DataBindings.Add(new Binding("SelectedItem", bindingSource1, nameof(Model.LogoVerticalPosition),
|
||||
false, DataSourceUpdateMode.OnPropertyChanged));
|
||||
|
||||
// Bind progress bar and status labels
|
||||
ProgressBar1.DataBindings.Add(new Binding("Maximum", bindingSource1, nameof(Model.ProgressBarMaximum),
|
||||
false, DataSourceUpdateMode.OnPropertyChanged));
|
||||
ProgressBar1.DataBindings.Add(new Binding("Value", bindingSource1, nameof(Model.ProgressBarValue),
|
||||
false, DataSourceUpdateMode.OnPropertyChanged));
|
||||
|
||||
Label18.DataBindings.Add(new Binding("Text", bindingSource1, nameof(Model.ProcessedImagesCount),
|
||||
false, DataSourceUpdateMode.OnPropertyChanged));
|
||||
lblFotoTotaliNum.DataBindings.Add(new Binding("Text", bindingSource1, nameof(Model.TotalImagesCount),
|
||||
false, DataSourceUpdateMode.OnPropertyChanged));
|
||||
Label10.DataBindings.Add(new Binding("Text", bindingSource1, nameof(Model.ProcessingStatus),
|
||||
false, DataSourceUpdateMode.OnPropertyChanged));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -147,50 +119,6 @@ public partial class MainForm
|
|||
_logger.LogInformation("Programma Avviato");
|
||||
}
|
||||
|
||||
private void FixPaths()
|
||||
{
|
||||
Model.SourcePath = FixPath(Model.SourcePath);
|
||||
Model.DestinationPath = FixPath(Model.DestinationPath);
|
||||
}
|
||||
|
||||
private string FixPath(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// Trim leading/trailing quotes
|
||||
path = path.Trim().Trim('"');
|
||||
|
||||
// Normalize directory separators
|
||||
path = path.Replace('/', Path.DirectorySeparatorChar)
|
||||
.Replace('\\', Path.DirectorySeparatorChar);
|
||||
|
||||
// Remove trailing separators then add one back
|
||||
path = path.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private void lockUI()
|
||||
{
|
||||
Model.UiEnabled = false;
|
||||
//TabControl1.Enabled = false;
|
||||
//Button5.Enabled = false;
|
||||
//Button6.Enabled = false;
|
||||
//btnCreaCatalogoAsync.Enabled = false;
|
||||
}
|
||||
|
||||
private void unlockUI()
|
||||
{
|
||||
Model.UiEnabled = true;
|
||||
//TabControl1.Enabled = true;
|
||||
//Button5.Enabled = true;
|
||||
//Button6.Enabled = true;
|
||||
//btnCreaCatalogoAsync.Enabled = true;
|
||||
}
|
||||
|
||||
private string CalcTime(DateTime timeStart, DateTime timeStop, int numFoto)
|
||||
{
|
||||
long timediffH, timediffS;
|
||||
|
|
@ -224,6 +152,26 @@ public partial class MainForm
|
|||
return FixPath(dialog.SelectedPath);
|
||||
}
|
||||
|
||||
private string FixPath(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// Trim leading/trailing quotes
|
||||
path = path.Trim().Trim('"');
|
||||
|
||||
// Normalize directory separators
|
||||
path = path.Replace('/', Path.DirectorySeparatorChar)
|
||||
.Replace('\\', Path.DirectorySeparatorChar);
|
||||
|
||||
// Remove trailing separators then add one back
|
||||
path = path.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private void OnSelectSourceFolderRequested(object sender, EventArgs e)
|
||||
{
|
||||
var dialogResult = SelectFolder(Model.SourcePath);
|
||||
|
|
@ -356,76 +304,6 @@ public partial class MainForm
|
|||
}
|
||||
}
|
||||
|
||||
private void SetPicSettings(string SourcePath, string DestPath)
|
||||
{
|
||||
_picSettings.DirectorySorgente = SourcePath;
|
||||
_picSettings.DirectoryDestinazione = DestPath;
|
||||
|
||||
// Font and text settings from Model
|
||||
_picSettings.DimStandard = Model.FontSize;
|
||||
_picSettings.DimStandardMiniatura = Model.FontSizeThumbnail;
|
||||
_picSettings.IlFont = Model.FontName;
|
||||
_picSettings.Grassetto = Model.FontBold;
|
||||
_picSettings.Posizione = Model.VerticalPosition;
|
||||
_picSettings.Allineamento = Model.HorizontalAlignment;
|
||||
_picSettings.Trasparenza = Model.TextTransparency;
|
||||
_picSettings.Margine = Model.TextMargin;
|
||||
_picSettings.FontColoreRGB = ColorTranslator.FromHtml(Model.TextColorRGB);
|
||||
|
||||
// Thumbnail settings from Model
|
||||
_picSettings.AltezzaSmall = Model.ThumbnailHeight;
|
||||
_picSettings.LarghezzaSmall = Model.ThumbnailWidth;
|
||||
_picSettings.Suffisso = Model.ThumbnailPrefix;
|
||||
_picSettings.CreaMiniature = Model.CreateThumbnails;
|
||||
_picSettings.JpegQualityMin = Model.JpegQualityThumbnail;
|
||||
_picSettings.DimMin = Model.FontSizeThumbnail;
|
||||
|
||||
// Big photo settings from Model
|
||||
_picSettings.AltezzaBig = Model.PhotoBigHeight;
|
||||
_picSettings.LarghezzaBig = Model.PhotoBigWidth;
|
||||
_picSettings.FotoGrandeDimOrigina = Model.KeepOriginalDimensions;
|
||||
_picSettings.JpegQuality = Model.JpegQuality;
|
||||
_picSettings.Codice = Model.BigPhotoSuffix;
|
||||
|
||||
// Logo settings from Model
|
||||
_picSettings.LogoAggiungi = Model.AddLogo;
|
||||
_picSettings.LogoNomeFile = Model.LogoFile;
|
||||
_picSettings.LogoAltezza = Model.LogoHeight;
|
||||
_picSettings.LogoLarghezza = Model.LogoWidth;
|
||||
_picSettings.LogoMargine = Model.LogoMargin.ToString();
|
||||
_picSettings.LogoTrasparenza = Model.LogoTransparency.ToString();
|
||||
_picSettings.LogoPosizioneH = Model.LogoHorizontalPosition;
|
||||
_picSettings.LogoPosizioneV = Model.LogoVerticalPosition;
|
||||
|
||||
// Text content from Model
|
||||
_picSettings.TestoFirmaStart = Model.HorizontalText;
|
||||
_picSettings.TestoFirmaStartV = Model.VerticalText;
|
||||
|
||||
// Vertical text settings from Model
|
||||
_picSettings.DimVert = Model.VerticalTextSize;
|
||||
_picSettings.MargVert = Model.VerticalTextMargin;
|
||||
|
||||
// Boolean flags from Model
|
||||
_picSettings.UsaRotazioneAutomatica = Model.AutomaticRotation;
|
||||
_picSettings.UsaForzaJpg = Model.ForceJpeg;
|
||||
_picSettings.TestoNome = Model.ShowPhotoNumber;
|
||||
_picSettings.NomeData = Model.ShowDate;
|
||||
_picSettings.UsaOrarioTestoApplicare = Model.AddTime;
|
||||
_picSettings.UsaTempoGaraTestoApplicare = Model.AddRaceTime;
|
||||
_picSettings.OverwriteFiles = Model.OverwriteImages;
|
||||
|
||||
// Additional settings from Model
|
||||
_picSettings.UsaOrarioMiniatura = Model.AddTimeToThumbnails;
|
||||
_picSettings.DataPartenza = Model.RaceStartDate;
|
||||
_picSettings.TestoOrario = Model.TimeLabel;
|
||||
_picSettings.TestoMin = Model.ShowFileNameOnThumbnails;
|
||||
|
||||
// Thumbnail text options from Model
|
||||
_picSettings.AggiungiScritteMiniature = Model.AddTextToThumbnails;
|
||||
_picSettings.AggTempoGaraMin = Model.AddRaceTimeToThumbnails;
|
||||
_picSettings.AggNumTempMin = Model.AddNumberAndTimeToThumbnails;
|
||||
}
|
||||
|
||||
private void setLabel18Text(string text)
|
||||
{
|
||||
if (Label18.InvokeRequired)
|
||||
|
|
@ -437,99 +315,6 @@ public partial class MainForm
|
|||
Label18.Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
private NumerazioneType GetNumerazioneEnum()
|
||||
{
|
||||
NumerazioneType numerazioneType;
|
||||
if (rdbNumProgressiva.Checked)
|
||||
{
|
||||
numerazioneType = NumerazioneType.Progressiva;
|
||||
}
|
||||
else
|
||||
{
|
||||
numerazioneType = NumerazioneType.Files;
|
||||
}
|
||||
|
||||
return numerazioneType;
|
||||
}
|
||||
|
||||
|
||||
private async void Button1_Click(object sender, EventArgs e)
|
||||
{
|
||||
_logger.LogInformation("Avvio elaborazione...");
|
||||
lockUI();
|
||||
|
||||
Model.MainToken?.Dispose();
|
||||
Model.MainToken = new CancellationTokenSource();
|
||||
var token = Model.MainToken.Token;
|
||||
|
||||
// timeStart = TimeOfDay
|
||||
FixPaths();
|
||||
Label10.Text = "Elaborazione in corso...";
|
||||
lblFotoTotaliNum.Text = "0";
|
||||
Label18.Text = "0";
|
||||
Model.SpeedCounter = "-f/m";
|
||||
SetPicSettings(Model.SourcePath, Model.DestinationPath);
|
||||
ProgressBar1.Minimum = 0;
|
||||
ProgressBar1.Step = 1;
|
||||
ProgressBar1.Value = 0;
|
||||
|
||||
var imageCreationOptions = new ImageCreationStuff.Options
|
||||
{
|
||||
AggiornaSottodirectory = chkAggiornaSottodirectory.Checked,
|
||||
CreaSottocartelle = chkCreaSottocartelle.Checked,
|
||||
FilePerCartella = int.Parse(txtFilePerCartella.Text),
|
||||
SuffissoCartelle = txtSuffissoCartelle.Text,
|
||||
CifreContatore = int.Parse(txtCifreContatore.Text),
|
||||
NumerazioneType = GetNumerazioneEnum(),
|
||||
SourcePath = Model.SourcePath,
|
||||
DestinationPath = Model.DestinationPath,
|
||||
MaxThreads = Model.ThreadsCount,
|
||||
ChunksSize = Model.ChunkSize,
|
||||
LinearExecution = rdbVecchioMetodo.Checked
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
_results = [];
|
||||
_currentAmount = 0;
|
||||
_previousAmount = 0;
|
||||
timer1.Tick += Timer1OnTick;
|
||||
|
||||
timer1.Interval = 1000 * 60;
|
||||
timer1.Enabled = true;
|
||||
|
||||
var time =
|
||||
await _imageCreationService.CreaCatalogoParallel(imageCreationOptions, _results, UiUpdateEvent, token);
|
||||
Model.SpeedCounter = time;
|
||||
timer1.Enabled = false;
|
||||
}
|
||||
catch (OperationCanceledException operationCanceledException)
|
||||
{
|
||||
_logger.LogInformation("Operazione Cancellata");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Model.MainToken?.Dispose();
|
||||
Model.MainToken = null;
|
||||
|
||||
timer1.Tick -= Timer1OnTick;
|
||||
}
|
||||
|
||||
Label10.Text = "Finito";
|
||||
unlockUI();
|
||||
}
|
||||
|
||||
private int _currentAmount = 0;
|
||||
private int _previousAmount = 0;
|
||||
|
||||
private void Timer1OnTick(object sender, EventArgs e)
|
||||
{
|
||||
_previousAmount = _currentAmount;
|
||||
_currentAmount = _results.Count;
|
||||
int diff = _currentAmount - _previousAmount;
|
||||
Model.SpeedCounter = $"{diff} f/m";
|
||||
}
|
||||
}
|
||||
|
||||
public class PicInfo
|
||||
|
|
|
|||
94
imagecatalog/Mappings/DataModelMappingProfile.cs
Normal file
94
imagecatalog/Mappings/DataModelMappingProfile.cs
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
using System.Drawing;
|
||||
using AutoMapper;
|
||||
using MaddoShared;
|
||||
|
||||
namespace ImageCatalog_2.Mappings;
|
||||
|
||||
/// <summary>
|
||||
/// AutoMapper profile for mapping between DataModel and PicSettings
|
||||
/// </summary>
|
||||
public class DataModelMappingProfile : Profile
|
||||
{
|
||||
public DataModelMappingProfile()
|
||||
{
|
||||
CreateMap<DataModel, PicSettings>()
|
||||
// Paths
|
||||
.ForMember(dest => dest.DirectorySorgente, opt => opt.MapFrom(src => src.SourcePath))
|
||||
.ForMember(dest => dest.DirectoryDestinazione, opt => opt.MapFrom(src => src.DestinationPath))
|
||||
|
||||
// Font and text settings
|
||||
.ForMember(dest => dest.DimStandard, opt => opt.MapFrom(src => src.FontSize))
|
||||
.ForMember(dest => dest.DimStandardMiniatura, opt => opt.MapFrom(src => src.FontSizeThumbnail))
|
||||
.ForMember(dest => dest.IlFont, opt => opt.MapFrom(src => src.FontName))
|
||||
.ForMember(dest => dest.Grassetto, opt => opt.MapFrom(src => src.FontBold))
|
||||
.ForMember(dest => dest.Posizione, opt => opt.MapFrom(src => src.VerticalPosition))
|
||||
.ForMember(dest => dest.Allineamento, opt => opt.MapFrom(src => src.HorizontalAlignment))
|
||||
.ForMember(dest => dest.Trasparenza, opt => opt.MapFrom(src => src.TextTransparency))
|
||||
.ForMember(dest => dest.Margine, opt => opt.MapFrom(src => src.TextMargin))
|
||||
.ForMember(dest => dest.FontColoreRGB, opt => opt.MapFrom(src => ColorTranslator.FromHtml(src.TextColorRGB)))
|
||||
|
||||
// Thumbnail settings
|
||||
.ForMember(dest => dest.AltezzaSmall, opt => opt.MapFrom(src => src.ThumbnailHeight))
|
||||
.ForMember(dest => dest.LarghezzaSmall, opt => opt.MapFrom(src => src.ThumbnailWidth))
|
||||
.ForMember(dest => dest.Suffisso, opt => opt.MapFrom(src => src.ThumbnailPrefix))
|
||||
.ForMember(dest => dest.CreaMiniature, opt => opt.MapFrom(src => src.CreateThumbnails))
|
||||
.ForMember(dest => dest.JpegQualityMin, opt => opt.MapFrom(src => src.JpegQualityThumbnail))
|
||||
.ForMember(dest => dest.DimMin, opt => opt.MapFrom(src => src.FontSizeThumbnail))
|
||||
|
||||
// Big photo settings
|
||||
.ForMember(dest => dest.AltezzaBig, opt => opt.MapFrom(src => src.PhotoBigHeight))
|
||||
.ForMember(dest => dest.LarghezzaBig, opt => opt.MapFrom(src => src.PhotoBigWidth))
|
||||
.ForMember(dest => dest.FotoGrandeDimOrigina, opt => opt.MapFrom(src => src.KeepOriginalDimensions))
|
||||
.ForMember(dest => dest.JpegQuality, opt => opt.MapFrom(src => src.JpegQuality))
|
||||
.ForMember(dest => dest.Codice, opt => opt.MapFrom(src => src.BigPhotoSuffix))
|
||||
|
||||
// Logo settings
|
||||
.ForMember(dest => dest.LogoAggiungi, opt => opt.MapFrom(src => src.AddLogo))
|
||||
.ForMember(dest => dest.LogoNomeFile, opt => opt.MapFrom(src => src.LogoFile))
|
||||
.ForMember(dest => dest.LogoAltezza, opt => opt.MapFrom(src => src.LogoHeight))
|
||||
.ForMember(dest => dest.LogoLarghezza, opt => opt.MapFrom(src => src.LogoWidth))
|
||||
.ForMember(dest => dest.LogoMargine, opt => opt.MapFrom(src => src.LogoMargin.ToString()))
|
||||
.ForMember(dest => dest.LogoTrasparenza, opt => opt.MapFrom(src => src.LogoTransparency.ToString()))
|
||||
.ForMember(dest => dest.LogoPosizioneH, opt => opt.MapFrom(src => src.LogoHorizontalPosition))
|
||||
.ForMember(dest => dest.LogoPosizioneV, opt => opt.MapFrom(src => src.LogoVerticalPosition))
|
||||
|
||||
// Text content
|
||||
.ForMember(dest => dest.TestoFirmaStart, opt => opt.MapFrom(src => src.HorizontalText))
|
||||
.ForMember(dest => dest.TestoFirmaStartV, opt => opt.MapFrom(src => src.VerticalText))
|
||||
|
||||
// Vertical text settings
|
||||
.ForMember(dest => dest.DimVert, opt => opt.MapFrom(src => src.VerticalTextSize))
|
||||
.ForMember(dest => dest.MargVert, opt => opt.MapFrom(src => src.VerticalTextMargin))
|
||||
|
||||
// Boolean flags
|
||||
.ForMember(dest => dest.UsaRotazioneAutomatica, opt => opt.MapFrom(src => src.AutomaticRotation))
|
||||
.ForMember(dest => dest.UsaForzaJpg, opt => opt.MapFrom(src => src.ForceJpeg))
|
||||
.ForMember(dest => dest.TestoNome, opt => opt.MapFrom(src => src.ShowPhotoNumber))
|
||||
.ForMember(dest => dest.NomeData, opt => opt.MapFrom(src => src.ShowDate))
|
||||
.ForMember(dest => dest.UsaOrarioTestoApplicare, opt => opt.MapFrom(src => src.AddTime))
|
||||
.ForMember(dest => dest.UsaTempoGaraTestoApplicare, opt => opt.MapFrom(src => src.AddRaceTime))
|
||||
.ForMember(dest => dest.OverwriteFiles, opt => opt.MapFrom(src => src.OverwriteImages))
|
||||
|
||||
// Additional settings
|
||||
.ForMember(dest => dest.UsaOrarioMiniatura, opt => opt.MapFrom(src => src.AddTimeToThumbnails))
|
||||
.ForMember(dest => dest.DataPartenza, opt => opt.MapFrom(src => src.RaceStartDate))
|
||||
.ForMember(dest => dest.TestoOrario, opt => opt.MapFrom(src => src.TimeLabel))
|
||||
.ForMember(dest => dest.TestoMin, opt => opt.MapFrom(src => src.ShowFileNameOnThumbnails))
|
||||
|
||||
// Thumbnail text options
|
||||
.ForMember(dest => dest.AggiungiScritteMiniature, opt => opt.MapFrom(src => src.AddTextToThumbnails))
|
||||
.ForMember(dest => dest.AggTempoGaraMin, opt => opt.MapFrom(src => src.AddRaceTimeToThumbnails))
|
||||
.ForMember(dest => dest.AggNumTempMin, opt => opt.MapFrom(src => src.AddNumberAndTimeToThumbnails))
|
||||
|
||||
// Ignore unmapped properties
|
||||
.ForMember(dest => dest.DestDir, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.SecretDefault, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.SecretBig, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.SecretSmall, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.SecretPathSmall, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.SecretPathBig, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.FotoRuotaADestra, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.FotoRuotaASinistra, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.TempMinText, opt => opt.Ignore());
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ using ImageCatalog;
|
|||
using ImageCatalog_2.Services;
|
||||
using MaddoShared;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using AutoMapper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Logging.Console;
|
||||
|
|
@ -79,6 +80,9 @@ static class Program
|
|||
|
||||
private static void ConfigureServices(ServiceCollection services)
|
||||
{
|
||||
// Register AutoMapper (new AddAutoMapper overload — provide config and marker types)
|
||||
services.AddAutoMapper(cfg => { }, typeof(Program));
|
||||
|
||||
// Register your services here
|
||||
services.AddTransient<ITestService, TestService>();
|
||||
services.AddTransient<ISettingsService, SettingsService>();
|
||||
|
|
|
|||
|
|
@ -4,20 +4,66 @@ using System.ComponentModel;
|
|||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace ImageCatalog_2
|
||||
{
|
||||
public class ViewModelBase : INotifyPropertyChanged
|
||||
{
|
||||
private readonly SynchronizationContext? _synchronizationContext;
|
||||
private Control? _control;
|
||||
|
||||
protected ViewModelBase()
|
||||
{
|
||||
// Capture the synchronization context (UI thread context)
|
||||
_synchronizationContext = SynchronizationContext.Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a Control to use for thread marshalling in WinForms applications.
|
||||
/// This is required for proper cross-thread handling with data binding.
|
||||
/// </summary>
|
||||
public void SetControl(Control control)
|
||||
{
|
||||
_control = control;
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
// This method is called by the Set accessor of each property.
|
||||
// The CallerMemberName attribute that is applied to the optional propertyName
|
||||
// parameter causes the property name of the caller to be substituted as an argument.
|
||||
protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
|
||||
{
|
||||
if (PropertyChanged != null)
|
||||
if (PropertyChanged == null)
|
||||
return;
|
||||
|
||||
// If we have a Control reference (WinForms), use Control.Invoke for proper marshalling
|
||||
if (_control != null)
|
||||
{
|
||||
if (_control.InvokeRequired)
|
||||
{
|
||||
_control.Invoke(() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)));
|
||||
}
|
||||
else
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
// Fallback to SynchronizationContext if available
|
||||
else if (_synchronizationContext != null && SynchronizationContext.Current != _synchronizationContext)
|
||||
{
|
||||
// We're on a different thread, marshal to the UI thread
|
||||
_synchronizationContext.Send(_ =>
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're already on the UI thread or no sync context available
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue