using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Text; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; 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; public partial class MainForm { private readonly DataModel Model; private readonly ILogger _logger; private readonly ParametriSetup _parametriSetup; private readonly PicSettings _picSettings; public MainForm(DataModel model, ImageCreationStuff imageCreationStuff, PicSettings picSettings, ParametriSetup parametriSetup, ILogger logger) { Model = model; _parametriSetup = parametriSetup; _picSettings = picSettings; _logger = logger; _logger.LogDebug("Start"); InitializeComponent(); // Set this form as the control for thread marshalling in the DataModel Model.SetControl(this); BindControls(); 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; } private void SetDefaults() { // Bind ComboBoxes to Model using proper data binding ComboBox1.DataSource = new List(Model.VerticalPositions); ComboBox1.DataBindings.Add(new Binding("SelectedItem", bindingSource1, nameof(Model.VerticalPosition), false, DataSourceUpdateMode.OnPropertyChanged)); ComboBox2.DataSource = new List(Model.HorizontalAlignments); ComboBox2.DataBindings.Add(new Binding("SelectedItem", bindingSource1, nameof(Model.HorizontalAlignment), false, DataSourceUpdateMode.OnPropertyChanged)); ComboBox3.DataSource = new List(Model.AvailableFonts); ComboBox3.DataBindings.Add(new Binding("SelectedItem", bindingSource1, nameof(Model.FontName), false, DataSourceUpdateMode.OnPropertyChanged)); ComboBox4.DataSource = new List(Model.HorizontalAlignments); ComboBox4.DataBindings.Add(new Binding("SelectedItem", bindingSource1, nameof(Model.LogoHorizontalPosition), false, DataSourceUpdateMode.OnPropertyChanged)); ComboBox5.DataSource = new List { "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)); } private void Form1_Load(object sender, EventArgs e) { bindingSource1.DataSource = Model; Application.EnableVisualStyles(); SetDefaults(); _logger.LogInformation("Programma Avviato"); } private string CalcTime(DateTime timeStart, DateTime timeStop, int numFoto) { long timediffH, timediffS; long timediffM; TimeSpan timeDiff = timeStop - timeStart; timediffM = (int)timeDiff.TotalMinutes; timediffS = (int)timeDiff.TotalSeconds; timediffH = (int)timeDiff.TotalHours; // timediffM = DateAndTime.DateDiff(DateInterval.Minute, timeStart, timeStop); // timediffS = DateAndTime.DateDiff(DateInterval.Second, timeStart, timeStop); // timediffH = DateAndTime.DateDiff(DateInterval.Hour, timeStart, timeStop); double fotoSec = numFoto / (double)timediffS; double fotoMin = numFoto / (double)timediffM; double fotoOra = numFoto / (double)timediffH; string s = "S: " + timediffS.ToString() + "; F/s: " + fotoSec.ToString( "0.000"); // + " F/m: " + fotoMin.ToString("0.00") + " F/h: " + fotoOra.ToString("0.00") return s; } private string SelectFolder(string startingFolder) { var dialog = new FolderBrowserDialog(); dialog.InitialDirectory = startingFolder; if (dialog.ShowDialog() != DialogResult.OK) return string.Empty; 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); if (!string.IsNullOrWhiteSpace(dialogResult)) { Model.SourcePath = dialogResult; } } private void OnSelectDestinationFolderRequested(object sender, EventArgs e) { var dialogResult = SelectFolder(Model.DestinationPath); if (!string.IsNullOrWhiteSpace(dialogResult)) { Model.DestinationPath = dialogResult; } } private void OnSelectLogoFileRequested(object sender, EventArgs e) { var dialog = new OpenFileDialog(); dialog.Filter = "Image Files|*.jpg;*.jpeg;*.png;*.bmp;*.gif"; if (Model.LogoFile.Length > 0) { dialog.FileName = Model.LogoFile; } if (dialog.ShowDialog() == DialogResult.OK) { Model.LogoFile = dialog.FileName; UpdateLogoPictureBox(Model.LogoFile); } } private async void OnSaveSettingsRequested(object sender, string e) { var saveDialog = new SaveFileDialog { Filter = "Setup (*.xml)|*.xml|All valid files (*.*)|*.*", FilterIndex = 0, RestoreDirectory = true }; if (saveDialog.ShowDialog() != DialogResult.OK) return; await Model.SaveSettingsToFileAsync(saveDialog.FileName); Text = "Image Catalog - " + Path.GetFileName(saveDialog.FileName); } private async void OnLoadSettingsRequested(object sender, string e) { var openDialog = new OpenFileDialog { Filter = "Setup (*.xml)|*.xml|All valid files (*.*)|*.*", FilterIndex = 0, RestoreDirectory = true }; if (openDialog.ShowDialog() != DialogResult.OK) return; try { await Model.LoadSettingsFromFileAsync(openDialog.FileName); // Explicitly ensure UI is enabled after loading Model.UiEnabled = true; // Update logo preview if logo file exists if (File.Exists(Model.LogoFile)) { UpdateLogoPictureBox(Model.LogoFile); } Text = "Image Catalog - " + Path.GetFileName(openDialog.FileName); _logger.LogInformation($"Settings loaded successfully from {openDialog.FileName}"); } catch (Exception ex) { _logger.LogError(ex, "Error loading settings"); MessageBox.Show($"Error loading settings: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void OnSelectColorRequested(object sender, EventArgs e) { var colorDialog = new ColorDialog { AllowFullOpen = true }; if (!string.IsNullOrWhiteSpace(Model.TextColorRGB)) { try { colorDialog.Color = ColorTranslator.FromHtml(Model.TextColorRGB); } catch { // Invalid color, use default } } if (colorDialog.ShowDialog() == DialogResult.OK) { Model.TextColorRGB = ColorTranslator.ToHtml(colorDialog.Color); TextBox34.BackColor = colorDialog.Color; } } private void UpdateLogoPictureBox(string logoPath) { try { PictureBox1.Image = Image.FromFile(logoPath); if (PictureBox1.Image.Height >= PictureBox1.Image.Width) { PictureBox1.Height = 160; PictureBox1.Width = (int)(160 * PictureBox1.Image.Width / (double)PictureBox1.Image.Height); } else { PictureBox1.Width = 160; PictureBox1.Height = (int)(160 * PictureBox1.Image.Height / (double)PictureBox1.Image.Width); } } catch { // Image loading failed, ignore } } private void setLabel18Text(string text) { if (Label18.InvokeRequired) { Label18.Invoke(new Action(setLabel18Text), text); } else { Label18.Text = text; } } } public class PicInfo { public DirectoryInfo DirSource, DirDest, DirDestStart; public string NomeImmagine; public PicInfo(DirectoryInfo Dir_Source, DirectoryInfo Dir_Dest, DirectoryInfo Dir_DestStart, string Nome_Immagine) { DirSource = Dir_Source; DirDest = Dir_Dest; DirDestStart = Dir_DestStart; NomeImmagine = Nome_Immagine; } }