Forge
csharp4405de34
1using System.Collections.ObjectModel;
2using CascadeIDE.Features.Documents;
3using CascadeIDE.Features.Shell.Application;
4using CascadeIDE.Features.Workspace.Application;
5using CascadeIDE.Models;
6using Avalonia.Input.Platform;
7using CommunityToolkit.Mvvm.ComponentModel;
8using CommunityToolkit.Mvvm.Input;
9
10namespace CascadeIDE.ViewModels;
11
12/// <summary>Solution Explorer: фильтр, compact, track active, индекс файлов (ADR 0167).</summary>
13public partial class MainWindowViewModel
14{
15 private readonly WorkspaceFileIndex _workspaceFileIndex = new();
16
17 public WorkspaceFileIndex WorkspaceFileIndex => _workspaceFileIndex;
18
19 [ObservableProperty]
20 private bool _solutionExplorerTrackActiveItem;
21
22 [ObservableProperty]
23 private bool _solutionExplorerCompactTree;
24
25 [ObservableProperty]
26 private string _solutionExplorerFilterText = "";
27
28 [ObservableProperty]
29 private ObservableCollection<SolutionItem> _solutionExplorerDisplayRoots = [];
30
31 [ObservableProperty]
32 private SolutionItem? _solutionExplorerSelectedItem;
33
34 internal void ApplySolutionExplorerSettingsFromModel(SolutionExplorerSettings settings)
35 {
36 SolutionExplorerTrackActiveItem = settings.TrackActiveItem;
37 SolutionExplorerCompactTree = settings.CompactTree;
38 }
39
40 partial void OnSolutionExplorerFilterTextChanged(string value) =>
41 RefreshSolutionExplorerTreeFilter();
42
43 partial void OnSolutionExplorerTrackActiveItemChanged(bool value)
44 {
45 _settings.Workspace.SolutionExplorer.TrackActiveItem = value;
46 SaveSettingsIfChanged();
47 if (value)
48 Documents.SyncSelectedSolutionItemToCurrentFile();
49 }
50
51 partial void OnSolutionExplorerCompactTreeChanged(bool value)
52 {
53 _settings.Workspace.SolutionExplorer.CompactTree = value;
54 SaveSettingsIfChanged();
55 }
56
57 internal void InvalidateWorkspaceFileIndex() =>
58 _workspaceFileIndex.Invalidate(
59 Workspace.SolutionRoots,
60 Workspace.SolutionPath,
61 GetWorkspacePath() ?? "");
62
63 internal void RefreshSolutionExplorerTreeFilter()
64 {
65 InvalidateWorkspaceFileIndex();
66 SolutionExplorerTreeFilter.RebuildDisplayRoots(
67 Workspace.SolutionRoots,
68 SolutionExplorerDisplayRoots,
69 SolutionExplorerFilterText,
70 _workspaceFileIndex);
71 }
72
73 partial void OnSolutionExplorerSelectedItemChanged(SolutionItem? value)
74 {
75 if (value?.FullPath is { } path
76 && SolutionTreePath.TryGetFullPath(path, out var normalized))
77 {
78 Workspace.SelectedSolutionItem =
79 SolutionTreePath.FindItemByFullPath(Workspace.SolutionRoots, normalized) ?? value;
80 return;
81 }
82
83 Workspace.SelectedSolutionItem = value;
84 }
85
86 [RelayCommand]
87 private void OpenGoToFilePalette()
88 {
89 IsCommandPaletteOpen = true;
90 CommandPaletteQuery = "f:";
91 RefreshCommandPaletteFilter();
92 CommandPaletteSelectedIndex = CommandPaletteSelectionProjection.InitialSelectedIndex(
93 FilteredCommandPaletteEntries.Count);
94 }
95
96 [RelayCommand]
97 public void FocusSolutionExplorerFilter()
98 {
99 Shell.ShowSolutionExplorerPageCommand.Execute(null);
100 SolutionExplorerFilterFocusRequested?.Invoke();
101 }
102
103 /// <summary>View подписывается, чтобы сфокусировать поле фильтра SE.</summary>
104 internal event Action? SolutionExplorerFilterFocusRequested;
105
106 [RelayCommand]
107 private void OpenSelectedSolutionItem()
108 {
109 var item = Workspace.SelectedSolutionItem;
110 if (item?.FullPath is not { } path || Directory.Exists(path))
111 return;
112 Documents.OpenOrActivateDocument(path);
113 }
114
115 [RelayCommand]
116 private async Task CopySelectedSolutionItemPathAsync()
117 {
118 var item = Workspace.SelectedSolutionItem;
119 if (item?.FullPath is not { } path)
120 return;
121 if (Avalonia.Application.Current?.ApplicationLifetime is Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktop
122 && desktop.MainWindow?.Clipboard is { } clipboard)
123 await clipboard.SetTextAsync(path);
124 }
125
126 [RelayCommand]
127 private void RevealSelectedSolutionItemInExplorer()
128 {
129 var item = Workspace.SelectedSolutionItem;
130 if (item?.FullPath is not { } path)
131 return;
132 WindowsShellReveal.TryRevealInExplorer(path);
133 }
134}
135
View only · write via MCP/CIDE