From 16f5131803e16a7b301b839222a23eba1eadb8dc Mon Sep 17 00:00:00 2001 From: Miguel Date: Fri, 13 Jun 2025 22:33:13 +0200 Subject: [PATCH] =?UTF-8?q?Implementada=20la=20funcionalidad=20de=20copiar?= =?UTF-8?q?=20y=20pegar=20objetos=20seleccionados=20como=20JSON=20desde=20?= =?UTF-8?q?el=20portapapeles,=20incluyendo=20opciones=20para=20reemplazar?= =?UTF-8?q?=20IDs=20existentes.=20Se=20agreg=C3=B3=20manejo=20de=20errores?= =?UTF-8?q?=20y=20validaci=C3=B3n=20del=20contenido=20del=20portapapeles?= =?UTF-8?q?=20para=20asegurar=20la=20correcta=20deserializaci=C3=B3n=20de?= =?UTF-8?q?=20los=20objetos.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MainWindow.xaml.cs | 229 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 801cdf5..f1207f7 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -11,6 +11,11 @@ using System.Windows.Threading; using MouseEventArgs = System.Windows.Input.MouseEventArgs; using UserControl = System.Windows.Controls.UserControl; using CtrEditor.Controls; // Add this using statement +using Newtonsoft.Json; +using System.Text.RegularExpressions; +using System.Collections.Generic; +using System; +using System.Linq; namespace CtrEditor { @@ -646,6 +651,27 @@ namespace CtrEditor contextMenu.Items.Add(new Separator()); + // Agregar opción de copiar + var copyMenuItem = new MenuItem { Header = "Copiar (Ctrl+C)" }; + copyMenuItem.Click += (s, e) => CopySelectedObjectsAsJson(); + contextMenu.Items.Add(copyMenuItem); + + contextMenu.Items.Add(new Separator()); + } + + // Agregar opciones de pegado + if (Clipboard.ContainsText()) + { + var pasteMenuItem = new MenuItem { Header = "Pegar (Ctrl+V)" }; + pasteMenuItem.Click += (s, e) => PasteObjectsFromJson(); + contextMenu.Items.Add(pasteMenuItem); + + var pasteReplaceMenuItem = new MenuItem { Header = "Pegar con Reemplazo" }; + pasteReplaceMenuItem.Click += (s, e) => PasteObjectsFromJson(true); + contextMenu.Items.Add(pasteReplaceMenuItem); + + contextMenu.Items.Add(new Separator()); + // Opciones de bloqueo/desbloqueo var lockSubmenu = new MenuItem { Header = "Bloqueo" }; @@ -718,6 +744,16 @@ namespace CtrEditor _objectManager.RemoveResizeRectangles(); e.Handled = true; } + else if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.C) + { + CopySelectedObjectsAsJson(); + e.Handled = true; + } + else if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.V) + { + PasteObjectsFromJson(); + e.Handled = true; + } else if (_objectManager.SelectedObjects.Any()) { const float moveDistance = 0.01f; @@ -745,6 +781,199 @@ namespace CtrEditor } public Image ImagenDeFondo => imagenDeFondo; + + private void CopySelectedObjectsAsJson() + { + if (!_objectManager.SelectedObjects.Any()) + return; + + try + { + var objectsToCopy = new List(); + + // Preparar objetos para serialización + foreach (var obj in _objectManager.SelectedObjects) + { + obj.SalvarDatosNoSerializables(); + objectsToCopy.Add(obj); + } + + // Crear configuración de serialización igual a la usada en el guardado + var settings = new JsonSerializerSettings + { + Formatting = Formatting.Indented, + NullValueHandling = NullValueHandling.Ignore, + TypeNameHandling = TypeNameHandling.Auto, + ObjectCreationHandling = ObjectCreationHandling.Replace, + ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor + }; + + // Serializar objetos + string jsonString = JsonConvert.SerializeObject(objectsToCopy, settings); + + // Copiar al portapapeles + Clipboard.SetText(jsonString); + + // Mostrar mensaje de confirmación + Console.WriteLine($"Copiados {objectsToCopy.Count} objeto(s) al portapapeles"); + + // Restaurar datos no serializables + foreach (var obj in _objectManager.SelectedObjects) + { + obj.RestaurarDatosNoSerializables(); + } + } + catch (Exception ex) + { + MessageBox.Show($"Error al copiar objetos: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + private void PasteObjectsFromJson(bool replaceExistingIds = false) + { + if (!Clipboard.ContainsText()) + return; + + try + { + string jsonString = Clipboard.GetText(); + + // Validación básica del JSON + if (string.IsNullOrWhiteSpace(jsonString) || (!jsonString.TrimStart().StartsWith("[") && !jsonString.TrimStart().StartsWith("{"))) + { + MessageBox.Show("El contenido del portapapeles no parece ser un JSON válido.", "Error", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + // Crear configuración de deserialización + var settings = new JsonSerializerSettings + { + Formatting = Formatting.Indented, + NullValueHandling = NullValueHandling.Ignore, + TypeNameHandling = TypeNameHandling.Auto, + ObjectCreationHandling = ObjectCreationHandling.Replace, + ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor + }; + + List pastedObjects = null; + + // Intentar deserializar como lista de objetos + try + { + pastedObjects = JsonConvert.DeserializeObject>(jsonString, settings); + } + catch + { + // Si falla, intentar como objeto individual + try + { + var singleObject = JsonConvert.DeserializeObject(jsonString, settings); + if (singleObject != null) + { + pastedObjects = new List { singleObject }; + } + } + catch + { + MessageBox.Show("No se pudo deserializar el contenido del portapapeles como objetos válidos.", "Error", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + } + + if (pastedObjects == null || !pastedObjects.Any()) + { + MessageBox.Show("No se encontraron objetos válidos en el portapapeles.", "Error", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + // Obtener posición del mouse en el canvas + var mousePosition = Mouse.GetPosition(ImagenEnTrabajoCanvas); + var mousePositionMeters = ( + PixelToMeter.Instance.calc.PixelsToMeters((float)mousePosition.X), + PixelToMeter.Instance.calc.PixelsToMeters((float)mousePosition.Y) + ); + + // Calcular el centro de los objetos pegados para posicionarlos en el mouse + var centerX = pastedObjects.Average(obj => obj.Left); + var centerY = pastedObjects.Average(obj => obj.Top); + var offsetX = mousePositionMeters.Item1 - centerX; + var offsetY = mousePositionMeters.Item2 - centerY; + + if (DataContext is MainViewModel viewModel) + { + viewModel.StopSimulation(); + viewModel.DisconnectPLC(); + + // Limpiar selección actual + _objectManager.ClearSelection(); + + var newlyPastedObjects = new List(); + + foreach (var obj in pastedObjects) + { + try + { + // Aplicar offset de posición + obj.Left += offsetX; + obj.Top += offsetY; + + // Manejar IDs + if (!replaceExistingIds) + { + // Generar nuevo ID (comportamiento por defecto) + obj.Id.ObtenerNuevaID(); + + // Actualizar nombre si contiene ID + if (obj.Nombre.Contains("_")) + { + var parts = obj.Nombre.Split('_'); + if (parts.Length > 1 && int.TryParse(parts.Last(), out _)) + { + obj.Nombre = string.Join("_", parts.Take(parts.Length - 1)) + "_" + obj.Id.Value; + } + } + } + // Si replaceExistingIds es true, mantener los IDs originales + + // Verificar que el objeto no existe ya si estamos reemplazando IDs + if (replaceExistingIds) + { + var existingObj = viewModel.ObjetosSimulables.FirstOrDefault(o => o.Id.Value == obj.Id.Value); + if (existingObj != null) + { + viewModel.RemoverObjetoSimulable(existingObj); + } + } + + obj.CheckData(); + viewModel.ObjetosSimulables.Add(obj); + viewModel.CrearUserControlDesdeObjetoSimulable(obj); + + newlyPastedObjects.Add(obj); + } + catch (Exception ex) + { + MessageBox.Show($"Error al procesar objeto {obj.Nombre}: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Warning); + } + } + + // Seleccionar los objetos pegados + foreach (var obj in newlyPastedObjects) + { + _objectManager.SelectObject(obj); + } + + _objectManager.UpdateSelectionVisuals(); + viewModel.HasUnsavedChanges = true; + + Console.WriteLine($"Pegados {newlyPastedObjects.Count} objeto(s) desde el portapapeles"); + } + } + catch (Exception ex) + { + MessageBox.Show($"Error al pegar objetos: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + } + } } public class FloatValidationRule : ValidationRule