|
|
@@ -1,183 +1,173 @@
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
+using System.Collections.ObjectModel;
|
|
|
+using System.ComponentModel;
|
|
|
using System.Linq;
|
|
|
+using System.Runtime.CompilerServices;
|
|
|
+using System.Threading.Tasks;
|
|
|
using System.Windows;
|
|
|
using System.Windows.Controls;
|
|
|
-using System.ComponentModel;
|
|
|
-using System.Collections.ObjectModel;
|
|
|
|
|
|
namespace Quadarax.Application.Tools.Vsix.FilteredSolutionsExtension
|
|
|
{
|
|
|
- public partial class ProjectFilterDialog : Window
|
|
|
+ public partial class ProjectFilterDialog : Window, INotifyPropertyChanged
|
|
|
{
|
|
|
private readonly SolutionInfo _solutionInfo;
|
|
|
- private readonly ObservableCollection<ProjectTreeItem> _projectItems;
|
|
|
- private readonly ObservableCollection<ProjectTreeItem> _filteredItems;
|
|
|
+ private readonly SolutionParser _solutionParser;
|
|
|
+ private string _filterPattern = "";
|
|
|
|
|
|
- public List<ProjectInfo> SelectedProjects { get; private set; } = new List<ProjectInfo>();
|
|
|
+ public string FilteredSolutionPath { get; private set; }
|
|
|
+ public ObservableCollection<ProjectNode> Projects { get; set; }
|
|
|
+
|
|
|
+ public string FilterPattern
|
|
|
+ {
|
|
|
+ get => _filterPattern;
|
|
|
+ set
|
|
|
+ {
|
|
|
+ _filterPattern = value;
|
|
|
+ OnPropertyChanged();
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
public ProjectFilterDialog(SolutionInfo solutionInfo)
|
|
|
{
|
|
|
InitializeComponent();
|
|
|
- _solutionInfo = solutionInfo;
|
|
|
- _projectItems = new ObservableCollection<ProjectTreeItem>(CreateProjectTreeItems());
|
|
|
- _filteredItems = new ObservableCollection<ProjectTreeItem>(_projectItems);
|
|
|
+ DataContext = this;
|
|
|
|
|
|
- ProjectTreeView.ItemsSource = _filteredItems;
|
|
|
- Title = $"Select Projects - {System.IO.Path.GetFileNameWithoutExtension(_solutionInfo.SolutionPath)}";
|
|
|
+ _solutionInfo = solutionInfo ?? throw new ArgumentNullException(nameof(solutionInfo));
|
|
|
+ _solutionParser = new SolutionParser();
|
|
|
+ Projects = new ObservableCollection<ProjectNode>();
|
|
|
|
|
|
- // Subscribe to property changes for dependency handling
|
|
|
- foreach (var item in _projectItems)
|
|
|
- {
|
|
|
- item.PropertyChanged += ProjectItem_PropertyChanged;
|
|
|
- }
|
|
|
+ Title = $"Filter Projects - {_solutionInfo.Name}";
|
|
|
+
|
|
|
+ // Load projects asynchronously
|
|
|
+ Loaded += async (s, e) => await LoadProjectsAsync();
|
|
|
}
|
|
|
|
|
|
- private void ProjectItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
|
+ private async Task LoadProjectsAsync()
|
|
|
{
|
|
|
- if (e.PropertyName == nameof(ProjectTreeItem.IsChecked))
|
|
|
+ try
|
|
|
{
|
|
|
- var item = sender as ProjectTreeItem;
|
|
|
- if (item != null)
|
|
|
+ // Show loading indicator
|
|
|
+ ProjectTreeView.Visibility = Visibility.Hidden;
|
|
|
+ var loadingLabel = new System.Windows.Controls.Label
|
|
|
{
|
|
|
- if (item.IsChecked)
|
|
|
- {
|
|
|
- CheckDependencies(item.ProjectInfo);
|
|
|
- }
|
|
|
- else
|
|
|
+ Content = "Loading projects...",
|
|
|
+ HorizontalAlignment = HorizontalAlignment.Center,
|
|
|
+ VerticalAlignment = VerticalAlignment.Center,
|
|
|
+ FontSize = 14
|
|
|
+ };
|
|
|
+
|
|
|
+ var grid = (Grid)Content;
|
|
|
+ Grid.SetRow(loadingLabel, 2);
|
|
|
+ grid.Children.Add(loadingLabel);
|
|
|
+
|
|
|
+ var projects = await _solutionParser.ParseSolutionAsync(_solutionInfo.FullPath);
|
|
|
+
|
|
|
+ Application.Current.Dispatcher.Invoke(() =>
|
|
|
+ {
|
|
|
+ Projects.Clear();
|
|
|
+ foreach (var project in projects)
|
|
|
{
|
|
|
- UncheckDependents(item.ProjectInfo);
|
|
|
+ Projects.Add(project);
|
|
|
}
|
|
|
- }
|
|
|
+
|
|
|
+ // Build dependency tree
|
|
|
+ _solutionParser.BuildDependencyTree(Projects.ToList());
|
|
|
+
|
|
|
+ // Remove loading indicator and show tree
|
|
|
+ grid.Children.Remove(loadingLabel);
|
|
|
+ ProjectsTreeView.Visibility = Visibility.Visible;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ MessageBox.Show($"Error loading solution: {ex.Message}\n\nPlease try opening the solution normally and use the File menu to filter projects.",
|
|
|
+ "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
+ DialogResult = false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private List<ProjectTreeItem> CreateProjectTreeItems()
|
|
|
+ private void SelectAll_Click(object sender, RoutedEventArgs e)
|
|
|
{
|
|
|
- return _solutionInfo.Projects.Select(p => new ProjectTreeItem(p)).ToList();
|
|
|
+ foreach (var project in Projects)
|
|
|
+ {
|
|
|
+ project.IsSelected = true;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- private void SelectAllButton_Click(object sender, RoutedEventArgs e)
|
|
|
+ private void ClearAll_Click(object sender, RoutedEventArgs e)
|
|
|
{
|
|
|
- foreach (var item in _projectItems)
|
|
|
+ foreach (var project in Projects)
|
|
|
{
|
|
|
- item.IsChecked = true;
|
|
|
+ project.IsSelected = false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void ClearAllButton_Click(object sender, RoutedEventArgs e)
|
|
|
+ private void Filter_Click(object sender, RoutedEventArgs e)
|
|
|
{
|
|
|
- foreach (var item in _projectItems)
|
|
|
- {
|
|
|
- item.IsChecked = false;
|
|
|
- }
|
|
|
+ ApplyFilter();
|
|
|
}
|
|
|
|
|
|
- private void FilterButton_Click(object sender, RoutedEventArgs e)
|
|
|
+ private void ApplyFilter()
|
|
|
{
|
|
|
- var pattern = FilterTextBox.Text.Trim();
|
|
|
- _filteredItems.Clear();
|
|
|
-
|
|
|
- if (string.IsNullOrEmpty(pattern))
|
|
|
- {
|
|
|
- foreach (var item in _projectItems)
|
|
|
- {
|
|
|
- _filteredItems.Add(item);
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
+ if (string.IsNullOrWhiteSpace(FilterPattern))
|
|
|
{
|
|
|
- var matchingItems = _projectItems.Where(item =>
|
|
|
- MatchesPattern(item.ProjectInfo.DisplayName, pattern));
|
|
|
-
|
|
|
- foreach (var item in matchingItems)
|
|
|
+ foreach (var project in Projects)
|
|
|
{
|
|
|
- _filteredItems.Add(item);
|
|
|
+ project.IsVisible = true;
|
|
|
}
|
|
|
+ return;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- private bool MatchesPattern(string text, string pattern)
|
|
|
- {
|
|
|
- if (string.IsNullOrEmpty(pattern)) return true;
|
|
|
-
|
|
|
- // Simple wildcard matching
|
|
|
- pattern = pattern.Replace("*", ".*").Replace("?", ".");
|
|
|
- return System.Text.RegularExpressions.Regex.IsMatch(text, pattern,
|
|
|
+ var pattern = FilterPattern.Replace("*", ".*");
|
|
|
+ var regex = new System.Text.RegularExpressions.Regex(pattern,
|
|
|
System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|
|
- }
|
|
|
|
|
|
- private void OkButton_Click(object sender, RoutedEventArgs e)
|
|
|
- {
|
|
|
- var checkedItems = _projectItems.Where(item => item.IsChecked).ToList();
|
|
|
- SelectedProjects = checkedItems.Select(item => item.ProjectInfo).ToList();
|
|
|
-
|
|
|
- // Ensure all dependencies are included (should already be checked due to auto-checking)
|
|
|
- var finalProjects = new HashSet<ProjectInfo>(SelectedProjects);
|
|
|
- foreach (var project in SelectedProjects.ToList())
|
|
|
+ foreach (var project in Projects)
|
|
|
{
|
|
|
- AddDependencies(project, finalProjects);
|
|
|
+ project.IsVisible = regex.IsMatch(project.Name);
|
|
|
}
|
|
|
-
|
|
|
- SelectedProjects = finalProjects.ToList();
|
|
|
- DialogResult = true;
|
|
|
- Close();
|
|
|
}
|
|
|
|
|
|
- private void AddDependencies(ProjectInfo project, HashSet<ProjectInfo> finalProjects)
|
|
|
+ private async void Ok_Click(object sender, RoutedEventArgs e)
|
|
|
{
|
|
|
- foreach (var depGuid in project.Dependencies)
|
|
|
+ try
|
|
|
{
|
|
|
- var depProject = _solutionInfo.Projects.FirstOrDefault(p =>
|
|
|
- p.ProjectGuid.Equals(depGuid, StringComparison.OrdinalIgnoreCase));
|
|
|
-
|
|
|
- if (depProject != null && !finalProjects.Contains(depProject))
|
|
|
+ var selectedProjects = Projects.Where(p => p.IsSelected).ToList();
|
|
|
+ if (!selectedProjects.Any())
|
|
|
{
|
|
|
- finalProjects.Add(depProject);
|
|
|
- AddDependencies(depProject, finalProjects);
|
|
|
+ MessageBox.Show("Please select at least one project.", "Warning",
|
|
|
+ MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ // Include dependencies
|
|
|
+ var projectsWithDependencies = _solutionParser.GetProjectsWithDependencies(selectedProjects);
|
|
|
+
|
|
|
+ // Create filtered solution
|
|
|
+ FilteredSolutionPath = await _solutionParser.CreateFilteredSolutionAsync(
|
|
|
+ _solutionInfo.FullPath, projectsWithDependencies);
|
|
|
+
|
|
|
+ DialogResult = true;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ MessageBox.Show($"Error creating filtered solution: {ex.Message}", "Error",
|
|
|
+ MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void CancelButton_Click(object sender, RoutedEventArgs e)
|
|
|
+ private void Cancel_Click(object sender, RoutedEventArgs e)
|
|
|
{
|
|
|
DialogResult = false;
|
|
|
- Close();
|
|
|
}
|
|
|
|
|
|
- private void CheckDependencies(ProjectInfo project)
|
|
|
- {
|
|
|
- foreach (var depGuid in project.Dependencies)
|
|
|
- {
|
|
|
- var depItem = _projectItems.FirstOrDefault(item =>
|
|
|
- item.ProjectInfo.ProjectGuid.Equals(depGuid, StringComparison.OrdinalIgnoreCase));
|
|
|
-
|
|
|
- if (depItem != null && !depItem.IsChecked)
|
|
|
- {
|
|
|
- depItem.PropertyChanged -= ProjectItem_PropertyChanged; // Temporarily unsubscribe
|
|
|
- depItem.IsChecked = true;
|
|
|
- depItem.PropertyChanged += ProjectItem_PropertyChanged; // Resubscribe
|
|
|
- CheckDependencies(depItem.ProjectInfo);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
|
|
- private void UncheckDependents(ProjectInfo project)
|
|
|
+ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
|
{
|
|
|
- foreach (var item in _projectItems)
|
|
|
- {
|
|
|
- if (item.ProjectInfo.Dependencies.Contains(project.ProjectGuid) && item.IsChecked)
|
|
|
- {
|
|
|
- item.PropertyChanged -= ProjectItem_PropertyChanged; // Temporarily unsubscribe
|
|
|
- item.IsChecked = false;
|
|
|
- item.PropertyChanged += ProjectItem_PropertyChanged; // Resubscribe
|
|
|
- UncheckDependents(item.ProjectInfo);
|
|
|
- }
|
|
|
- }
|
|
|
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
}
|
|
|
-
|
|
|
- // Remove the old event handlers as we're using PropertyChanged now
|
|
|
- private void ProjectTreeItem_Checked(object sender, RoutedEventArgs e) { }
|
|
|
- private void ProjectTreeItem_Unchecked(object sender, RoutedEventArgs e) { }
|
|
|
}
|
|
|
}
|