From a41cb8bae00a638a8675a3f37bd9fea33bc262fd Mon Sep 17 00:00:00 2001 From: Kaphotics Date: Sat, 23 Jul 2016 01:04:55 -0700 Subject: [PATCH] Add advanced search to database Can run certain queries using the same format as BatchEditor Improved property filtering if filter is invalid. --- Subforms/PKM Editors/BatchEditor.cs | 6 ++- Subforms/SAV_Database.Designer.cs | 74 +++++++++++++++++++---------- Subforms/SAV_Database.cs | 37 +++++++++++++++ Util/ReflectUtil.cs | 6 ++- 4 files changed, 96 insertions(+), 27 deletions(-) diff --git a/Subforms/PKM Editors/BatchEditor.cs b/Subforms/PKM Editors/BatchEditor.cs index dce279af6..09a5965af 100644 --- a/Subforms/PKM Editors/BatchEditor.cs +++ b/Subforms/PKM Editors/BatchEditor.cs @@ -204,7 +204,7 @@ private void tabMain_DragDrop(object sender, DragEventArgs e) } // Utility Methods - private class StringInstruction + public class StringInstruction { public string PropertyName; public string PropertyValue; @@ -222,10 +222,14 @@ private static ModifyResult ProcessPKM(PKM PKM, IEnumerable F if (!PKM.ChecksumValid || PKM.Species == 0) return ModifyResult.Invalid; + Type pkm = PKM.GetType(); + foreach (var cmd in Filters) { try { + if (!pkm.HasProperty(cmd.PropertyName)) + return ModifyResult.Filtered; if (ReflectUtil.GetValueEquals(PKM, cmd.PropertyName, cmd.PropertyValue) != cmd.Evaluator) return ModifyResult.Filtered; } diff --git a/Subforms/SAV_Database.Designer.cs b/Subforms/SAV_Database.Designer.cs index 8c9920e2b..04ab4dbde 100644 --- a/Subforms/SAV_Database.Designer.cs +++ b/Subforms/SAV_Database.Designer.cs @@ -150,10 +150,12 @@ private void InitializeComponent() this.CHK_Shiny = new System.Windows.Forms.CheckBox(); this.TLP_Filters = new System.Windows.Forms.TableLayoutPanel(); this.FLP_Format = new System.Windows.Forms.FlowLayoutPanel(); - this.CB_Format = new System.Windows.Forms.ComboBox(); this.CB_FormatComparator = new System.Windows.Forms.ComboBox(); + this.CB_Format = new System.Windows.Forms.ComboBox(); this.L_Format = new System.Windows.Forms.Label(); this.FLP_Level = new System.Windows.Forms.FlowLayoutPanel(); + this.RTB_Instructions = new System.Windows.Forms.RichTextBox(); + this.Menu_SearchAdvanced = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.bpkx30)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.bpkx29)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.bpkx28)).BeginInit(); @@ -947,7 +949,8 @@ private void InitializeComponent() this.Menu_SearchBoxes, this.Menu_SearchDatabase, this.Menu_SearchLegal, - this.Menu_SearchIllegal}); + this.Menu_SearchIllegal, + this.Menu_SearchAdvanced}); this.Menu_SearchSettings.Image = global::PKHeX.Properties.Resources.settings; this.Menu_SearchSettings.Name = "Menu_SearchSettings"; this.Menu_SearchSettings.Size = new System.Drawing.Size(197, 22); @@ -959,7 +962,7 @@ private void InitializeComponent() this.Menu_SearchBoxes.CheckOnClick = true; this.Menu_SearchBoxes.CheckState = System.Windows.Forms.CheckState.Checked; this.Menu_SearchBoxes.Name = "Menu_SearchBoxes"; - this.Menu_SearchBoxes.Size = new System.Drawing.Size(198, 22); + this.Menu_SearchBoxes.Size = new System.Drawing.Size(207, 22); this.Menu_SearchBoxes.Text = "Search Within Boxes"; // // Menu_SearchDatabase @@ -968,7 +971,7 @@ private void InitializeComponent() this.Menu_SearchDatabase.CheckOnClick = true; this.Menu_SearchDatabase.CheckState = System.Windows.Forms.CheckState.Checked; this.Menu_SearchDatabase.Name = "Menu_SearchDatabase"; - this.Menu_SearchDatabase.Size = new System.Drawing.Size(198, 22); + this.Menu_SearchDatabase.Size = new System.Drawing.Size(207, 22); this.Menu_SearchDatabase.Text = "Search Within Database"; // // Menu_SearchLegal @@ -977,7 +980,7 @@ private void InitializeComponent() this.Menu_SearchLegal.CheckOnClick = true; this.Menu_SearchLegal.CheckState = System.Windows.Forms.CheckState.Checked; this.Menu_SearchLegal.Name = "Menu_SearchLegal"; - this.Menu_SearchLegal.Size = new System.Drawing.Size(198, 22); + this.Menu_SearchLegal.Size = new System.Drawing.Size(207, 22); this.Menu_SearchLegal.Text = "Show Legal"; // // Menu_SearchIllegal @@ -986,7 +989,7 @@ private void InitializeComponent() this.Menu_SearchIllegal.CheckOnClick = true; this.Menu_SearchIllegal.CheckState = System.Windows.Forms.CheckState.Checked; this.Menu_SearchIllegal.Name = "Menu_SearchIllegal"; - this.Menu_SearchIllegal.Size = new System.Drawing.Size(198, 22); + this.Menu_SearchIllegal.Size = new System.Drawing.Size(207, 22); this.Menu_SearchIllegal.Text = "Show Illegal"; // // Menu_OpenDB @@ -1655,8 +1658,7 @@ private void InitializeComponent() // // TLP_Filters // - this.TLP_Filters.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + this.TLP_Filters.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Right))); this.TLP_Filters.AutoScroll = true; this.TLP_Filters.AutoScrollMargin = new System.Drawing.Size(3, 3); @@ -1730,6 +1732,23 @@ private void InitializeComponent() this.FLP_Format.Size = new System.Drawing.Size(122, 21); this.FLP_Format.TabIndex = 124; // + // CB_FormatComparator + // + this.CB_FormatComparator.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.CB_FormatComparator.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.CB_FormatComparator.FormattingEnabled = true; + this.CB_FormatComparator.Items.AddRange(new object[] { + "Any", + ">=", + "==", + "<="}); + this.CB_FormatComparator.Location = new System.Drawing.Point(0, 0); + this.CB_FormatComparator.Margin = new System.Windows.Forms.Padding(0); + this.CB_FormatComparator.Name = "CB_FormatComparator"; + this.CB_FormatComparator.Size = new System.Drawing.Size(54, 21); + this.CB_FormatComparator.TabIndex = 122; + this.CB_FormatComparator.SelectedIndexChanged += new System.EventHandler(this.changeFormatFilter); + // // CB_Format // this.CB_Format.Anchor = System.Windows.Forms.AnchorStyles.Left; @@ -1748,23 +1767,6 @@ private void InitializeComponent() this.CB_Format.TabIndex = 121; this.CB_Format.Visible = false; // - // CB_FormatComparator - // - this.CB_FormatComparator.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.CB_FormatComparator.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.CB_FormatComparator.FormattingEnabled = true; - this.CB_FormatComparator.Items.AddRange(new object[] { - "Any", - ">=", - "==", - "<="}); - this.CB_FormatComparator.Location = new System.Drawing.Point(0, 0); - this.CB_FormatComparator.Margin = new System.Windows.Forms.Padding(0); - this.CB_FormatComparator.Name = "CB_FormatComparator"; - this.CB_FormatComparator.Size = new System.Drawing.Size(54, 21); - this.CB_FormatComparator.TabIndex = 122; - this.CB_FormatComparator.SelectedIndexChanged += new System.EventHandler(this.changeFormatFilter); - // // L_Format // this.L_Format.Anchor = System.Windows.Forms.AnchorStyles.Right; @@ -1789,6 +1791,25 @@ private void InitializeComponent() this.FLP_Level.Size = new System.Drawing.Size(88, 21); this.FLP_Level.TabIndex = 119; // + // RTB_Instructions + // + this.RTB_Instructions.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.RTB_Instructions.Location = new System.Drawing.Point(63, 27); + this.RTB_Instructions.Name = "RTB_Instructions"; + this.RTB_Instructions.Size = new System.Drawing.Size(235, 352); + this.RTB_Instructions.TabIndex = 119; + this.RTB_Instructions.Text = ""; + // + // Menu_SearchAdvanced + // + this.Menu_SearchAdvanced.CheckOnClick = true; + this.Menu_SearchAdvanced.Name = "Menu_SearchAdvanced"; + this.Menu_SearchAdvanced.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.A))); + this.Menu_SearchAdvanced.Size = new System.Drawing.Size(207, 22); + this.Menu_SearchAdvanced.Text = "Advanced Search"; + this.Menu_SearchAdvanced.Click += new System.EventHandler(this.Menu_SearchAdvanced_Click); + // // SAV_Database // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1801,6 +1822,7 @@ private void InitializeComponent() this.Controls.Add(this.B_Reset); this.Controls.Add(this.P_Results); this.Controls.Add(this.menuStrip1); + this.Controls.Add(this.RTB_Instructions); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximizeBox = false; @@ -2019,5 +2041,7 @@ private void InitializeComponent() private System.Windows.Forms.FlowLayoutPanel FLP_Format; private System.Windows.Forms.ComboBox CB_FormatComparator; private System.Windows.Forms.ComboBox CB_Format; + private System.Windows.Forms.RichTextBox RTB_Instructions; + private System.Windows.Forms.ToolStripMenuItem Menu_SearchAdvanced; } } \ No newline at end of file diff --git a/Subforms/SAV_Database.cs b/Subforms/SAV_Database.cs index 7b274db36..f9c0f5b2d 100644 --- a/Subforms/SAV_Database.cs +++ b/Subforms/SAV_Database.cs @@ -306,6 +306,7 @@ private void resetFilters(object sender, EventArgs e) CB_Generation.SelectedIndex = 0; MT_ESV.Visible = L_ESV.Visible = false; + RTB_Instructions.Clear(); if (sender != null) System.Media.SystemSounds.Asterisk.Play(); @@ -547,6 +548,36 @@ private void B_Search_Click(object sender, EventArgs e) if (!Menu_SearchLegal.Checked && Menu_SearchIllegal.Checked) // Illegal Only res = res.Where(pk => pk.Gen6 && pk is PK6 && !new LegalityAnalysis((PK6) pk).Valid); + if (RTB_Instructions.Lines.Any(line => line.Length > 0)) + { + var raw = + RTB_Instructions.Lines + .Where(line => !string.IsNullOrWhiteSpace(line)) + .Where(line => new[] { '!', '=' }.Contains(line[0])); + + var filters = (from line in raw + let eval = line[0] == '=' + let split = line.Substring(1).Split('=') + where split.Length == 2 && !string.IsNullOrWhiteSpace(split[0]) + select new BatchEditor.StringInstruction { PropertyName = split[0], PropertyValue = split[1], Evaluator = eval }).ToArray(); + + if (filters.Any(z => string.IsNullOrWhiteSpace(z.PropertyValue))) + { Util.Error("Empty Filter Value detected."); return; } + + res = res.Where(pkm => // Compare across all filters + { + foreach (var cmd in filters) + { + if (!pkm.GetType().HasProperty(cmd.PropertyName)) + return false; + try { if (ReflectUtil.GetValueEquals(pkm, cmd.PropertyName, cmd.PropertyValue) == cmd.Evaluator) continue; } + catch { Console.WriteLine($"Unable to compare {cmd.PropertyName} to {cmd.PropertyValue}."); } + return false; + } + return true; + }); + } + var results = res.ToArray(); if (results.Length == 0) { @@ -639,6 +670,12 @@ private void testUnique() var any = result[0][0]; m_parent.populateFields(any); } + private void Menu_SearchAdvanced_Click(object sender, EventArgs e) + { + if (!Menu_SearchAdvanced.Checked) + { Size = MinimumSize; RTB_Instructions.Clear(); } + else Size = MaximumSize; + } private void Menu_Exit_Click(object sender, EventArgs e) { diff --git a/Util/ReflectUtil.cs b/Util/ReflectUtil.cs index be844a0bc..f90a32dd2 100644 --- a/Util/ReflectUtil.cs +++ b/Util/ReflectUtil.cs @@ -32,7 +32,11 @@ internal static IEnumerable getPropertiesStartWithPrefix(Type type, stri } internal static IEnumerable getPropertiesCanWritePublic(Type type) { - return type.GetProperties().Where(p => p.CanWrite && p.GetSetMethod(/*nonPublic*/ true).IsPublic).Select(p => p.Name); + return type.GetProperties().Where(p => p.CanWrite && p.GetSetMethod(nonPublic: true).IsPublic).Select(p => p.Name); + } + internal static bool HasProperty(this Type type, string name) + { + return type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Any(p => p.Name == name); } } }