diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 8015d1e8d..c30a3ea2a 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -708,12 +708,14 @@ Run `git gc` command for this repository. Clear all Clear + Collapse All Configure this repository CONTINUE Custom Actions No Custom Actions Dashboard Discard all changes + Expand All Open in File Browser Search Branches/Tags/Submodules Visibility in Graph diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index 8f9817472..354772b3c 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -703,12 +703,14 @@ Ejecutar comando `git gc` para este repositorio. Limpiar todo Limpiar + Contraer Todo Configurar este repositorio CONTINUAR Acciones Personalizadas No hay ninguna Acción Personalizada Dashboard Descartar todos los cambios + Expandir Todo Abrir en el Explorador Buscar Ramas/Etiquetas/Submódulos Visibilidad en el Gráfico diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index 66e448d6e..d36518148 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -688,12 +688,14 @@ Lancer `git gc` pour ce repository. Tout effacer Nettoyer + Tout Réduire Configurer ce repository CONTINUER Actions personnalisées Pas d'actions personnalisées Tableau de bord Rejeter tous les changements + Tout Développer Ouvrir dans l'explorateur de fichiers Rechercher Branches/Tags/Submodules Visibilité dans le graphique diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml index b5c919220..ed408ce15 100644 --- a/src/Resources/Locales/it_IT.axaml +++ b/src/Resources/Locales/it_IT.axaml @@ -642,12 +642,14 @@ Esegui il comando `git gc` per questo repository. Cancella tutto Cancella + Comprimi Tutto Configura questo repository CONTINUA Azioni Personalizzate Nessuna Azione Personalizzata Dashboard Scarta tutte le modifiche + Espandi Tutto Apri nell'Esplora File Cerca Branch/Tag/Sottomodulo Visibilità nel grafico diff --git a/src/Views/BranchTree.axaml.cs b/src/Views/BranchTree.axaml.cs index 834e0fc6b..8c150ccea 100644 --- a/src/Views/BranchTree.axaml.cs +++ b/src/Views/BranchTree.axaml.cs @@ -387,6 +387,84 @@ public void ToggleNodeIsExpanded(ViewModels.BranchTreeNode node) _disableSelectionChangingEvent = false; } + public void ExpandAll() + { + if (Nodes == null || Nodes.Count == 0) + return; + + _disableSelectionChangingEvent = true; + + // Set IsExpanded = true on all folder nodes recursively + SetExpandedRecursive(Nodes, true); + + // Rebuild rows + var rows = Rows; + rows.Clear(); + var newRows = new List(); + MakeRows(newRows, Nodes, 0); + rows.AddRange(newRows); + + // Persist state for all nodes + var repo = DataContext as ViewModels.Repository; + if (repo != null) + PersistExpandedState(Nodes, repo); + + RaiseEvent(new RoutedEventArgs(RowsChangedEvent)); + _disableSelectionChangingEvent = false; + } + + public void CollapseAll() + { + if (Nodes == null || Nodes.Count == 0) + return; + + _disableSelectionChangingEvent = true; + + // Set IsExpanded = false on all folder nodes recursively + SetExpandedRecursive(Nodes, false); + + // Rebuild rows (only root nodes visible) + var rows = Rows; + rows.Clear(); + var newRows = new List(); + MakeRows(newRows, Nodes, 0); + rows.AddRange(newRows); + + // Persist state for all nodes + var repo = DataContext as ViewModels.Repository; + if (repo != null) + PersistExpandedState(Nodes, repo); + + RaiseEvent(new RoutedEventArgs(RowsChangedEvent)); + _disableSelectionChangingEvent = false; + } + + private void SetExpandedRecursive(List nodes, bool expanded) + { + foreach (var node in nodes) + { + // Only set IsExpanded for folder nodes (not branch leaves) + if (node.Backend is not Models.Branch) + node.IsExpanded = expanded; + + // Recurse into children + if (node.Children != null && node.Children.Count > 0) + SetExpandedRecursive(node.Children, expanded); + } + } + + private void PersistExpandedState(List nodes, ViewModels.Repository repo) + { + foreach (var node in nodes) + { + if (node.Backend is not Models.Branch) + repo.UpdateBranchNodeIsExpanded(node); + + if (node.Children != null && node.Children.Count > 0) + PersistExpandedState(node.Children, repo); + } + } + protected override void OnSizeChanged(SizeChangedEventArgs e) { base.OnSizeChanged(e); diff --git a/src/Views/Repository.axaml b/src/Views/Repository.axaml index 145a1e654..140a64929 100644 --- a/src/Views/Repository.axaml +++ b/src/Views/Repository.axaml @@ -192,36 +192,60 @@ - - - - - - - - - + Margin="6,0,0,0" + Fill="{DynamicResource Brush.FG2}" + Data="{StaticResource Icons.Search}"/> + + + + + + + + + + + + + diff --git a/src/Views/Repository.axaml.cs b/src/Views/Repository.axaml.cs index f99184f5e..1792d5429 100644 --- a/src/Views/Repository.axaml.cs +++ b/src/Views/Repository.axaml.cs @@ -598,5 +598,41 @@ private async void OnBisectCommand(object sender, RoutedEventArgs e) e.Handled = true; } + + private void OnExpandAllNodes(object sender, RoutedEventArgs e) + { + if (DataContext is ViewModels.Repository repo) + { + repo.IsLocalBranchGroupExpanded = true; + repo.IsRemoteGroupExpanded = true; + repo.IsTagGroupExpanded = true; + repo.IsSubmoduleGroupExpanded = true; + repo.IsWorktreeGroupExpanded = true; + } + + LocalBranchTree?.ExpandAll(); + RemoteBranchTree?.ExpandAll(); + TagsList?.ExpandAll(); + SubmoduleList?.ExpandAll(); + e.Handled = true; + } + + private void OnCollapseAllNodes(object sender, RoutedEventArgs e) + { + if (DataContext is ViewModels.Repository repo) + { + repo.IsLocalBranchGroupExpanded = false; + repo.IsRemoteGroupExpanded = false; + repo.IsTagGroupExpanded = false; + repo.IsSubmoduleGroupExpanded = false; + repo.IsWorktreeGroupExpanded = false; + } + + LocalBranchTree?.CollapseAll(); + RemoteBranchTree?.CollapseAll(); + TagsList?.CollapseAll(); + SubmoduleList?.CollapseAll(); + e.Handled = true; + } } } diff --git a/src/Views/SubmodulesView.axaml.cs b/src/Views/SubmodulesView.axaml.cs index 6e4b7b7f9..457c90dd3 100644 --- a/src/Views/SubmodulesView.axaml.cs +++ b/src/Views/SubmodulesView.axaml.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Avalonia; using Avalonia.Controls; @@ -118,6 +119,61 @@ public void ToggleNodeIsExpanded(ViewModels.SubmoduleTreeNode node) } } + public void ExpandAll() + { + if (Content is ViewModels.SubmoduleCollectionAsTree tree) + { + SetExpandedRecursive(tree.Tree, true); + + // Rebuild rows manually + tree.Rows.Clear(); + MakeTreeRows(tree.Rows, tree.Tree); + + Rows = tree.Rows.Count; + RaiseEvent(new RoutedEventArgs(RowsChangedEvent)); + } + } + + public void CollapseAll() + { + if (Content is ViewModels.SubmoduleCollectionAsTree tree) + { + SetExpandedRecursive(tree.Tree, false); + + // Rebuild rows manually + tree.Rows.Clear(); + MakeTreeRows(tree.Rows, tree.Tree); + + Rows = tree.Rows.Count; + RaiseEvent(new RoutedEventArgs(RowsChangedEvent)); + } + } + + private void MakeTreeRows(Avalonia.Collections.AvaloniaList rows, List nodes) + { + foreach (var node in nodes) + { + rows.Add(node); + + if (!node.IsExpanded || !node.IsFolder) + continue; + + MakeTreeRows(rows, node.Children); + } + } + + private void SetExpandedRecursive(List nodes, bool expanded) + { + foreach (var node in nodes) + { + if (node.IsFolder) + node.IsExpanded = expanded; + + if (node.Children != null && node.Children.Count > 0) + SetExpandedRecursive(node.Children, expanded); + } + } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); diff --git a/src/Views/TagsView.axaml.cs b/src/Views/TagsView.axaml.cs index 8ff788a08..8557b24eb 100644 --- a/src/Views/TagsView.axaml.cs +++ b/src/Views/TagsView.axaml.cs @@ -144,6 +144,61 @@ public void ToggleNodeIsExpanded(ViewModels.TagTreeNode node) } } + public void ExpandAll() + { + if (Content is ViewModels.TagCollectionAsTree tree) + { + SetExpandedRecursive(tree.Tree, true); + + // Rebuild rows manually + tree.Rows.Clear(); + MakeTreeRows(tree.Rows, tree.Tree); + + Rows = tree.Rows.Count; + RaiseEvent(new RoutedEventArgs(RowsChangedEvent)); + } + } + + public void CollapseAll() + { + if (Content is ViewModels.TagCollectionAsTree tree) + { + SetExpandedRecursive(tree.Tree, false); + + // Rebuild rows manually + tree.Rows.Clear(); + MakeTreeRows(tree.Rows, tree.Tree); + + Rows = tree.Rows.Count; + RaiseEvent(new RoutedEventArgs(RowsChangedEvent)); + } + } + + private void MakeTreeRows(Avalonia.Collections.AvaloniaList rows, List nodes) + { + foreach (var node in nodes) + { + rows.Add(node); + + if (!node.IsExpanded || !node.IsFolder) + continue; + + MakeTreeRows(rows, node.Children); + } + } + + private void SetExpandedRecursive(List nodes, bool expanded) + { + foreach (var node in nodes) + { + if (node.IsFolder) + node.IsExpanded = expanded; + + if (node.Children != null && node.Children.Count > 0) + SetExpandedRecursive(node.Children, expanded); + } + } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change);