From 4cb17a8f7e67f68bdc600a0f826a35b0dea8569a Mon Sep 17 00:00:00 2001 From: Paul Hebble Date: Thu, 19 Sep 2024 14:47:47 -0500 Subject: [PATCH] Label search fixes --- GUI/Controls/EditModSearch.cs | 6 +-- GUI/Controls/EditModSearchDetails.cs | 14 +----- GUI/Controls/ManageMods.cs | 4 +- GUI/Main/Main.cs | 3 +- GUI/Model/ModList.cs | 2 +- GUI/Model/ModSearch.cs | 74 ++++++++++++++-------------- 6 files changed, 42 insertions(+), 61 deletions(-) diff --git a/GUI/Controls/EditModSearch.cs b/GUI/Controls/EditModSearch.cs index ed8efa97c..ebf245e2f 100644 --- a/GUI/Controls/EditModSearch.cs +++ b/GUI/Controls/EditModSearch.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Drawing; using System.Windows.Forms; #if NET5_0_OR_GREATER @@ -139,10 +138,7 @@ private void ImmediateHandler(object? sender, EventArgs? e) if (Main.Instance?.CurrentInstance != null) { // Sync the search boxes immediately - currentSearch = ModSearch.Parse( - FilterCombinedTextBox.Text, - ModuleLabelList.ModuleLabels.LabelsFor(Main.Instance.CurrentInstance.Name) - .ToList()); + currentSearch = ModSearch.Parse(FilterCombinedTextBox.Text); } SearchToEditor(); } diff --git a/GUI/Controls/EditModSearchDetails.cs b/GUI/Controls/EditModSearchDetails.cs index 42a8e4cc6..0d6de0197 100644 --- a/GUI/Controls/EditModSearchDetails.cs +++ b/GUI/Controls/EditModSearchDetails.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Windows.Forms; #if NET5_0_OR_GREATER @@ -45,11 +44,6 @@ public void SetFocus() } public ModSearch CurrentSearch() - => CurrentSearch( - ModuleLabelList.ModuleLabels.LabelsFor(Main.Instance?.CurrentInstance?.Name ?? "") - .ToList()); - - private ModSearch CurrentSearch(List? knownLabels) => new ModSearch( FilterByNameTextBox.Text, FilterByAuthorTextBox.Text.Split(Array.Empty(), StringSplitOptions.RemoveEmptyEntries).ToList(), @@ -62,10 +56,7 @@ private ModSearch CurrentSearch(List? knownLabels) FilterByConflictsTextBox.Text.Split(Array.Empty(), StringSplitOptions.RemoveEmptyEntries).ToList(), FilterBySupportsTextBox.Text.Split(Array.Empty(), StringSplitOptions.RemoveEmptyEntries).ToList(), FilterByTagsTextBox.Text.Split(Array.Empty(), StringSplitOptions.RemoveEmptyEntries).ToList(), - FilterByLabelsTextBox.Text.Split(Array.Empty(), StringSplitOptions.RemoveEmptyEntries) - .Select(ln => knownLabels?.FirstOrDefault(lb => lb.Name == ln)) - .OfType() - .ToList(), + FilterByLabelsTextBox.Text.Split(Array.Empty(), StringSplitOptions.RemoveEmptyEntries).ToList(), CompatibleToggle.Value, InstalledToggle.Value, CachedToggle.Value, @@ -97,8 +88,7 @@ public void PopulateSearch(ModSearch? search) ?? ""; FilterByTagsTextBox.Text = search?.TagNames.Aggregate("", CombinePieces) ?? ""; - FilterByLabelsTextBox.Text = search?.Labels.Select(lb => lb.Name) - .Aggregate("", CombinePieces) + FilterByLabelsTextBox.Text = search?.LabelNames.Aggregate("", CombinePieces) ?? ""; CompatibleToggle.Value = search?.Compatible; diff --git a/GUI/Controls/ManageMods.cs b/GUI/Controls/ManageMods.cs index f03d8e869..3281e957f 100644 --- a/GUI/Controls/ManageMods.cs +++ b/GUI/Controls/ManageMods.cs @@ -465,10 +465,8 @@ public void Filter(SavedSearch search, bool merge) { if (currentInstance != null) { - var lbls = ModuleLabelList.ModuleLabels.LabelsFor(currentInstance.Name) - .ToList(); var searches = search.Values - .Select(s => ModSearch.Parse(s, lbls)) + .Select(s => ModSearch.Parse(s)) .OfType() .ToList(); diff --git a/GUI/Main/Main.cs b/GUI/Main/Main.cs index 3603a0875..2cfaab01f 100644 --- a/GUI/Main/Main.cs +++ b/GUI/Main/Main.cs @@ -634,8 +634,7 @@ private void SetupDefaultSearch() } else { - var labels = ModuleLabelList.ModuleLabels.LabelsFor(CurrentInstance.Name).ToList(); - var searches = def.Select(s => ModSearch.Parse(s, labels)) + var searches = def.Select(s => ModSearch.Parse(s)) .OfType() .ToList(); ManageMods.SetSearches(searches); diff --git a/GUI/Model/ModList.cs b/GUI/Model/ModList.cs index 06b06fd78..6cce0b361 100644 --- a/GUI/Model/ModList.cs +++ b/GUI/Model/ModList.cs @@ -255,7 +255,7 @@ private bool TagInSearches(ModuleTag tag) => activeSearches?.Any(s => s?.TagNames.Contains(tag.Name) ?? false) ?? false; private bool LabelInSearches(ModuleLabel label) - => activeSearches?.Any(s => s?.Labels.Contains(label) ?? false) ?? false; + => activeSearches?.Any(s => s?.LabelNames.Contains(label.Name) ?? false) ?? false; private bool HiddenByTagsOrLabels(GUIMod m, string instanceName, IGame game, Registry registry) // "Hide" labels apply to all non-custom filters diff --git a/GUI/Model/ModSearch.cs b/GUI/Model/ModSearch.cs index 2542c7ec0..38b0e3cc0 100644 --- a/GUI/Model/ModSearch.cs +++ b/GUI/Model/ModSearch.cs @@ -34,7 +34,7 @@ public ModSearch( List? licenses, List? localizations, List? depends, List? recommends, List? suggests, List? conflicts, List? supports, - List? tagNames, List? labels, + List? tagNames, List? labelNames, bool? compatible, bool? installed, bool? cached, bool? newlyCompatible, bool? upgradeable, bool? replaceable, string? combined = null) @@ -53,11 +53,8 @@ public ModSearch( initStringList(ConflictsWith, conflicts); initStringList(Supports, supports); - initStringList(TagNames, tagNames); - if (labels?.Any() ?? false) - { - Labels.AddRange(labels); - } + initStringList(TagNames, tagNames); + initStringList(LabelNames, labelNames); Compatible = compatible; Installed = installed; @@ -93,15 +90,15 @@ public ModSearch(GUIModFilter filter, case GUIModFilter.Uncached: Cached = false; break; case GUIModFilter.NewInRepository: NewlyCompatible = true; break; case GUIModFilter.Tag: - if (tag?.Name is string n) + if (tag?.Name is string tn) { - TagNames.Add(n); + TagNames.Add(tn); } break; case GUIModFilter.CustomLabel: - if (label != null) + if (label?.Name is string ln) { - Labels.Add(label); + LabelNames.Add(ln); } break; default: @@ -166,8 +163,8 @@ public ModSearch(GUIModFilter filter, /// public readonly string? Combined; - public readonly List TagNames = new List(); - public readonly List Labels = new List(); + public readonly List TagNames = new List(); + public readonly List LabelNames = new List(); public readonly bool? Compatible; public readonly bool? Installed; @@ -209,7 +206,7 @@ public ModSearch MergedWith(ModSearch other) ConflictsWith.Concat(other.ConflictsWith).Distinct().ToList(), Supports.Concat(other.Supports).Distinct().ToList(), TagNames.Concat(other.TagNames).Distinct().ToList(), - Labels.Concat(other.Labels).Distinct().ToList(), + LabelNames.Concat(other.LabelNames).Distinct().ToList(), Compatible ?? other.Compatible, Installed ?? other.Installed, Cached ?? other.Cached, @@ -271,9 +268,9 @@ public ModSearch MergedWith(ModSearch other) { pieces.Add(AddTermPrefix(Properties.Resources.ModSearchTagPrefix, tagName ?? "")); } - foreach (var label in Labels) + foreach (var label in LabelNames) { - pieces.Add($"{Properties.Resources.ModSearchLabelPrefix}{label.Name.Replace(" ", "")}"); + pieces.Add($"{Properties.Resources.ModSearchLabelPrefix}{label.Replace(" ", "")}"); } if (Compatible.HasValue) { @@ -321,7 +318,7 @@ private static string triStateString(bool val, string suffix) /// /// New search object, or null if no search terms defined /// - public static ModSearch? Parse(string combined, List knownLabels) + public static ModSearch? Parse(string combined) { if (string.IsNullOrWhiteSpace(combined)) { @@ -339,8 +336,8 @@ private static string triStateString(bool val, string suffix) var conflicts = new List(); var supports = new List(); - List tagNames = new List(); - List labels = new List(); + List tagNames = new List(); + List labels = new List(); bool? compatible = null; bool? installed = null; @@ -394,13 +391,7 @@ private static string triStateString(bool val, string suffix) } else if (TryPrefix(s, Properties.Resources.ModSearchLabelPrefix, out string labelName)) { - labels.AddRange( - // Label searches exclude spaces, but label names can include them - knownLabels.Where(lb => lb.Name.Replace(" ", "") == labelName) - // If label doesn't exist, maybe it will be created later or the user is still typing. - // Make an unofficial label object to accurately reflect the search. - .DefaultIfEmpty(new ModuleLabel(labelName)) - ); + labels.Add(labelName); } else if (TryPrefix(s, Properties.Resources.ModSearchYesPrefix, out string yesSuffix)) { @@ -601,21 +592,28 @@ private static bool RelationshipMatch(List? rels, List r.StartsWith(subRel)))); private bool MatchesTags(GUIMod mod) - { - var tagsInMod = mod.ToModule().Tags; - return TagNames.Count < 1 + => TagNames.Count < 1 || TagNames.All(tn => - ShouldNegateTerm(tn, out string subTag) ^ ( - string.IsNullOrEmpty(subTag) - ? tagsInMod == null - : tagsInMod?.Contains(subTag) ?? false)); - } + ShouldNegateTerm(tn, out string subTag) ^ ( + string.IsNullOrEmpty(subTag) + ? mod.ToModule().Tags == null + : mod.ToModule().Tags?.Contains(subTag) ?? false)); private bool MatchesLabels(GUIMod mod) - // Every label in Labels must contain this mod - => Main.Instance?.CurrentInstance != null - && (Labels.Count < 1 - || Labels.All(lb => lb.ContainsModule(Main.Instance.CurrentInstance.game, mod.Identifier))); + => LabelNames.Count < 1 + || (Main.Instance?.CurrentInstance is GameInstance inst + && ModuleLabelList.ModuleLabels.LabelsFor(inst.Name) + .ToArray() + is ModuleLabel[] instanceLabels + && LabelNames.All(ln => + ShouldNegateTerm(ln, out string subLabel) ^ ( + string.IsNullOrEmpty(subLabel) + ? instanceLabels.All(lbl => !lbl.ContainsModule(inst.game, mod.Identifier)) + : instanceLabels.Where(lbl => lbl.Name == subLabel) + .ToArray() + is ModuleLabel[] myLabels + && myLabels.Length > 0 + && myLabels.All(lbl => lbl.ContainsModule(inst.game, mod.Identifier))))); private bool MatchesCompatible(GUIMod mod) => !Compatible.HasValue || Compatible.Value == !mod.IsIncompatible; @@ -654,7 +652,7 @@ public bool Equals(ModSearch? other) && ConflictsWith.SequenceEqual(other.ConflictsWith) && Supports.SequenceEqual(other.Supports) && TagNames.SequenceEqual(other.TagNames) - && Labels.SequenceEqual(other.Labels); + && LabelNames.SequenceEqual(other.LabelNames); public override bool Equals(object? obj) => Equals(obj as ModSearch);