CtrEditor/PopUps/LibraryWindowViewModel.cs

581 lines
22 KiB
C#

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CtrEditor.Controls;
using CtrEditor.ObjetosSim;
using CtrEditor.Serialization;
using Newtonsoft.Json;
using Ookii.Dialogs.Wpf;
namespace CtrEditor.PopUps
{
public partial class LibraryWindowViewModel : ObservableObject
{
private readonly MainViewModel _mainViewModel;
private List<osBase> _clipboardObjects = new List<osBase>();
[ObservableProperty]
private ObservableCollection<LibraryDirectoryItem> libraryDirectories;
[ObservableProperty]
private LibraryDirectoryItem selectedLibraryDirectory;
[ObservableProperty]
private ObservableCollection<LibraryItem> libraries;
[ObservableProperty]
private LibraryItem selectedLibrary;
[ObservableProperty]
private ObservableCollection<ObjectTypeGroup> filteredObjectsByType;
[ObservableProperty]
private osBase selectedObject;
// Commands
public ICommand AddLibraryDirectoryCommand { get; }
public ICommand RemoveLibraryDirectoryCommand { get; }
public ICommand CopyObjectCommand { get; }
public ICommand PasteObjectCommand { get; }
public ICommand DeleteObjectCommand { get; }
public ICommand CreateNewLibraryCommand { get; }
public LibraryWindowViewModel(MainViewModel mainViewModel)
{
_mainViewModel = mainViewModel;
LibraryDirectories = new ObservableCollection<LibraryDirectoryItem>();
Libraries = new ObservableCollection<LibraryItem>();
FilteredObjectsByType = new ObservableCollection<ObjectTypeGroup>();
// Initialize commands
AddLibraryDirectoryCommand = new RelayCommand(AddLibraryDirectory);
RemoveLibraryDirectoryCommand = new RelayCommand(RemoveLibraryDirectory, () => SelectedLibraryDirectory != null);
CopyObjectCommand = new RelayCommand(CopyObject, () => SelectedObject != null);
PasteObjectCommand = new RelayCommand(PasteObject, () => SelectedLibrary != null && _clipboardObjects.Any());
DeleteObjectCommand = new RelayCommand(DeleteObject, () => SelectedObject != null && SelectedLibrary != null && !SelectedLibrary.IsCurrentProject);
CreateNewLibraryCommand = new RelayCommand(CreateNewLibrary, () => SelectedLibraryDirectory != null);
LoadLibraryDirectories();
RefreshLibraries();
}
partial void OnSelectedLibraryDirectoryChanged(LibraryDirectoryItem value)
{
RefreshLibraries();
CommandManager.InvalidateRequerySuggested();
}
partial void OnSelectedLibraryChanged(LibraryItem value)
{
LoadObjectsFromLibrary();
CommandManager.InvalidateRequerySuggested();
}
private osVisFilter _objectFilter;
public void SetObjectFilter(osVisFilter filter)
{
_objectFilter = filter;
if (SelectedLibrary != null)
{
UpdateFilterTypes(filter);
}
}
private void LoadLibraryDirectories()
{
LibraryDirectories.Clear();
// Add current project directory
LibraryDirectories.Add(new LibraryDirectoryItem
{
Path = _mainViewModel.directorioTrabajo,
DisplayName = "Proyecto Actual",
IsCurrentProject = true
});
// Add saved library directories
foreach (var directory in EstadoPersistente.Instance.LibraryDirectories)
{
if (Directory.Exists(directory))
{
LibraryDirectories.Add(new LibraryDirectoryItem
{
Path = directory,
DisplayName = Path.GetFileName(directory),
IsCurrentProject = false
});
}
}
if (LibraryDirectories.Any())
{
SelectedLibraryDirectory = LibraryDirectories.First();
}
}
private void RefreshLibraries()
{
Libraries.Clear();
if (SelectedLibraryDirectory == null) return;
if (SelectedLibraryDirectory.IsCurrentProject)
{
// Add current project as a library
Libraries.Add(new LibraryItem
{
Name = "Proyecto Actual",
FilePath = null,
IsCurrentProject = true,
Objects = _mainViewModel.ObjetosSimulables.ToList()
});
// Add JSON files from current project directory
AddJsonFilesFromDirectory(SelectedLibraryDirectory.Path);
}
else
{
// Add JSON files from selected library directory
AddJsonFilesFromDirectory(SelectedLibraryDirectory.Path);
}
}
private void AddJsonFilesFromDirectory(string directoryPath)
{
if (!Directory.Exists(directoryPath)) return;
var jsonFiles = Directory.GetFiles(directoryPath, "*.json", SearchOption.AllDirectories);
foreach (var jsonFile in jsonFiles)
{
try
{
var relativePath = Path.GetRelativePath(directoryPath, jsonFile);
var displayName = Path.GetFileNameWithoutExtension(jsonFile);
var libraryItem = new LibraryItem
{
Name = displayName,
FilePath = jsonFile,
IsCurrentProject = false,
Objects = LoadObjectsFromJsonFile(jsonFile)
};
Libraries.Add(libraryItem);
}
catch (Exception ex)
{
// Log error but continue processing other files
System.Diagnostics.Debug.WriteLine($"Error loading library {jsonFile}: {ex.Message}");
}
}
}
private List<osBase> LoadObjectsFromJsonFile(string filePath)
{
var objects = new List<osBase>();
try
{
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
NullValueHandling = NullValueHandling.Ignore
};
string json = File.ReadAllText(filePath);
var simulationData = JsonConvert.DeserializeObject<SimulationData>(json, settings);
if (simulationData?.ObjetosSimulables != null)
{
objects.AddRange(simulationData.ObjetosSimulables);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Error loading objects from {filePath}: {ex.Message}");
}
return objects;
}
private void LoadObjectsFromLibrary()
{
FilteredObjectsByType.Clear();
if (SelectedLibrary == null) return;
// Update filter types and tags when library changes
if (_objectFilter != null)
{
UpdateFilterTypes(_objectFilter);
}
ApplyFiltering(SelectedLibrary.Objects);
}
public void UpdateFilterTypes(osVisFilter filter)
{
if (SelectedLibrary?.Objects != null)
{
var types = SelectedLibrary.Objects.Select(o => o.GetType()).Distinct();
filter.UpdateAvailableTypes(types);
filter.UpdateAvailableTags(SelectedLibrary.Objects);
}
}
private void ApplyFiltering(List<osBase> objects)
{
// Group objects by type
var groupedObjects = objects
.GroupBy(obj => obj.GetType())
.Select(group => new ObjectTypeGroup
{
Type = group.Key,
TypeName = GetTypeDisplayName(group.Key),
Objects = new ObservableCollection<osBase>(group.ToList())
})
.OrderBy(group => group.TypeName)
.ToList();
FilteredObjectsByType.Clear();
foreach (var group in groupedObjects)
{
FilteredObjectsByType.Add(group);
}
}
public void OnFilterChanged(osVisFilterViewModel filterViewModel)
{
if (SelectedLibrary == null) return;
var filteredObjects = new List<osBase>();
foreach (var obj in SelectedLibrary.Objects)
{
bool isVisible = true;
// Apply Show All filter
if (!filterViewModel.ShowAll)
{
// Check type filter
var typeFilter = filterViewModel.TypeFilters.FirstOrDefault(tf => tf.Type == obj.GetType());
if (typeFilter == null || !typeFilter.IsSelected)
{
isVisible = false;
}
// Check tag filters
if (filterViewModel.TagFilters.Any() && filterViewModel.TagFilters.Any(tf => tf.IsSelected))
{
var selectedTags = filterViewModel.TagFilters.Where(tf => tf.IsSelected).Select(tf => tf.TagName).ToList();
bool hasMatchingTag = obj.ListaEtiquetas.Any(tag => selectedTags.Contains(tag));
if (!hasMatchingTag)
{
isVisible = false;
}
}
// Check search tags
if (!string.IsNullOrWhiteSpace(filterViewModel.SearchTags))
{
var searchTags = filterViewModel.SearchTags
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Where(tag => tag.StartsWith("#") && tag.Length > 1)
.Select(tag => tag.Substring(1).ToLowerInvariant())
.ToList();
if (searchTags.Any())
{
bool hasMatchingSearchTag = searchTags.Any(searchTag => obj.ListaEtiquetas.Contains(searchTag));
if (!hasMatchingSearchTag)
{
isVisible = false;
}
}
}
// Check other filters
if (filterViewModel.ShowCloned && !obj.Cloned)
isVisible = false;
if (filterViewModel.ShowAutoCreated && !obj.AutoCreated)
isVisible = false;
if (filterViewModel.ShowEnableOnAllPages && !obj.Enable_On_All_Pages)
isVisible = false;
if (filterViewModel.ShowOnThisPage && !obj.Show_On_This_Page)
isVisible = false;
}
if (isVisible)
{
filteredObjects.Add(obj);
}
}
ApplyFiltering(filteredObjects);
}
private string GetTypeDisplayName(Type type)
{
try
{
var methodInfo = type.GetMethod("NombreClase", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
return methodInfo != null ? methodInfo.Invoke(null, null)?.ToString() : type.Name;
}
catch
{
return type.Name;
}
}
private void AddLibraryDirectory()
{
var dialog = new VistaFolderBrowserDialog();
if (dialog.ShowDialog() == true)
{
var path = dialog.SelectedPath;
if (!EstadoPersistente.Instance.LibraryDirectories.Contains(path))
{
EstadoPersistente.Instance.LibraryDirectories.Add(path);
EstadoPersistente.Instance.GuardarEstado();
LoadLibraryDirectories();
}
}
}
private void RemoveLibraryDirectory()
{
if (SelectedLibraryDirectory != null && !SelectedLibraryDirectory.IsCurrentProject)
{
var result = MessageBox.Show(
$"¿Está seguro de que desea eliminar el directorio '{SelectedLibraryDirectory.DisplayName}' de la lista de bibliotecas?",
"Confirmar eliminación",
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
EstadoPersistente.Instance.LibraryDirectories.Remove(SelectedLibraryDirectory.Path);
EstadoPersistente.Instance.GuardarEstado();
LoadLibraryDirectories();
}
}
}
private void CopyObject()
{
if (SelectedObject != null)
{
try
{
_clipboardObjects.Clear();
// Prepare object for serialization
SelectedObject.SalvarDatosNoSerializables();
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
TypeNameHandling = TypeNameHandling.All
};
// Serialize and deserialize to create a deep copy
var serializedData = JsonConvert.SerializeObject(SelectedObject, settings);
var copiedObject = JsonConvert.DeserializeObject<osBase>(serializedData, settings);
if (copiedObject != null)
{
_clipboardObjects.Add(copiedObject);
MessageBox.Show("Objeto copiado al portapapeles.", "Información", MessageBoxButton.OK, MessageBoxImage.Information);
}
// Restore object state
SelectedObject.RestaurarDatosNoSerializables();
CommandManager.InvalidateRequerySuggested();
}
catch (Exception ex)
{
MessageBox.Show($"Error al copiar objeto: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
private void PasteObject()
{
if (SelectedLibrary != null && _clipboardObjects.Any())
{
try
{
foreach (var objToPaste in _clipboardObjects)
{
// Create a new unique ID for the pasted object
objToPaste.Id.ObtenerNuevaID();
// Update name to include ID
string nombre = Regex.IsMatch(objToPaste.Nombre, @"_\d+$")
? Regex.Replace(objToPaste.Nombre, @"_\d+$", $"_{objToPaste.Id.Value}")
: objToPaste.Nombre + "_" + objToPaste.Id.Value;
objToPaste.Nombre = nombre;
if (SelectedLibrary.IsCurrentProject)
{
// Add to current project
_mainViewModel.ObjetosSimulables.Add(objToPaste);
_mainViewModel.CrearUserControlDesdeObjetoSimulable(objToPaste);
_mainViewModel.HasUnsavedChanges = true;
}
else
{
// Add to selected library file
SelectedLibrary.Objects.Add(objToPaste);
SaveLibraryToFile(SelectedLibrary);
}
}
RefreshLibraries();
LoadObjectsFromLibrary();
MessageBox.Show($"{_clipboardObjects.Count} objeto(s) pegado(s).", "Información", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
MessageBox.Show($"Error al pegar objeto: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
private void DeleteObject()
{
if (SelectedObject != null && SelectedLibrary != null && !SelectedLibrary.IsCurrentProject)
{
var result = MessageBox.Show(
$"¿Está seguro de que desea eliminar el objeto '{SelectedObject.Nombre}'?",
"Confirmar eliminación",
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
try
{
SelectedLibrary.Objects.Remove(SelectedObject);
SaveLibraryToFile(SelectedLibrary);
LoadObjectsFromLibrary();
SelectedObject = null;
MessageBox.Show("Objeto eliminado.", "Información", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
MessageBox.Show($"Error al eliminar objeto: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}
private void CreateNewLibrary()
{
if (SelectedLibraryDirectory == null) return;
var dialog = new Microsoft.Win32.SaveFileDialog
{
DefaultExt = ".json",
Filter = "JSON files (*.json)|*.json",
InitialDirectory = SelectedLibraryDirectory.Path,
Title = "Crear nueva biblioteca"
};
if (dialog.ShowDialog() == true)
{
try
{
var emptyLibrary = new SimulationData
{
ObjetosSimulables = new ObservableCollection<osBase>(),
UnitConverter = PixelToMeter.Instance.calc,
PLC_ConnectionData = new LibS7Adv.PLCViewModel()
};
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
TypeNameHandling = TypeNameHandling.All
};
string json = JsonConvert.SerializeObject(emptyLibrary, settings);
File.WriteAllText(dialog.FileName, json);
RefreshLibraries();
MessageBox.Show("Nueva biblioteca creada.", "Información", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
MessageBox.Show($"Error al crear biblioteca: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
private void SaveLibraryToFile(LibraryItem library)
{
if (library.IsCurrentProject || string.IsNullOrEmpty(library.FilePath)) return;
try
{
var simulationData = new SimulationData
{
ObjetosSimulables = new ObservableCollection<osBase>(library.Objects),
UnitConverter = PixelToMeter.Instance.calc,
PLC_ConnectionData = new LibS7Adv.PLCViewModel()
};
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
TypeNameHandling = TypeNameHandling.All
};
string json = JsonConvert.SerializeObject(simulationData, settings);
File.WriteAllText(library.FilePath, json);
}
catch (Exception ex)
{
MessageBox.Show($"Error al guardar biblioteca: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
// Support classes
public class LibraryDirectoryItem
{
public string Path { get; set; }
public string DisplayName { get; set; }
public bool IsCurrentProject { get; set; }
}
public class LibraryItem
{
public string Name { get; set; }
public string FilePath { get; set; }
public bool IsCurrentProject { get; set; }
public List<osBase> Objects { get; set; } = new List<osBase>();
public string DisplayName => IsCurrentProject ? $"{Name} (Proyecto)" : Name;
}
public class ObjectTypeGroup
{
public Type Type { get; set; }
public string TypeName { get; set; }
public ObservableCollection<osBase> Objects { get; set; } = new ObservableCollection<osBase>();
}
}