From 519f53cf3ad58c76961944e8fef2ca5c59fdf3e1 Mon Sep 17 00:00:00 2001 From: William Date: Thu, 2 Feb 2023 19:21:51 +0000 Subject: [PATCH] Project search system (#12) Co-authored-by: jonko0493 --- src/SerialLoops/Controls/ItemContextMenu.cs | 68 ++++++++++++++++ src/SerialLoops/Controls/ItemExplorerPanel.cs | 31 ++------ src/SerialLoops/Controls/ItemListPanel.cs | 59 ++++++++++++++ src/SerialLoops/Controls/ItemResultsPanel.cs | 31 ++++++++ src/SerialLoops/Controls/SectionList.cs | 15 ++-- src/SerialLoops/FindItemsDialog.cs | 39 ++++++++++ src/SerialLoops/MainForm.eto.cs | 29 ++++++- src/SerialLoops/ReferenceDialog.cs | 15 ++++ src/SerialLoops/ReferenceDialog.eto.cs | 61 +++++++++++++++ src/SerialLoops/SearchDialog.cs | 15 ++++ src/SerialLoops/SearchDialog.eto.cs | 77 +++++++++++++++++++ src/SerialLoops/SerialLoops.csproj | 6 ++ 12 files changed, 411 insertions(+), 35 deletions(-) create mode 100644 src/SerialLoops/Controls/ItemContextMenu.cs create mode 100644 src/SerialLoops/Controls/ItemListPanel.cs create mode 100644 src/SerialLoops/Controls/ItemResultsPanel.cs create mode 100644 src/SerialLoops/FindItemsDialog.cs create mode 100644 src/SerialLoops/ReferenceDialog.cs create mode 100644 src/SerialLoops/ReferenceDialog.eto.cs create mode 100644 src/SerialLoops/SearchDialog.cs create mode 100644 src/SerialLoops/SearchDialog.eto.cs diff --git a/src/SerialLoops/Controls/ItemContextMenu.cs b/src/SerialLoops/Controls/ItemContextMenu.cs new file mode 100644 index 00000000..49c1a182 --- /dev/null +++ b/src/SerialLoops/Controls/ItemContextMenu.cs @@ -0,0 +1,68 @@ +using Eto.Forms; +using HaruhiChokuretsuLib.Util; +using SerialLoops.Lib; +using SerialLoops.Lib.Items; +using System; + +namespace SerialLoops.Controls +{ + internal class ItemContextMenu : ContextMenu + { + + private readonly ILogger _log; + private readonly Project _project; + + private readonly EditorTabsPanel _tabs; + private readonly ItemExplorerPanel _explorer; + + public ItemContextMenu(Project project, ItemExplorerPanel explorer, EditorTabsPanel tabs, ILogger log) + { + _project = project; + _tabs = tabs; + _explorer = explorer; + _log = log; + + Command openCommand = new(); + openCommand.Executed += OpenCommand_OnClick; + Items.Add(new ButtonMenuItem { Text = "Open", Command = openCommand }); + + Command findReferences = new(); + findReferences.Executed += FindReferences_OnClick; + Items.Add(new ButtonMenuItem { Text = "Find References...", Command = findReferences }); + + Command findReferencedBy = new(); + findReferencedBy.Executed += FindReferencedBy_OnClick; + Items.Add(new ButtonMenuItem { Text = "Find Referenced By...", Command = findReferencedBy }); + } + + private void OpenCommand_OnClick(object sender, EventArgs args) + { + ItemDescription item = _project.FindItem(_explorer.Viewer.SelectedItem?.Text); + if (item != null) + { + _tabs.OpenTab(item, _log); + } + } + + private void FindReferences_OnClick(object sender, EventArgs args) + { + ShowReferences(ReferenceDialog.ReferenceMode.REFERENCES_TO); + } + + private void FindReferencedBy_OnClick(object sender, EventArgs args) + { + ShowReferences(ReferenceDialog.ReferenceMode.REFERENCED_BY); + } + + private void ShowReferences(ReferenceDialog.ReferenceMode mode) + { + ItemDescription item = _project.FindItem(_explorer.Viewer.SelectedItem?.Text); + if (item != null) + { + ReferenceDialog referenceDialog = new(item, mode, _project, _explorer, _tabs, _log); + referenceDialog.ShowModal(_explorer); + } + } + + } +} diff --git a/src/SerialLoops/Controls/ItemExplorerPanel.cs b/src/SerialLoops/Controls/ItemExplorerPanel.cs index 19cee9ea..98a1657c 100644 --- a/src/SerialLoops/Controls/ItemExplorerPanel.cs +++ b/src/SerialLoops/Controls/ItemExplorerPanel.cs @@ -4,44 +4,23 @@ using SerialLoops.Lib; using SerialLoops.Lib.Items; using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; namespace SerialLoops.Controls { - public class ItemExplorerPanel : Scrollable + public class ItemExplorerPanel : ItemListPanel { - private ILogger _log; - public static readonly Size ITEM_EXPLORER_BASE_SIZE = new(200, 420); - private SectionListTreeGridView _items; private readonly Project _project; private readonly EditorTabsPanel _tabs; - - public ItemExplorerPanel(Project project, EditorTabsPanel tabs, ILogger log) + + public ItemExplorerPanel(Project project, EditorTabsPanel tabs, ILogger log) : base(project.Items, new Size(200, 420), false, log) { - _log = log; _project = project; _tabs = tabs; - InitializeComponent(); - } - - void InitializeComponent() - { - MinimumSize = ITEM_EXPLORER_BASE_SIZE; - Padding = 0; - - IEnumerable
sections = _project.Items.GroupBy(i => i.Type).OrderBy(g => g.Key) - .Select(g => new Section($"{g.Key}s", g.Select(i => new Section() { Text = i.Name }), EditorTabsPanel.GetItemIcon(g.Key, _log))); - - _items = new SectionListTreeGridView(sections, ITEM_EXPLORER_BASE_SIZE); - _items.Activated += ItemList_ItemClicked; - - Content = new TableLayout(_items.Control); + ((TreeGridView)Viewer.Control).ContextMenu = new ItemContextMenu(project, this, tabs, _log); } - private void ItemList_ItemClicked(object sender, EventArgs e) + protected override void ItemList_ItemClicked(object sender, EventArgs e) { if (sender is SectionListTreeGridView view) { diff --git a/src/SerialLoops/Controls/ItemListPanel.cs b/src/SerialLoops/Controls/ItemListPanel.cs new file mode 100644 index 00000000..f8fcc2bc --- /dev/null +++ b/src/SerialLoops/Controls/ItemListPanel.cs @@ -0,0 +1,59 @@ +using Eto.Drawing; +using Eto.Forms; +using HaruhiChokuretsuLib.Util; +using SerialLoops.Lib; +using SerialLoops.Lib.Items; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SerialLoops.Controls +{ + public abstract class ItemListPanel : Scrollable + { + public List Items + { + protected get { return _items; } + set + { + _items = value; + Viewer?.SetContents(GetSections(), _expandItems); + } + } + public SectionListTreeGridView Viewer { get; private set; } + + protected ILogger _log; + private readonly Size _size; + private List _items; + private readonly bool _expandItems; + + protected ItemListPanel(List items, Size size, bool expandItems, ILogger log) + { + Items = items; + _log = log; + _size = size; + _expandItems = expandItems; + InitializeComponent(); + } + + void InitializeComponent() + { + Viewer = new SectionListTreeGridView(GetSections(), _size, _expandItems); + MinimumSize = _size; + Padding = 0; + Content = new TableLayout(Viewer.Control); + Viewer.Activated += ItemList_ItemClicked; + } + + private IEnumerable
GetSections() + { + return Items.GroupBy(i => i.Type).OrderBy(g => g.Key) + .Select(g => new Section($"{g.Key}s", g.Select(i => new Section() { Text = i.Name }), EditorTabsPanel.GetItemIcon(g.Key, _log))); + } + + protected abstract void ItemList_ItemClicked(object sender, EventArgs e); + + } +} diff --git a/src/SerialLoops/Controls/ItemResultsPanel.cs b/src/SerialLoops/Controls/ItemResultsPanel.cs new file mode 100644 index 00000000..7034afe2 --- /dev/null +++ b/src/SerialLoops/Controls/ItemResultsPanel.cs @@ -0,0 +1,31 @@ +using Eto.Drawing; +using Eto.Forms; +using HaruhiChokuretsuLib.Util; +using SerialLoops.Lib; +using SerialLoops.Lib.Items; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace SerialLoops.Controls +{ + public class ItemResultsPanel : ItemListPanel + { + public FindItemsDialog Dialog; + public ItemResultsPanel(List results, ILogger log) : base(results, new Size(280, 185), true, log) { } + + protected override void ItemList_ItemClicked(object sender, EventArgs e) + { + if (sender is SectionListTreeGridView view) + { + ItemDescription item = Dialog.Project.FindItem(view.SelectedItem?.Text); + if (item != null) + { + Dialog.Tabs.OpenTab(item, _log); + } + Dialog.Close(); + } + } + } +} \ No newline at end of file diff --git a/src/SerialLoops/Controls/SectionList.cs b/src/SerialLoops/Controls/SectionList.cs index 4860677b..e94e5460 100644 --- a/src/SerialLoops/Controls/SectionList.cs +++ b/src/SerialLoops/Controls/SectionList.cs @@ -81,13 +81,13 @@ public class SectionTreeItem : List, ITreeGridItem Count > 0; public ITreeGridItem Parent { get; set; } - public SectionTreeItem(Section section) + public SectionTreeItem(Section section, bool expanded) { Section = section; - Expanded = false; + Expanded = expanded; foreach (var child in section) { - SectionTreeItem temp = new(child) { Parent = this }; + SectionTreeItem temp = new(child, expanded) { Parent = this }; Add(temp); // recursive } } @@ -158,7 +158,7 @@ ITreeGridItem FindItem(SectionTreeItem node, ISection section) return null; } - public SectionListTreeGridView(IEnumerable
topNodes, Size size) + public SectionListTreeGridView(IEnumerable
topNodes, Size size, bool expanded) { _treeView = new TreeGridView { @@ -176,8 +176,13 @@ public SectionListTreeGridView(IEnumerable
topNodes, Size size) }); _treeView.SelectedItemChanged += (sender, e) => OnSelectedItemChanged(e); _treeView.Activated += (sender, e) => OnActivated(e); - _treeView.DataStore = new SectionTreeItem(new Section("Top", topNodes, null)); _treeView.Size = size; + SetContents(topNodes, expanded); + } + + public void SetContents(IEnumerable
topNodes, bool expanded) + { + _treeView.DataStore = new SectionTreeItem(new Section("Top", topNodes, null), expanded); } } } \ No newline at end of file diff --git a/src/SerialLoops/FindItemsDialog.cs b/src/SerialLoops/FindItemsDialog.cs new file mode 100644 index 00000000..c132cff6 --- /dev/null +++ b/src/SerialLoops/FindItemsDialog.cs @@ -0,0 +1,39 @@ +using Eto.Forms; +using HaruhiChokuretsuLib.Util; +using SerialLoops.Controls; +using SerialLoops.Lib; +using SerialLoops.Lib.Logging; +using System; + +namespace SerialLoops +{ + public abstract class FindItemsDialog : Dialog + { + public ILogger Log; + public EditorTabsPanel Tabs; + public ItemExplorerPanel Explorer; + public Project Project; + + protected override void OnLoad(EventArgs e) + { + if (Log is null) + { + // We can't log that log is null, so we have to throw + throw new LoggerNullException(); + } + if (Project is null) + { + Log.LogError($"Project not provided to project creation dialog"); + Close(); + } + if (Tabs is null) + { + Log.LogError($"Editor Tabs not provided to project creation dialog"); + Close(); + } + base.OnLoad(e); + } + + } + +} diff --git a/src/SerialLoops/MainForm.eto.cs b/src/SerialLoops/MainForm.eto.cs index a709004e..da4a93ae 100644 --- a/src/SerialLoops/MainForm.eto.cs +++ b/src/SerialLoops/MainForm.eto.cs @@ -13,6 +13,8 @@ public partial class MainForm : Form private LoopyLogger _log; public Config CurrentConfig { get; set; } public Project OpenProject { get; set; } + public EditorTabsPanel EditorTabs { get; set; } + public ItemExplorerPanel ItemExplorer { get; set; } void InitializeComponent() { @@ -30,6 +32,10 @@ void InitializeComponent() Command openProject = new() { MenuText = "Open Project", ToolBarText = "Open Project" }; openProject.Executed += OpenProject_Executed; + // Tools + Command searchProject = new() { MenuText = "Search", ToolBarText = "Search", Shortcut = Application.Instance.CommonModifier | Keys.F }; + searchProject.Executed += Search_Executed; + // About Command aboutCommand = new() { MenuText = "About..." }; AboutDialog aboutDialog = new() { ProgramName = "Serial Loops", Developers = new string[] { "Jonko", "William" }, Copyright = "© Haroohie Translation Club, 2023", Website = new Uri("https://haroohie.club") }; @@ -42,9 +48,10 @@ void InitializeComponent() { // File submenu new SubMenuItem { Text = "&File", Items = { newProject, openProject } }, + new SubMenuItem { Text = "&Tools", Items = { searchProject } }, // new SubMenuItem { Text = "&Edit", Items = { /* commands/items */ } }, // new SubMenuItem { Text = "&View", Items = { /* commands/items */ } }, - new SubMenuItem { Text = "&Build", Items = { } }, + //new SubMenuItem { Text = "&Build", Items = { } }, }, ApplicationItems = { @@ -57,10 +64,10 @@ void InitializeComponent() private void OpenProjectView(Project project) { - EditorTabsPanel tabs = new(project); - ItemExplorerPanel items = new(project, tabs, _log); + EditorTabs = new(project); + ItemExplorer = new(project, EditorTabs, _log); Title = $"{BASE_TITLE} - {project.Name}"; - Content = new TableLayout(new TableRow(items, tabs)); + Content = new TableLayout(new TableRow(ItemExplorer, EditorTabs)); } protected override void OnLoad(EventArgs e) @@ -91,5 +98,19 @@ private void OpenProject_Executed(object sender, EventArgs e) OpenProjectView(OpenProject); } } + + private void Search_Executed(object sender, EventArgs e) + { + if (OpenProject is not null) + { + SearchDialog searchDialog = new() + { + Project = OpenProject, + Tabs = EditorTabs, + Log = _log + }; + searchDialog.ShowModal(this); + } + } } } diff --git a/src/SerialLoops/ReferenceDialog.cs b/src/SerialLoops/ReferenceDialog.cs new file mode 100644 index 00000000..5cd2dfb7 --- /dev/null +++ b/src/SerialLoops/ReferenceDialog.cs @@ -0,0 +1,15 @@ +using System; +using Eto.Forms; +using Eto.Drawing; +using System.Collections.Generic; + +namespace SerialLoops +{ + public partial class ReferenceDialog : FindItemsDialog + { + public ReferenceDialog() + { + InitializeComponent(); + } + } +} diff --git a/src/SerialLoops/ReferenceDialog.eto.cs b/src/SerialLoops/ReferenceDialog.eto.cs new file mode 100644 index 00000000..a61739b1 --- /dev/null +++ b/src/SerialLoops/ReferenceDialog.eto.cs @@ -0,0 +1,61 @@ +using Eto.Drawing; +using Eto.Forms; +using HaruhiChokuretsuLib.Util; +using SerialLoops.Controls; +using SerialLoops.Lib; +using SerialLoops.Lib.Items; +using System.Collections.Generic; + +namespace SerialLoops +{ + partial class ReferenceDialog : FindItemsDialog + { + public ReferenceMode Mode; + public ItemDescription Item; + + public ReferenceDialog(ItemDescription item, ReferenceMode mode, Project project, ItemExplorerPanel explorer, EditorTabsPanel tabs, ILogger log) + { + Item = item; + Mode = mode; + Project = project; + Explorer = explorer; + Tabs = tabs; + Log = log; + InitializeComponent(); + } + + private void InitializeComponent() + { + Title = Mode == ReferenceMode.REFERENCES_TO ? $"References to {Item.Name}" : $"Items referenced by {Item.Name}"; + MinimumSize = new Size(400, 275); + Padding = 10; + + List results = GetResults(); + Content = new StackLayout + { + Orientation = Orientation.Vertical, + HorizontalContentAlignment = HorizontalAlignment.Center, + Spacing = 10, + Padding = 10, + Items = + { + $"{results.Count} items that {(Mode == ReferenceMode.REFERENCES_TO ? "reference" : "are referenced by")} {Item.Name}:", + new ItemResultsPanel(results, Log) { Dialog = this } + } + }; + } + + private List GetResults() + { + return new List(); //todo + } + + public enum ReferenceMode + { + REFERENCES_TO, + REFERENCED_BY + } + + } + +} diff --git a/src/SerialLoops/SearchDialog.cs b/src/SerialLoops/SearchDialog.cs new file mode 100644 index 00000000..862e2c24 --- /dev/null +++ b/src/SerialLoops/SearchDialog.cs @@ -0,0 +1,15 @@ +using System; +using Eto.Forms; +using Eto.Drawing; +using System.Collections.Generic; + +namespace SerialLoops +{ + public partial class SearchDialog : FindItemsDialog + { + public SearchDialog() + { + InitializeComponent(); + } + } +} diff --git a/src/SerialLoops/SearchDialog.eto.cs b/src/SerialLoops/SearchDialog.eto.cs new file mode 100644 index 00000000..ea2b5090 --- /dev/null +++ b/src/SerialLoops/SearchDialog.eto.cs @@ -0,0 +1,77 @@ +using Eto.Drawing; +using Eto.Forms; +using SerialLoops.Controls; +using SerialLoops.Lib; +using SerialLoops.Lib.Items; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace SerialLoops +{ + partial class SearchDialog : FindItemsDialog + { + + private ItemResultsPanel _results; + private TextBox _searchInput; + + void InitializeComponent() + { + Title = "Find in Project"; + MinimumSize = new Size(300, 200); + Padding = 10; + + _results = new(new List(), Log) + { + Dialog = this + }; + _searchInput = new() + { + PlaceholderText = "Search...", + Size = new Size(200, 25) + }; + _searchInput.TextChanged += SearchInput_OnTextChanged; + + Content = new StackLayout + { + Orientation = Orientation.Vertical, + HorizontalContentAlignment = HorizontalAlignment.Center, + Spacing = 10, + Padding = 10, + Items = + { + new GroupBox + { + Text = "Search", + Padding = 10, + Content = new StackLayout + { + Orientation = Orientation.Horizontal, + Spacing = 10, + Items = + { + "Find: ", + _searchInput + } + } + }, + _results + } + }; + } + + private void SearchInput_OnTextChanged(object sender, EventArgs e) + { + string searchTerm = _searchInput.Text; + if (!string.IsNullOrWhiteSpace(searchTerm)) + { + _results.Items = Project.Items.Where(item => item.Name.Contains(searchTerm.Trim(), StringComparison.OrdinalIgnoreCase)).ToList(); + } + else + { + _results.Items = Enumerable.Empty().ToList(); + } + } + + } +} diff --git a/src/SerialLoops/SerialLoops.csproj b/src/SerialLoops/SerialLoops.csproj index 92420f3d..36f008ac 100644 --- a/src/SerialLoops/SerialLoops.csproj +++ b/src/SerialLoops/SerialLoops.csproj @@ -46,6 +46,12 @@ + + $([System.String]::Copy('%(Filename)').Replace('.eto', ''))%(Extension) + + + $([System.String]::Copy('%(Filename)').Replace('.eto', ''))%(Extension) + ProjectCreationDialog.cs