From 909e438f5ba1c24d178c5012536abdc863c62b8b Mon Sep 17 00:00:00 2001 From: Miguel Date: Wed, 18 Jun 2025 13:40:49 +0200 Subject: [PATCH] =?UTF-8?q?Se=20a=C3=B1adi=C3=B3=20la=20capacidad=20de=20g?= =?UTF-8?q?estionar=20datos=20de=20im=C3=A1genes=20en=20la=20clase=20Datos?= =?UTF-8?q?DeTrabajo,=20permitiendo=20la=20carga=20de=20datos=20desde=20ar?= =?UTF-8?q?chivos=20JSON=20y=20la=20integraci=C3=B3n=20con=20MainViewModel?= =?UTF-8?q?.=20Se=20implement=C3=B3=20un=20nuevo=20m=C3=A9todo=20para=20es?= =?UTF-8?q?tablecer=20el=20ViewModel=20principal=20y=20se=20mejor=C3=B3=20?= =?UTF-8?q?la=20l=C3=B3gica=20de=20renombrado=20de=20im=C3=A1genes=20en=20?= =?UTF-8?q?la=20interfaz=20de=20usuario,=20incluyendo=20un=20comando=20par?= =?UTF-8?q?a=20renombrar=20im=C3=A1genes=20desde=20el=20contexto=20del=20L?= =?UTF-8?q?istBox.=20Adem=C3=A1s,=20se=20incorpor=C3=B3=20un=20convertidor?= =?UTF-8?q?=20para=20mostrar=20nombres=20de=20im=C3=A1genes=20personalizad?= =?UTF-8?q?os=20en=20la=20interfaz.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Converters/ImageDisplayNameConverter.cs | 28 +++++++++ DatosDeTrabajo.cs | 34 +++++++++++ MainViewModel.cs | 76 +++++++++++++++++++++++++ MainWindow.xaml | 17 +++++- Models/ImageData.cs | 57 +++++++++++++++++++ ObjectManipulationManager.cs | 2 +- PopUps/RenameImageWindow.xaml | 26 +++++++++ PopUps/RenameImageWindow.xaml.cs | 34 +++++++++++ Serialization/StateSerializer.cs | 35 ++++++++++-- 9 files changed, 301 insertions(+), 8 deletions(-) create mode 100644 Converters/ImageDisplayNameConverter.cs create mode 100644 Models/ImageData.cs create mode 100644 PopUps/RenameImageWindow.xaml create mode 100644 PopUps/RenameImageWindow.xaml.cs diff --git a/Converters/ImageDisplayNameConverter.cs b/Converters/ImageDisplayNameConverter.cs new file mode 100644 index 0000000..4aeb080 --- /dev/null +++ b/Converters/ImageDisplayNameConverter.cs @@ -0,0 +1,28 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace CtrEditor.Converters +{ + public class ImageDisplayNameConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is string imageName) + { + // Buscar el MainViewModel en el Application.Current.MainWindow.DataContext + if (Application.Current?.MainWindow?.DataContext is MainViewModel viewModel) + { + return viewModel.GetImageDisplayName(imageName); + } + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/DatosDeTrabajo.cs b/DatosDeTrabajo.cs index 385d8c3..7cb93c4 100644 --- a/DatosDeTrabajo.cs +++ b/DatosDeTrabajo.cs @@ -11,6 +11,7 @@ namespace CtrEditor public class DatosDeTrabajo { public Dictionary Imagenes { get; private set; } + private MainViewModel _mainViewModel; public DatosDeTrabajo() { @@ -18,6 +19,11 @@ namespace CtrEditor CargarImagenes(); // Inicializar la carga de imágenes basada en el directorio persistente } + public void SetMainViewModel(MainViewModel mainViewModel) + { + _mainViewModel = mainViewModel; + } + public string ObtenerPathImagenConExtension(string key, string extension) { if (Imagenes.TryGetValue(key, out string imagePath)) @@ -51,6 +57,34 @@ namespace CtrEditor Imagenes[nombreArchivo] = archivo; } } + + // Cargar datos de imágenes existentes desde archivos JSON + if (_mainViewModel != null) + { + CargarDatosImagenesExistentes(); + } + } + } + + private void CargarDatosImagenesExistentes() + { + foreach (var imageName in Imagenes.Keys) + { + string jsonPath = ObtenerPathImagenConExtension(imageName, ".json"); + if (!string.IsNullOrEmpty(jsonPath) && File.Exists(jsonPath)) + { + try + { + // Solo cargamos los datos de imagen si existe el archivo JSON + // El StateSerializer se encargará de cargar los datos completos + _mainViewModel.GetOrCreateImageData(imageName); + } + catch (Exception ex) + { + // Log del error pero no fallar la carga completa + System.Diagnostics.Debug.WriteLine($"Error al pre-cargar datos de imagen {imageName}: {ex.Message}"); + } + } } } } diff --git a/MainViewModel.cs b/MainViewModel.cs index 4d7373e..6f2b176 100644 --- a/MainViewModel.cs +++ b/MainViewModel.cs @@ -81,6 +81,12 @@ namespace CtrEditor [ObservableProperty] public ObservableCollection listaOsBase; + // Diccionario para almacenar datos expandidos de imágenes + public Dictionary _imageDataDictionary = new Dictionary(); + + // Comando para renombrar imagen + public ICommand RenameImageCommand { get; private set; } + public ICommand StartSimulationCommand { get; } public ICommand StopSimulationCommand { get; } public ICommand ItemDoubleClickCommand { get; private set; } @@ -383,6 +389,7 @@ namespace CtrEditor TBMultiPageAnalizeCommand = new RelayCommand(MultiPageAnalizeCommand); TBMultiPageMatrixCommand = new RelayCommand(MultiPageMatrixCommand); TBLibraryManagerCommand = new RelayCommand(ShowLibraryManager); + RenameImageCommand = new RelayCommand(RenameImage); stopwatch_Sim = new Stopwatch(); stopwatch_Sim.Start(); @@ -398,6 +405,68 @@ namespace CtrEditor _stateManager = new StateManager(EstadoPersistente.Instance.directorio, this); _stateSerializer = new StateSerializer(this, datosDeTrabajo, simulationManager); + + // Conectar DatosDeTrabajo con este ViewModel para el escaneo de imágenes + datosDeTrabajo.SetMainViewModel(this); + } + + // Métodos para manejo de datos de imágenes + private void RenameImage(string imageName) + { + if (string.IsNullOrEmpty(imageName)) return; + + var imageData = GetOrCreateImageData(imageName); + var currentCustomName = imageData.CustomName; + + var dialog = new PopUps.RenameImageWindow(imageName, currentCustomName); + dialog.Owner = MainWindow; + + if (dialog.ShowDialog() == true) + { + string newName = dialog.NewImageName?.Trim() ?? string.Empty; + + if (newName != currentCustomName) + { + if (string.IsNullOrEmpty(newName)) + { + // Si el nuevo nombre está vacío, removemos la entrada personalizada + imageData.CustomName = string.Empty; + if (string.IsNullOrEmpty(imageData.CustomName) && imageData.Tags.Count == 0) + { + _imageDataDictionary.Remove(imageName); + } + } + else + { + imageData.CustomName = newName; + } + + // Forzar actualización del UI usando CollectionViewSource + var collectionView = System.Windows.Data.CollectionViewSource.GetDefaultView(ListaImagenes); + collectionView?.Refresh(); + + HasUnsavedChanges = true; + } + } + } + + public string GetImageDisplayName(string imageName) + { + if (_imageDataDictionary.TryGetValue(imageName, out var imageData)) + { + return imageData.DisplayName; + } + return imageName; + } + + public Models.ImageData GetOrCreateImageData(string imageName) + { + if (!_imageDataDictionary.TryGetValue(imageName, out var imageData)) + { + imageData = new Models.ImageData(imageName); + _imageDataDictionary[imageName] = imageData; + } + return imageData; } private void OnVisFilterChanged(osVisFilterViewModel filter) // Changed signature to accept viewmodel directly @@ -1202,6 +1271,13 @@ namespace CtrEditor // Nueva propiedad para almacenar los datos locales de objetos globales public ObservableCollection? DatosLocalesObjetos { get; set; } + + // Diccionario para almacenar datos expandidos de imágenes + public Dictionary? ImageDataDictionary { get; set; } + + // Compatibilidad con versiones anteriores - OBSOLETO + [System.Obsolete("Use ImageDataDictionary instead")] + public Dictionary? ImageCustomNames { get; set; } } public class TipoSimulable diff --git a/MainWindow.xaml b/MainWindow.xaml index cc4fa6d..39a3283 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -6,6 +6,7 @@ xmlns:local="clr-namespace:CtrEditor" xmlns:controls="clr-namespace:CtrEditor.Controls" xmlns:uc="clr-namespace:CtrEditor.ObjetosSim.UserControls" + xmlns:converters="clr-namespace:CtrEditor.Converters" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:ObjetosSim="clr-namespace:CtrEditor.ObjetosSim" @@ -48,6 +49,9 @@ + + + @@ -87,7 +91,18 @@ + SelectedItem="{Binding SelectedImage}"> + + + + + + + + + + + diff --git a/Models/ImageData.cs b/Models/ImageData.cs new file mode 100644 index 0000000..1683da0 --- /dev/null +++ b/Models/ImageData.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace CtrEditor.Models +{ + public class ImageData : INotifyPropertyChanged + { + private string _customName; + private List _tags; + + public string FileName { get; set; } + + public string CustomName + { + get => _customName; + set + { + _customName = value; + OnPropertyChanged(); + } + } + + public List Tags + { + get => _tags ?? new List(); + set + { + _tags = value; + OnPropertyChanged(); + } + } + + public string DisplayName => !string.IsNullOrEmpty(CustomName) ? CustomName : FileName; + + public ImageData() + { + FileName = string.Empty; + _customName = string.Empty; + _tags = new List(); + } + + public ImageData(string fileName, string customName = null, List tags = null) + { + FileName = fileName; + _customName = customName ?? string.Empty; + _tags = tags ?? new List(); + } + + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/ObjectManipulationManager.cs b/ObjectManipulationManager.cs index 6501644..97022ce 100644 --- a/ObjectManipulationManager.cs +++ b/ObjectManipulationManager.cs @@ -202,7 +202,7 @@ namespace CtrEditor PurgeDeletedObjects(); // Asegurarse de que el canvas haya actualizado su layout _canvas.UpdateLayout(); - + RemoveResizeRectangles(); if (_selectedObjects.Any()) { diff --git a/PopUps/RenameImageWindow.xaml b/PopUps/RenameImageWindow.xaml new file mode 100644 index 0000000..b9cbf27 --- /dev/null +++ b/PopUps/RenameImageWindow.xaml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + +