Se añadió la clase LibraryWindowSettings para gestionar la configuración de la ventana de la biblioteca, incluyendo propiedades para dimensiones y posición. Se implementó la persistencia de estas configuraciones al abrir y cerrar la ventana. Además, se mejoró la interfaz de usuario con un TreeView jerárquico para la gestión de bibliotecas y se añadieron comandos para crear y eliminar directorios de bibliotecas. Se implementó la selección múltiple de objetos en la ventana de la biblioteca, mejorando la experiencia del usuario al gestionar objetos.
This commit is contained in:
parent
c353f6c6ea
commit
c03f6970d8
|
@ -5,9 +5,47 @@
|
|||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
xmlns:local="clr-namespace:CtrEditor.PopUps"
|
||||
xmlns:ObjetosSim="clr-namespace:CtrEditor.ObjetosSim"
|
||||
Title="Biblioteca de Objetos Simulables" Height="700" Width="1200"
|
||||
WindowStartupLocation="CenterOwner" ResizeMode="CanResize"
|
||||
Loaded="Window_Loaded">
|
||||
xmlns:ctr="clr-namespace:CtrEditor"
|
||||
Title="Biblioteca de Objetos Simulables"
|
||||
Height="{Binding Source={x:Static ctr:EstadoPersistente.Instance}, Path=LibraryWindow.Height, Mode=TwoWay}"
|
||||
Width="{Binding Source={x:Static ctr:EstadoPersistente.Instance}, Path=LibraryWindow.Width, Mode=TwoWay}"
|
||||
Left="{Binding Source={x:Static ctr:EstadoPersistente.Instance}, Path=LibraryWindow.Left, Mode=TwoWay}"
|
||||
Top="{Binding Source={x:Static ctr:EstadoPersistente.Instance}, Path=LibraryWindow.Top, Mode=TwoWay}"
|
||||
WindowStartupLocation="Manual" ResizeMode="CanResize"
|
||||
Loaded="Window_Loaded" Closing="Window_Closing">
|
||||
|
||||
<Window.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVisConverter"/>
|
||||
|
||||
<!-- Estilo para nombres largos con wrapping -->
|
||||
<Style x:Key="WrappingTextBlockStyle" TargetType="TextBlock">
|
||||
<Setter Property="TextWrapping" Value="Wrap"/>
|
||||
<Setter Property="MaxWidth" Value="200"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<!-- Estilo para nombres largos con formato especial -->
|
||||
<Style x:Key="WrappingProjectTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource WrappingTextBlockStyle}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsCurrentProject}" Value="True">
|
||||
<Setter Property="FontWeight" Value="Bold" />
|
||||
<Setter Property="Foreground" Value="Blue" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- Menú contextual para directorios -->
|
||||
<ContextMenu x:Key="DirectoryContextMenu">
|
||||
<MenuItem Header="Nueva Biblioteca" Command="{Binding CreateLibraryInDirectoryCommand}"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Eliminar Directorio" Command="{Binding RemoveDirectoryCommand}"/>
|
||||
</ContextMenu>
|
||||
|
||||
<!-- Estilo para TreeViewItem de directorios -->
|
||||
<Style x:Key="DirectoryTreeViewItemStyle" TargetType="TreeViewItem">
|
||||
<Setter Property="ContextMenu" Value="{StaticResource DirectoryContextMenu}"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Window.InputBindings>
|
||||
<KeyBinding Key="C" Modifiers="Ctrl" Command="{Binding CopyObjectCommand}" />
|
||||
|
@ -17,16 +55,16 @@
|
|||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="250" MinWidth="200" />
|
||||
<ColumnDefinition Width="{Binding Source={x:Static ctr:EstadoPersistente.Instance}, Path=LibraryWindow.Column0Width, Mode=TwoWay}" MinWidth="200" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="300" MinWidth="250" />
|
||||
<ColumnDefinition Width="{Binding Source={x:Static ctr:EstadoPersistente.Instance}, Path=LibraryWindow.Column2Width, Mode=TwoWay}" MinWidth="250" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="350" MinWidth="250" />
|
||||
<ColumnDefinition Width="{Binding Source={x:Static ctr:EstadoPersistente.Instance}, Path=LibraryWindow.Column4Width, Mode=TwoWay}" MinWidth="250" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="*" MinWidth="300" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Primera columna: Gestión de directorios de biblioteca -->
|
||||
<!-- Primera columna: TreeView jerárquico de directorios y bibliotecas -->
|
||||
<Grid Grid.Column="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
|
@ -34,16 +72,45 @@
|
|||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Content="Directorios de Biblioteca" FontWeight="Bold" />
|
||||
<Label Grid.Row="0" Content="Bibliotecas" FontWeight="Bold" />
|
||||
|
||||
<ListBox Grid.Row="1" Name="LibraryDirectoriesList"
|
||||
ItemsSource="{Binding LibraryDirectories}"
|
||||
SelectedItem="{Binding SelectedLibraryDirectory, Mode=TwoWay}"
|
||||
DisplayMemberPath="DisplayName" />
|
||||
<TreeView Grid.Row="1" Name="LibraryTreeView"
|
||||
ItemsSource="{Binding LibraryTreeNodes}"
|
||||
SelectedItemChanged="LibraryTreeView_SelectedItemChanged">
|
||||
<TreeView.ItemContainerStyleSelector>
|
||||
<local:LibraryTreeItemStyleSelector DirectoryStyle="{StaticResource DirectoryTreeViewItemStyle}"/>
|
||||
</TreeView.ItemContainerStyleSelector>
|
||||
|
||||
<TreeView.Resources>
|
||||
<!-- Template for directory and library nodes -->
|
||||
<HierarchicalDataTemplate DataType="{x:Type local:LibraryTreeNode}">
|
||||
<HierarchicalDataTemplate.ItemsSource>
|
||||
<Binding Path="Children"/>
|
||||
</HierarchicalDataTemplate.ItemsSource>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="2">
|
||||
<TextBlock Text="📁" Margin="0,0,5,0" VerticalAlignment="Center"
|
||||
Visibility="{Binding IsDirectory, Converter={StaticResource BoolToVisConverter}}"/>
|
||||
<TextBlock Text="📄" Margin="0,0,5,0" VerticalAlignment="Center">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsDirectory}" Value="False">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<TextBlock Text="{Binding DisplayName}" Style="{StaticResource WrappingProjectTextBlockStyle}"/>
|
||||
</StackPanel>
|
||||
</HierarchicalDataTemplate>
|
||||
</TreeView.Resources>
|
||||
</TreeView>
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
|
||||
<Button Content="Agregar" Command="{Binding AddLibraryDirectoryCommand}" Margin="2" Padding="5,2" />
|
||||
<Button Content="Eliminar" Command="{Binding RemoveLibraryDirectoryCommand}" Margin="2" Padding="5,2" />
|
||||
<Button Content="Agregar Directorio" Command="{Binding AddLibraryDirectoryCommand}" Margin="2" Padding="5,2" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
|
@ -51,35 +118,25 @@
|
|||
<GridSplitter Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Stretch"
|
||||
Background="LightGray" Width="5" />
|
||||
|
||||
<!-- Segunda columna: Bibliotecas -->
|
||||
<!-- Segunda columna: Filtros -->
|
||||
<Grid Grid.Column="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Content="Bibliotecas" FontWeight="Bold" />
|
||||
<TreeView Grid.Row="1" Name="LibrariesTreeView"
|
||||
ItemsSource="{Binding Libraries}"
|
||||
SelectedItemChanged="LibrariesTreeView_SelectedItemChanged">
|
||||
<TreeView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding DisplayName}" />
|
||||
</DataTemplate>
|
||||
</TreeView.ItemTemplate>
|
||||
</TreeView>
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
|
||||
<Button Content="Nueva Biblioteca" Command="{Binding CreateNewLibraryCommand}" Margin="2" Padding="5,2" />
|
||||
</StackPanel>
|
||||
<Label Grid.Row="0" Content="Filtros" FontWeight="Bold" />
|
||||
|
||||
<Expander Grid.Row="1" Header="Configuración de Filtros" IsExpanded="True">
|
||||
<controls:osVisFilter x:Name="ObjectFilter" Margin="5"/>
|
||||
</Expander>
|
||||
</Grid>
|
||||
|
||||
<!-- GridSplitter 2 -->
|
||||
<GridSplitter Grid.Column="3" HorizontalAlignment="Center" VerticalAlignment="Stretch"
|
||||
Background="LightGray" Width="5" />
|
||||
|
||||
<!-- Tercera columna: Objetos -->
|
||||
<!-- Tercera columna: Objetos con selección múltiple -->
|
||||
<Grid Grid.Column="4">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
|
@ -88,44 +145,44 @@
|
|||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Filtros -->
|
||||
<Expander Grid.Row="0" Header="Filtros" IsExpanded="True">
|
||||
<controls:osVisFilter x:Name="ObjectFilter" Margin="5"/>
|
||||
</Expander>
|
||||
<Label Grid.Row="0" Content="Objetos" FontWeight="Bold" />
|
||||
|
||||
<Label Grid.Row="1" Content="Objetos" FontWeight="Bold" />
|
||||
<TreeView Grid.Row="2" Name="ObjectsTreeView"
|
||||
ItemsSource="{Binding FilteredObjectsByType}"
|
||||
SelectedItemChanged="ObjectsTreeView_SelectedItemChanged">
|
||||
<TreeView.Resources>
|
||||
<!-- Template for object type groups -->
|
||||
<HierarchicalDataTemplate DataType="{x:Type local:ObjectTypeGroup}"
|
||||
ItemsSource="{Binding Objects}">
|
||||
<TextBlock Text="{Binding TypeName}" FontWeight="Bold" />
|
||||
</HierarchicalDataTemplate>
|
||||
|
||||
<!-- Template for individual objects -->
|
||||
<DataTemplate DataType="{x:Type ObjetosSim:osBase}">
|
||||
<TextBlock Text="{Binding Nombre}">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Enable_On_All_Pages}" Value="True">
|
||||
<Setter Property="Foreground" Value="Blue" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Cloned}" Value="True">
|
||||
<Setter Property="Foreground" Value="Orange" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding AutoCreated}" Value="True">
|
||||
<Setter Property="Foreground" Value="Green" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<!-- Controles de selección múltiple -->
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="5">
|
||||
<Button Content="Seleccionar Todo" Click="SelectAllObjects_Click" Margin="2" Padding="5,2"/>
|
||||
<Button Content="Deseleccionar Todo" Click="UnselectAllObjects_Click" Margin="2" Padding="5,2"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Listbox para objetos con checkboxes -->
|
||||
<ListBox Grid.Row="2" Name="SelectableObjectsList"
|
||||
ItemsSource="{Binding SelectableObjects}"
|
||||
SelectionMode="Extended">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}"
|
||||
Margin="0,0,5,0" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding Object.Nombre}" VerticalAlignment="Center">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Object.Enable_On_All_Pages}" Value="True">
|
||||
<Setter Property="Foreground" Value="Blue" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Object.Cloned}" Value="True">
|
||||
<Setter Property="Foreground" Value="Orange" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Object.AutoCreated}" Value="True">
|
||||
<Setter Property="Foreground" Value="Green" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</TreeView.Resources>
|
||||
</TreeView>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<!-- Botones de acción -->
|
||||
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CtrEditor.ObjetosSim;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace CtrEditor.PopUps
|
||||
{
|
||||
|
@ -12,13 +15,57 @@ namespace CtrEditor.PopUps
|
|||
public LibraryWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Aplicar configuraciones persistentes
|
||||
ApplyPersistedSettings();
|
||||
|
||||
// Suscribirse al evento StateChanged para persistir cambios de estado
|
||||
StateChanged += LibraryWindow_StateChanged;
|
||||
}
|
||||
|
||||
private void LibrariesTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||
private void LibraryWindow_StateChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Guardar el estado cuando cambia
|
||||
EstadoPersistente.Instance.LibraryWindow.IsMaximized = WindowState == WindowState.Maximized;
|
||||
EstadoPersistente.Instance.GuardarEstado();
|
||||
}
|
||||
|
||||
private void ApplyPersistedSettings()
|
||||
{
|
||||
var settings = EstadoPersistente.Instance.LibraryWindow;
|
||||
|
||||
// Asegurar que la ventana esté dentro de los límites de la pantalla
|
||||
var screenWidth = SystemParameters.WorkArea.Width;
|
||||
var screenHeight = SystemParameters.WorkArea.Height;
|
||||
|
||||
if (settings.Left < 0 || settings.Left > screenWidth - 100)
|
||||
settings.Left = 100;
|
||||
if (settings.Top < 0 || settings.Top > screenHeight - 100)
|
||||
settings.Top = 100;
|
||||
|
||||
if (settings.Width < 800 || settings.Width > screenWidth)
|
||||
settings.Width = 1200;
|
||||
if (settings.Height < 600 || settings.Height > screenHeight)
|
||||
settings.Height = 700;
|
||||
|
||||
// Aplicar el estado de la ventana
|
||||
WindowState = settings.IsMaximized ? WindowState.Maximized : WindowState.Normal;
|
||||
}
|
||||
|
||||
private void LibraryTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||
{
|
||||
if (DataContext is LibraryWindowViewModel viewModel)
|
||||
{
|
||||
viewModel.SelectedLibrary = e.NewValue as LibraryItem;
|
||||
if (e.NewValue is LibraryTreeNode selectedNode)
|
||||
{
|
||||
viewModel.SelectedTreeNode = selectedNode;
|
||||
|
||||
// Si es una biblioteca (no directorio), establecer como biblioteca seleccionada
|
||||
if (!selectedNode.IsDirectory && selectedNode.Library != null)
|
||||
{
|
||||
viewModel.SelectedLibrary = selectedNode.Library;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,6 +90,28 @@ namespace CtrEditor.PopUps
|
|||
}
|
||||
}
|
||||
|
||||
private void SelectAllObjects_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is LibraryWindowViewModel viewModel)
|
||||
{
|
||||
foreach (var item in viewModel.SelectableObjects)
|
||||
{
|
||||
item.IsSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UnselectAllObjects_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is LibraryWindowViewModel viewModel)
|
||||
{
|
||||
foreach (var item in viewModel.SelectableObjects)
|
||||
{
|
||||
item.IsSelected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
|
@ -57,5 +126,30 @@ namespace CtrEditor.PopUps
|
|||
viewModel.SetObjectFilter(ObjectFilter);
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
// Guardar configuraciones de la ventana antes de cerrar
|
||||
SaveWindowSettings();
|
||||
}
|
||||
|
||||
private void SaveWindowSettings()
|
||||
{
|
||||
var settings = EstadoPersistente.Instance.LibraryWindow;
|
||||
|
||||
if (WindowState == WindowState.Normal)
|
||||
{
|
||||
settings.Width = ActualWidth;
|
||||
settings.Height = ActualHeight;
|
||||
settings.Left = Left;
|
||||
settings.Top = Top;
|
||||
}
|
||||
|
||||
settings.IsMaximized = WindowState == WindowState.Maximized;
|
||||
|
||||
EstadoPersistente.Instance.GuardarEstado();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace CtrEditor.PopUps
|
||||
{
|
||||
|
||||
|
||||
// StyleSelector para TreeViewItems
|
||||
public class LibraryTreeItemStyleSelector : StyleSelector
|
||||
{
|
||||
public Style DirectoryStyle { get; set; }
|
||||
|
||||
public override Style SelectStyle(object item, DependencyObject container)
|
||||
{
|
||||
if (item is LibraryTreeNode node && node.IsDirectory)
|
||||
{
|
||||
return DirectoryStyle;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Clase para nodos del TreeView jerárquico
|
||||
public class LibraryTreeNode : ObservableObject
|
||||
{
|
||||
public string DisplayName { get; set; }
|
||||
public bool IsDirectory { get; set; }
|
||||
public bool IsCurrentProject { get; set; }
|
||||
public string DirectoryPath { get; set; }
|
||||
public LibraryItem Library { get; set; }
|
||||
public ObservableCollection<LibraryTreeNode> Children { get; set; } = new ObservableCollection<LibraryTreeNode>();
|
||||
}
|
||||
|
||||
// Wrapper para objetos seleccionables
|
||||
public class SelectableObjectWrapper : ObservableObject
|
||||
{
|
||||
public CtrEditor.ObjetosSim.osBase Object { get; set; }
|
||||
|
||||
private bool _isSelected;
|
||||
public bool IsSelected
|
||||
{
|
||||
get => _isSelected;
|
||||
set => SetProperty(ref _isSelected, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,6 +38,17 @@ namespace CtrEditor.PopUps
|
|||
[ObservableProperty]
|
||||
private osBase selectedObject;
|
||||
|
||||
// Nueva propiedad para el TreeView jerárquico
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<LibraryTreeNode> libraryTreeNodes;
|
||||
|
||||
[ObservableProperty]
|
||||
private LibraryTreeNode selectedTreeNode;
|
||||
|
||||
// Nueva propiedad para objetos seleccionados múltiples
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<SelectableObjectWrapper> selectableObjects;
|
||||
|
||||
// Commands
|
||||
public ICommand AddLibraryDirectoryCommand { get; }
|
||||
public ICommand RemoveLibraryDirectoryCommand { get; }
|
||||
|
@ -46,6 +57,10 @@ namespace CtrEditor.PopUps
|
|||
public ICommand DeleteObjectCommand { get; }
|
||||
public ICommand CreateNewLibraryCommand { get; }
|
||||
|
||||
// Nuevos comandos para menú contextual
|
||||
public ICommand CreateLibraryInDirectoryCommand { get; }
|
||||
public ICommand RemoveDirectoryCommand { get; }
|
||||
|
||||
public LibraryWindowViewModel(MainViewModel mainViewModel)
|
||||
{
|
||||
_mainViewModel = mainViewModel;
|
||||
|
@ -53,17 +68,57 @@ namespace CtrEditor.PopUps
|
|||
LibraryDirectories = new ObservableCollection<LibraryDirectoryItem>();
|
||||
Libraries = new ObservableCollection<LibraryItem>();
|
||||
FilteredObjectsByType = new ObservableCollection<ObjectTypeGroup>();
|
||||
LibraryTreeNodes = new ObservableCollection<LibraryTreeNode>();
|
||||
SelectableObjects = new ObservableCollection<SelectableObjectWrapper>();
|
||||
|
||||
// Initialize commands
|
||||
AddLibraryDirectoryCommand = new RelayCommand(AddLibraryDirectory);
|
||||
RemoveLibraryDirectoryCommand = new RelayCommand(RemoveLibraryDirectory, () => SelectedLibraryDirectory != null);
|
||||
CopyObjectCommand = new RelayCommand(CopyObject, () => SelectedObject != null);
|
||||
CopyObjectCommand = new RelayCommand(CopyObject, () => HasSelectedObjects());
|
||||
PasteObjectCommand = new RelayCommand(PasteObject, () => SelectedLibrary != null && _clipboardObjects.Any());
|
||||
DeleteObjectCommand = new RelayCommand(DeleteObject, () => SelectedObject != null && SelectedLibrary != null && !SelectedLibrary.IsCurrentProject);
|
||||
DeleteObjectCommand = new RelayCommand(DeleteObject, () => HasSelectedObjects() && SelectedLibrary != null && !SelectedLibrary.IsCurrentProject);
|
||||
CreateNewLibraryCommand = new RelayCommand(CreateNewLibrary, () => SelectedLibraryDirectory != null);
|
||||
|
||||
// Nuevos comandos
|
||||
CreateLibraryInDirectoryCommand = new RelayCommand(CreateLibraryInDirectory, () => SelectedTreeNode?.IsDirectory == true);
|
||||
RemoveDirectoryCommand = new RelayCommand(RemoveDirectory, () => SelectedTreeNode?.IsDirectory == true && !SelectedTreeNode.IsCurrentProject);
|
||||
|
||||
LoadLibraryDirectories();
|
||||
RefreshLibraries();
|
||||
RefreshLibraryTree();
|
||||
}
|
||||
|
||||
private bool HasSelectedObjects()
|
||||
{
|
||||
return SelectableObjects?.Any(o => o.IsSelected) == true || SelectedObject != null;
|
||||
}
|
||||
|
||||
private List<osBase> GetSelectedObjects()
|
||||
{
|
||||
var selected = new List<osBase>();
|
||||
|
||||
// Primero agregar objetos seleccionados por checkbox
|
||||
if (SelectableObjects != null)
|
||||
{
|
||||
selected.AddRange(SelectableObjects.Where(o => o.IsSelected).Select(o => o.Object));
|
||||
}
|
||||
|
||||
// Si no hay objetos con checkbox seleccionados, usar la selección simple
|
||||
if (!selected.Any() && SelectedObject != null)
|
||||
{
|
||||
selected.Add(SelectedObject);
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
partial void OnSelectedTreeNodeChanged(LibraryTreeNode value)
|
||||
{
|
||||
if (value?.IsDirectory == false) // Es una biblioteca
|
||||
{
|
||||
SelectedLibrary = value.Library;
|
||||
LoadObjectsFromLibrary();
|
||||
}
|
||||
CommandManager.InvalidateRequerySuggested();
|
||||
}
|
||||
|
||||
partial void OnSelectedLibraryDirectoryChanged(LibraryDirectoryItem value)
|
||||
|
@ -96,7 +151,7 @@ namespace CtrEditor.PopUps
|
|||
LibraryDirectories.Add(new LibraryDirectoryItem
|
||||
{
|
||||
Path = _mainViewModel.directorioTrabajo,
|
||||
DisplayName = "Proyecto Actual",
|
||||
DisplayName = $"Proyecto Actual ({_mainViewModel.directorioTrabajo})",
|
||||
IsCurrentProject = true
|
||||
});
|
||||
|
||||
|
@ -108,7 +163,7 @@ namespace CtrEditor.PopUps
|
|||
LibraryDirectories.Add(new LibraryDirectoryItem
|
||||
{
|
||||
Path = directory,
|
||||
DisplayName = Path.GetFileName(directory),
|
||||
DisplayName = directory, // Show full path instead of just folder name
|
||||
IsCurrentProject = false
|
||||
});
|
||||
}
|
||||
|
@ -191,11 +246,27 @@ namespace CtrEditor.PopUps
|
|||
};
|
||||
|
||||
string json = File.ReadAllText(filePath);
|
||||
var simulationData = JsonConvert.DeserializeObject<SimulationData>(json, settings);
|
||||
|
||||
if (simulationData?.ObjetosSimulables != null)
|
||||
// Try to detect format: check if it starts with '[' (AllPages.json format) or '{' (normal format)
|
||||
json = json.Trim();
|
||||
|
||||
if (json.StartsWith("["))
|
||||
{
|
||||
objects.AddRange(simulationData.ObjetosSimulables);
|
||||
// AllPages.json format: direct array of objects
|
||||
var directObjects = JsonConvert.DeserializeObject<List<osBase>>(json, settings);
|
||||
if (directObjects != null)
|
||||
{
|
||||
objects.AddRange(directObjects);
|
||||
}
|
||||
}
|
||||
else if (json.StartsWith("{"))
|
||||
{
|
||||
// Normal format: SimulationData wrapper
|
||||
var simulationData = JsonConvert.DeserializeObject<SimulationData>(json, settings);
|
||||
if (simulationData?.ObjetosSimulables != null)
|
||||
{
|
||||
objects.AddRange(simulationData.ObjetosSimulables);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -209,9 +280,16 @@ namespace CtrEditor.PopUps
|
|||
private void LoadObjectsFromLibrary()
|
||||
{
|
||||
FilteredObjectsByType.Clear();
|
||||
SelectableObjects.Clear();
|
||||
|
||||
if (SelectedLibrary == null) return;
|
||||
|
||||
// Crear objetos seleccionables con checkboxes
|
||||
foreach (var obj in SelectedLibrary.Objects)
|
||||
{
|
||||
SelectableObjects.Add(new SelectableObjectWrapper { Object = obj, IsSelected = false });
|
||||
}
|
||||
|
||||
// Update filter types and tags when library changes
|
||||
if (_objectFilter != null)
|
||||
{
|
||||
|
@ -374,15 +452,13 @@ namespace CtrEditor.PopUps
|
|||
|
||||
private void CopyObject()
|
||||
{
|
||||
if (SelectedObject != null)
|
||||
var objectsToCopy = GetSelectedObjects();
|
||||
if (objectsToCopy.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
_clipboardObjects.Clear();
|
||||
|
||||
// Prepare object for serialization
|
||||
SelectedObject.SalvarDatosNoSerializables();
|
||||
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
Formatting = Formatting.Indented,
|
||||
|
@ -390,23 +466,30 @@ namespace CtrEditor.PopUps
|
|||
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)
|
||||
foreach (var obj in objectsToCopy)
|
||||
{
|
||||
_clipboardObjects.Add(copiedObject);
|
||||
MessageBox.Show("Objeto copiado al portapapeles.", "Información", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
// Prepare object for serialization
|
||||
obj.SalvarDatosNoSerializables();
|
||||
|
||||
// Serialize and deserialize to create a deep copy
|
||||
var serializedData = JsonConvert.SerializeObject(obj, settings);
|
||||
var copiedObject = JsonConvert.DeserializeObject<osBase>(serializedData, settings);
|
||||
|
||||
if (copiedObject != null)
|
||||
{
|
||||
_clipboardObjects.Add(copiedObject);
|
||||
}
|
||||
|
||||
// Restore object state
|
||||
obj.RestaurarDatosNoSerializables();
|
||||
}
|
||||
|
||||
// Restore object state
|
||||
SelectedObject.RestaurarDatosNoSerializables();
|
||||
MessageBox.Show($"{_clipboardObjects.Count} objeto(s) copiado(s) al portapapeles.", "Información", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
CommandManager.InvalidateRequerySuggested();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Error al copiar objeto: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
MessageBox.Show($"Error al copiar objeto(s): {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -456,27 +539,37 @@ namespace CtrEditor.PopUps
|
|||
|
||||
private void DeleteObject()
|
||||
{
|
||||
if (SelectedObject != null && SelectedLibrary != null && !SelectedLibrary.IsCurrentProject)
|
||||
var objectsToDelete = GetSelectedObjects();
|
||||
if (objectsToDelete.Any() && 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);
|
||||
var message = objectsToDelete.Count == 1
|
||||
? $"¿Está seguro de que desea eliminar el objeto '{objectsToDelete.First().Nombre}'?"
|
||||
: $"¿Está seguro de que desea eliminar {objectsToDelete.Count} objetos?";
|
||||
|
||||
var result = MessageBox.Show(message, "Confirmar eliminación", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
SelectedLibrary.Objects.Remove(SelectedObject);
|
||||
foreach (var obj in objectsToDelete)
|
||||
{
|
||||
SelectedLibrary.Objects.Remove(obj);
|
||||
}
|
||||
|
||||
SaveLibraryToFile(SelectedLibrary);
|
||||
LoadObjectsFromLibrary();
|
||||
SelectedObject = null;
|
||||
MessageBox.Show("Objeto eliminado.", "Información", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
|
||||
var successMessage = objectsToDelete.Count == 1
|
||||
? "Objeto eliminado."
|
||||
: $"{objectsToDelete.Count} objetos eliminados.";
|
||||
|
||||
MessageBox.Show(successMessage, "Información", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Error al eliminar objeto: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
MessageBox.Show($"Error al eliminar objeto(s): {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -553,8 +646,108 @@ namespace CtrEditor.PopUps
|
|||
MessageBox.Show($"Error al guardar biblioteca: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshLibraryTree()
|
||||
{
|
||||
LibraryTreeNodes.Clear();
|
||||
|
||||
foreach (var directory in LibraryDirectories)
|
||||
{
|
||||
var directoryNode = new LibraryTreeNode
|
||||
{
|
||||
DisplayName = directory.DisplayName,
|
||||
IsDirectory = true,
|
||||
IsCurrentProject = directory.IsCurrentProject,
|
||||
DirectoryPath = directory.Path,
|
||||
Children = new ObservableCollection<LibraryTreeNode>()
|
||||
};
|
||||
|
||||
// Agregar bibliotecas como hijos del directorio
|
||||
if (directory.IsCurrentProject)
|
||||
{
|
||||
// Agregar proyecto actual
|
||||
directoryNode.Children.Add(new LibraryTreeNode
|
||||
{
|
||||
DisplayName = "Proyecto Actual",
|
||||
IsDirectory = false,
|
||||
Library = new LibraryItem
|
||||
{
|
||||
Name = "Proyecto Actual",
|
||||
IsCurrentProject = true,
|
||||
Objects = _mainViewModel.ObjetosSimulables.ToList()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Agregar archivos JSON
|
||||
if (Directory.Exists(directory.Path))
|
||||
{
|
||||
var jsonFiles = Directory.GetFiles(directory.Path, "*.json", SearchOption.AllDirectories);
|
||||
foreach (var jsonFile in jsonFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
var displayName = Path.GetFileNameWithoutExtension(jsonFile);
|
||||
directoryNode.Children.Add(new LibraryTreeNode
|
||||
{
|
||||
DisplayName = displayName,
|
||||
IsDirectory = false,
|
||||
Library = new LibraryItem
|
||||
{
|
||||
Name = displayName,
|
||||
FilePath = jsonFile,
|
||||
IsCurrentProject = false,
|
||||
Objects = LoadObjectsFromJsonFile(jsonFile)
|
||||
}
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignorar archivos que no se pueden cargar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LibraryTreeNodes.Add(directoryNode);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateLibraryInDirectory()
|
||||
{
|
||||
if (SelectedTreeNode?.IsDirectory != true) return;
|
||||
|
||||
var oldSelectedDirectory = SelectedLibraryDirectory;
|
||||
|
||||
// Temporalmente cambiar el directorio seleccionado
|
||||
SelectedLibraryDirectory = LibraryDirectories.FirstOrDefault(d => d.Path == SelectedTreeNode.DirectoryPath);
|
||||
CreateNewLibrary();
|
||||
RefreshLibraryTree();
|
||||
|
||||
// Restaurar el directorio seleccionado
|
||||
SelectedLibraryDirectory = oldSelectedDirectory;
|
||||
}
|
||||
|
||||
private void RemoveDirectory()
|
||||
{
|
||||
if (SelectedTreeNode?.IsDirectory != true || SelectedTreeNode.IsCurrentProject) return;
|
||||
|
||||
var result = MessageBox.Show($"¿Eliminar el directorio '{SelectedTreeNode.DisplayName}' de la lista de bibliotecas?",
|
||||
"Confirmar eliminación", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
EstadoPersistente.Instance.LibraryDirectories.Remove(SelectedTreeNode.DirectoryPath);
|
||||
EstadoPersistente.Instance.GuardarEstado();
|
||||
LoadLibraryDirectories();
|
||||
RefreshLibraryTree();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Support classes
|
||||
public class LibraryDirectoryItem
|
||||
{
|
||||
|
|
|
@ -22,6 +22,18 @@ namespace CtrEditor
|
|||
public string TargetColumn { get; set; }
|
||||
}
|
||||
|
||||
public class LibraryWindowSettings
|
||||
{
|
||||
public double Width { get; set; } = 1200;
|
||||
public double Height { get; set; } = 700;
|
||||
public double Left { get; set; } = 100;
|
||||
public double Top { get; set; } = 100;
|
||||
public double Column0Width { get; set; } = 300;
|
||||
public double Column2Width { get; set; } = 350;
|
||||
public double Column4Width { get; set; } = 350;
|
||||
public bool IsMaximized { get; set; } = false;
|
||||
}
|
||||
|
||||
internal class EstadoPersistente
|
||||
{
|
||||
// Ruta donde se guardará el estado
|
||||
|
@ -44,6 +56,8 @@ namespace CtrEditor
|
|||
|
||||
public List<string> LibraryDirectories { get; set; } = new List<string>();
|
||||
|
||||
public LibraryWindowSettings LibraryWindow { get; set; } = new LibraryWindowSettings();
|
||||
|
||||
// Propiedad pública con get y set para controlar el acceso a _strDirectorioTrabajo
|
||||
public string directorio
|
||||
{
|
||||
|
@ -76,6 +90,7 @@ namespace CtrEditor
|
|||
{
|
||||
_strDirectorioTrabajo = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
RecentDirectories = new List<string>();
|
||||
LibraryWindow = new LibraryWindowSettings();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -114,7 +129,11 @@ namespace CtrEditor
|
|||
if (File.Exists(_filePath))
|
||||
{
|
||||
string json = File.ReadAllText(_filePath);
|
||||
return JsonSerializer.Deserialize<EstadoPersistente>(json);
|
||||
var estado = JsonSerializer.Deserialize<EstadoPersistente>(json);
|
||||
// Asegurar que LibraryWindow esté inicializado
|
||||
if (estado.LibraryWindow == null)
|
||||
estado.LibraryWindow = new LibraryWindowSettings();
|
||||
return estado;
|
||||
}
|
||||
return new EstadoPersistente().Inizializar(); // Devuelve una nueva instancia si no existe el archivo
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue