Implementada la funcionalidad de copiar y pegar objetos seleccionados como JSON desde el portapapeles, incluyendo opciones para reemplazar IDs existentes. Se agregó manejo de errores y validación del contenido del portapapeles para asegurar la correcta deserialización de los objetos.

This commit is contained in:
Miguel 2025-06-13 22:33:13 +02:00
parent 883620b69d
commit 16f5131803
1 changed files with 229 additions and 0 deletions

View File

@ -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<osBase>();
// 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<osBase> pastedObjects = null;
// Intentar deserializar como lista de objetos
try
{
pastedObjects = JsonConvert.DeserializeObject<List<osBase>>(jsonString, settings);
}
catch
{
// Si falla, intentar como objeto individual
try
{
var singleObject = JsonConvert.DeserializeObject<osBase>(jsonString, settings);
if (singleObject != null)
{
pastedObjects = new List<osBase> { 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<osBase>();
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