From 169c6406137fb3121a36d2227d5fdfe889e80316 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 28 Sep 2010 15:29:32 +0200 Subject: [PATCH] Allow grouping search results by file. --- .../Project/Gui/DefaultSearchResult.cs | 63 ++++++++++++++++++- .../Project/Gui/ResultsTreeView.cs | 11 ++++ .../Project/Gui/SearchFileNode.cs | 35 +++++++++++ .../Project/Gui/SearchResultNode.cs | 6 +- .../Project/Gui/SearchRootNode.cs | 27 +++++--- .../Project/SearchAndReplace.csproj | 6 ++ 6 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchFileNode.cs diff --git a/src/AddIns/Misc/SearchAndReplace/Project/Gui/DefaultSearchResult.cs b/src/AddIns/Misc/SearchAndReplace/Project/Gui/DefaultSearchResult.cs index 741ffa0a53..8358c5b2a9 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/Gui/DefaultSearchResult.cs +++ b/src/AddIns/Misc/SearchAndReplace/Project/Gui/DefaultSearchResult.cs @@ -5,8 +5,11 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Windows; +using System.Windows.Controls; -using ICSharpCode.Core; +using ICSharpCode.Core.Presentation; +using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Editor.Search; using ICSharpCode.SharpDevelop.Gui; @@ -43,13 +46,69 @@ namespace SearchAndReplace WorkbenchSingleton.AssertMainThread(); if (resultsTreeViewInstance == null) resultsTreeViewInstance = new ResultsTreeView(); + rootNode.GroupResultsByFile(ResultsTreeView.GroupResultsByFile); resultsTreeViewInstance.ItemsSource = new object[] { rootNode }; return resultsTreeViewInstance; } + static IList toolbarItems; + static MenuItem flatItem, perFileItem; + public IList GetToolbarItems() { - return null; + WorkbenchSingleton.AssertMainThread(); + if (toolbarItems == null) { + toolbarItems = new List(); + DropDownButton perFileDropDown = new DropDownButton(); + perFileDropDown.Content = new Image { Height = 16, Source = PresentationResourceService.GetBitmapSource("Icons.16x16.FindIcon") }; + perFileDropDown.SetValueToExtension(DropDownButton.ToolTipProperty, new LocalizeExtension("MainWindow.Windows.SearchResultPanel.SelectViewMode.ToolTip")); + + flatItem = new MenuItem(); + flatItem.SetValueToExtension(MenuItem.HeaderProperty, new LocalizeExtension("MainWindow.Windows.SearchResultPanel.Flat")); + flatItem.Click += delegate { SetPerFile(false); }; + + perFileItem = new MenuItem(); + perFileItem.SetValueToExtension(MenuItem.HeaderProperty, new LocalizeExtension("MainWindow.Windows.SearchResultPanel.PerFile")); + perFileItem.Click += delegate { SetPerFile(true); }; + + perFileDropDown.DropDownMenu = new ContextMenu(); + perFileDropDown.DropDownMenu.Items.Add(flatItem); + perFileDropDown.DropDownMenu.Items.Add(perFileItem); + toolbarItems.Add(perFileDropDown); + toolbarItems.Add(new Separator()); + + Button expandAll = new Button(); + expandAll.SetValueToExtension(Button.ToolTipProperty, new LocalizeExtension("MainWindow.Windows.SearchResultPanel.ExpandAll.ToolTip")); + expandAll.Content = new Image { Height = 16, Source = PresentationResourceService.GetBitmapSource("Icons.16x16.OpenAssembly") }; + expandAll.Click += delegate { ExpandCollapseAll(true); }; + toolbarItems.Add(expandAll); + + Button collapseAll = new Button(); + collapseAll.SetValueToExtension(Button.ToolTipProperty, new LocalizeExtension("MainWindow.Windows.SearchResultPanel.CollapseAll.ToolTip")); + collapseAll.Content = new Image { Height = 16, Source = PresentationResourceService.GetBitmapSource("Icons.16x16.Assembly") }; + collapseAll.Click += delegate { ExpandCollapseAll(false); }; + toolbarItems.Add(collapseAll); + } + return toolbarItems; + } + + static void ExpandCollapseAll(bool newIsExpanded) + { + if (resultsTreeViewInstance != null) { + foreach (SearchNode node in resultsTreeViewInstance.ItemsSource.OfType().Flatten(n => n.Children)) { + node.IsExpanded = newIsExpanded; + } + } + } + + static void SetPerFile(bool perFile) + { + ResultsTreeView.GroupResultsByFile = perFile; + if (resultsTreeViewInstance != null) { + foreach (SearchRootNode node in resultsTreeViewInstance.ItemsSource.OfType()) { + node.GroupResultsByFile(perFile); + } + } } } diff --git a/src/AddIns/Misc/SearchAndReplace/Project/Gui/ResultsTreeView.cs b/src/AddIns/Misc/SearchAndReplace/Project/Gui/ResultsTreeView.cs index 5671a94da4..24162166f4 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/Gui/ResultsTreeView.cs +++ b/src/AddIns/Misc/SearchAndReplace/Project/Gui/ResultsTreeView.cs @@ -5,6 +5,8 @@ using System; using System.Windows.Controls; using System.Windows.Input; +using ICSharpCode.Core; + namespace SearchAndReplace { /// @@ -35,5 +37,14 @@ namespace SearchAndReplace node.ActivateItem(); e.Handled = true; } + + public static bool GroupResultsByFile { + get { + return PropertyService.Get("SearchAndReplace.GroupResultsByFile", false); + } + set { + PropertyService.Set("SearchAndReplace.GroupResultsByFile", value); + } + } } } diff --git a/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchFileNode.cs b/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchFileNode.cs new file mode 100644 index 0000000000..775e5f8d62 --- /dev/null +++ b/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchFileNode.cs @@ -0,0 +1,35 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.IO; +using System.Windows.Controls; +using System.Windows.Documents; + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Editor.Search; + +namespace SearchAndReplace +{ + class SearchFileNode : SearchNode + { + FileName fileName; + + public SearchFileNode(FileName fileName, SearchResultNode[] resultNodes) + { + this.fileName = fileName; + this.Children = resultNodes; + this.IsExpanded = true; + } + + protected override object CreateText() + { + return new TextBlock { + Inlines = { + new Bold(new Run(Path.GetFileName(fileName))), + new Run(StringParser.Parse(" (${res:MainWindow.Windows.SearchResultPanel.In} ") + Path.GetDirectoryName(fileName) + ")") + } + }; + } + } +} diff --git a/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchResultNode.cs b/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchResultNode.cs index 18f3ef82b3..db859762f8 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchResultNode.cs +++ b/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchResultNode.cs @@ -35,7 +35,7 @@ namespace SearchAndReplace var startPosition = result.GetStartPosition(document); int lineNumber = startPosition.Line; int column = startPosition.Column; - this.anchor = new PermanentAnchor(FileName.Create(result.FileName), lineNumber, column); + this.anchor = new PermanentAnchor(result.FileName, lineNumber, column); anchor.SurviveDeletion = true; if (lineNumber >= 1 && lineNumber <= document.TotalNumberOfLines) { @@ -82,6 +82,10 @@ namespace SearchAndReplace } } + public FileName FileName { + get { return anchor.FileName; } + } + protected override object CreateText() { var location = anchor.Location; diff --git a/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchRootNode.cs b/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchRootNode.cs index 97be4ead08..462a5c8620 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchRootNode.cs +++ b/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchRootNode.cs @@ -18,23 +18,34 @@ namespace SearchAndReplace { sealed class SearchRootNode : SearchNode { - IList results; - int fileCount; + IList resultNodes; + IList fileNodes; public string Title { get; private set; } public SearchRootNode(string title, IList results) { this.Title = title; - this.results = results.Select(r => new SearchResultNode(r)).ToArray(); + this.resultNodes = results.Select(r => new SearchResultNode(r)).ToArray(); + this.fileNodes = resultNodes.GroupBy(r => r.FileName).Select(g => new SearchFileNode(g.Key, g.ToArray())).ToArray(); - fileCount = results.GroupBy(r => r.FileName).Count(); - this.Children = this.results; + this.Children = this.resultNodes; this.IsExpanded = true; } + public void GroupResultsByFile(bool perFile) + { + if (perFile) + this.Children = fileNodes; + else + this.Children = resultNodes; + foreach (SearchResultNode node in resultNodes) { + node.ShowFileName = !perFile; + } + } + public int Occurrences { - get { return results.Count; } + get { return resultNodes.Count; } } protected override object CreateText() @@ -42,9 +53,9 @@ namespace SearchAndReplace return new TextBlock { Inlines = { new Bold(new Run(this.Title)), - new Run(" (" + GetOccurrencesString(results.Count) + new Run(" (" + GetOccurrencesString(resultNodes.Count) + StringParser.Parse(" ${res:MainWindow.Windows.SearchResultPanel.In} ") - + GetFileCountString(fileCount) + ")") + + GetFileCountString(fileNodes.Count) + ")") } }; } diff --git a/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj b/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj index 837045d92b..3cd78bcb56 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj +++ b/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj @@ -98,6 +98,7 @@ + @@ -131,6 +132,11 @@ ICSharpCode.Core False + + {7E4A7172-7FF5-48D0-B719-7CD959DD1AC9} + ICSharpCode.Core.Presentation + False + {857CA1A3-FC88-4BE0-AB6A-D1EE772AB288} ICSharpCode.Core.WinForms