| 1 | using System.Collections.ObjectModel; |
| 2 | using System.ComponentModel; |
| 3 | using System.Runtime.CompilerServices; |
| 4 | |
| 5 | namespace CascadeIDE.Models; |
| 6 | |
| 7 | public sealed class SolutionItem : INotifyPropertyChanged |
| 8 | { |
| 9 | private bool _isExpanded; |
| 10 | private bool _isVisible = true; |
| 11 | |
| 12 | public string Title { get; } |
| 13 | public string? FullPath { get; } |
| 14 | public bool IsFolder => Children.Count > 0 && FullPath is null; |
| 15 | public ObservableCollection<SolutionItem> Children { get; } = []; |
| 16 | |
| 17 | public bool IsExpanded |
| 18 | { |
| 19 | get => _isExpanded; |
| 20 | set |
| 21 | { |
| 22 | if (_isExpanded == value) |
| 23 | return; |
| 24 | _isExpanded = value; |
| 25 | OnPropertyChanged(); |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | public bool IsVisible |
| 30 | { |
| 31 | get => _isVisible; |
| 32 | set |
| 33 | { |
| 34 | if (_isVisible == value) |
| 35 | return; |
| 36 | _isVisible = value; |
| 37 | OnPropertyChanged(); |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | /// <summary>Ключ иконки для UI: solution, project, folder, file, file_cs, file_json, file_md, file_xml, file_txt и т.д.</summary> |
| 42 | public string IconKey => GetIconKey(); |
| 43 | |
| 44 | public event PropertyChangedEventHandler? PropertyChanged; |
| 45 | |
| 46 | private string GetIconKey() |
| 47 | { |
| 48 | if (FullPath is null) |
| 49 | return Children.Count > 0 ? "folder" : "file"; |
| 50 | if (Directory.Exists(FullPath)) |
| 51 | return "folder"; |
| 52 | var p = FullPath.AsSpan(); |
| 53 | if (p.EndsWith(".slnx", StringComparison.OrdinalIgnoreCase) || p.EndsWith(".sln", StringComparison.OrdinalIgnoreCase)) |
| 54 | return "solution"; |
| 55 | if (p.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase)) |
| 56 | return "file_csproj"; |
| 57 | if (p.EndsWith(".fsproj", StringComparison.OrdinalIgnoreCase)) |
| 58 | return "file_fsproj"; |
| 59 | if (p.EndsWith(".vbproj", StringComparison.OrdinalIgnoreCase)) |
| 60 | return "file_vbproj"; |
| 61 | var ext = Path.GetExtension(FullPath); |
| 62 | if (string.IsNullOrEmpty(ext) || ext.Length <= 1) return "file"; |
| 63 | return "file_" + ext[1..].ToLowerInvariant(); |
| 64 | } |
| 65 | |
| 66 | private SolutionItem(string title, string? fullPath) |
| 67 | { |
| 68 | Title = title; |
| 69 | FullPath = fullPath; |
| 70 | } |
| 71 | |
| 72 | public static SolutionItem CreateSolution(string title, string slnPath) |
| 73 | => new(title, slnPath); |
| 74 | |
| 75 | /// <summary>Корень обозревателя при открытии каталога как workspace (без .sln). <see cref="IconKey"/> — папка.</summary> |
| 76 | public static SolutionItem CreateFolderWorkspaceRoot(string title, string folderPath) |
| 77 | => new(title, folderPath); |
| 78 | |
| 79 | public static SolutionItem CreateProject(string title, string projectPath) |
| 80 | => new(title, projectPath); |
| 81 | |
| 82 | public static SolutionItem CreateFile(string title, string filePath) |
| 83 | => new(title, filePath); |
| 84 | |
| 85 | public static SolutionItem CreateFolder(string title) |
| 86 | => new(title, null); |
| 87 | |
| 88 | private void OnPropertyChanged([CallerMemberName] string? name = null) => |
| 89 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); |
| 90 | } |
| 91 | |