Skip to content

Commit d5b8aa4

Browse files
authored
Merge pull request #1 from IvoKrugers/develop
Port from VS2019
2 parents 4c8ff2a + 3ad0e9e commit d5b8aa4

29 files changed

+2255
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,3 +348,4 @@ MigrationBackup/
348348

349349
# Ionide (cross platform F# VS Code tools) working folder
350350
.ionide/
351+
.extensionsettings/SolutionTreeFilter.json
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.810.21
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualStudioMac.SolutionTreeFilter", "VisualStudioMac.SolutionTreeFilter\VisualStudioMac.SolutionTreeFilter.csproj", "{FE30B344-6910-4F82-ABDE-52217485EBE3}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{FE30B344-6910-4F82-ABDE-52217485EBE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{FE30B344-6910-4F82-ABDE-52217485EBE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{FE30B344-6910-4F82-ABDE-52217485EBE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{FE30B344-6910-4F82-ABDE-52217485EBE3}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {FB0373DF-9E5B-4DEF-A926-AC825FF19148}
24+
EndGlobalSection
25+
EndGlobal
Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Linq;
5+
using MonoDevelop.Core;
6+
using MonoDevelop.Ide.Gui.Pads.ProjectPad;
7+
using MonoDevelop.Projects;
8+
using VisualStudioMac.SolutionTreeFilter.Helpers;
9+
using VisualStudioMac.SolutionTreeFilter.Helpers.ExtensionSettings;
10+
11+
namespace VisualStudioMac.SolutionTreeFilter.Cache
12+
{
13+
public static class FilteredProjectCache
14+
{
15+
struct TreeItem
16+
{
17+
public FilePath ProjectVirtualPath;
18+
public bool IsExpanded;
19+
public bool IsEnabled;
20+
}
21+
22+
private static Dictionary<string, DateTime> _projectsDictionary = new Dictionary<string, DateTime>();
23+
private static Dictionary<string, TreeItem> _treeDictionary = new Dictionary<string, TreeItem>();
24+
25+
private static string _lastFilter = string.Empty;
26+
27+
public static void ScanProjectForFiles(Project project)
28+
{
29+
lock (_projectsDictionary)
30+
{
31+
var filter = FilterSettings.SolutionFilter;
32+
33+
// check if cache is still current according to filter used
34+
if (_lastFilter != filter)
35+
{
36+
_projectsDictionary.Clear();
37+
_treeDictionary.Clear();
38+
_lastFilter = filter;
39+
}
40+
41+
// check if cache is still current
42+
DateTime lastDate;
43+
if (_projectsDictionary.TryGetValue(project.Name, out lastDate))
44+
{
45+
var d = DateTime.Now - lastDate;
46+
if (d.TotalSeconds < 60)
47+
return;
48+
}
49+
_projectsDictionary[project.Name] = DateTime.Now;
50+
var filterArray = FilterSettings.SolutionFilterArray;
51+
var pinnedDocuments = FilterSettings.PinnedDocuments;
52+
53+
// clear all entries related to project.
54+
ClearCacheOfProject(project);
55+
56+
// Look for files that are in this project and comply with the filter. Add them to dictionary
57+
foreach (var file in project.Files)
58+
{
59+
FilePath path;
60+
61+
//If the file is pinned in the Workbench, add it to the cache.
62+
if (filterArray.Count() > 0 && pinnedDocuments.Contains(file.FilePath))
63+
RegisterFile(project.Name, file.ProjectVirtualPath.FileName, file.ProjectVirtualPath.ParentDirectory, true, filterArray, true);
64+
65+
if (!file.Visible || file.Flags.HasFlag(ProjectItemFlags.Hidden) || file.Subtype == Subtype.Directory)
66+
continue;
67+
68+
path = file.IsLink ? project.BaseDirectory.Combine(file.ProjectVirtualPath) : file.FilePath;
69+
70+
if (filterArray.Length > 0)
71+
{
72+
foreach (var key in filterArray)
73+
{
74+
75+
if (file.ProjectVirtualPath.ToString().ToLower().Contains(key))
76+
{
77+
#if DEBUG
78+
if (file.FilePath.FileName == "StageProgressBar.designer.cs")
79+
{
80+
Debug.WriteLine("BINGO !!");
81+
}
82+
#endif
83+
84+
85+
// if this file depends on another, make sure that that parent file in the cache is marked as expanded too.
86+
87+
88+
// Found file or folder that fits the filter
89+
var filenameInFilter = false;
90+
var filenameToTest = file.FilePath.FileName.ToLower();
91+
foreach (var key1 in filterArray)
92+
{
93+
if (filenameToTest.Contains(key1))
94+
{
95+
filenameInFilter = true;
96+
break;
97+
}
98+
}
99+
100+
var filename = file.ProjectVirtualPath.FileName;
101+
var folder = file.ProjectVirtualPath.ParentDirectory;
102+
RegisterFile(project.Name, filename, folder, filenameInFilter, filterArray);
103+
104+
break;
105+
}
106+
}
107+
}
108+
}
109+
}
110+
Debug.WriteLine(ToString());
111+
}
112+
113+
private static void ClearCacheOfProject(Project project)
114+
{
115+
foreach (var s in _treeDictionary.Where(item => item.Key.StartsWith(project.Name)).ToList())
116+
{
117+
_treeDictionary.Remove(s.Key);
118+
}
119+
}
120+
121+
/// <summary>
122+
/// Recursive routine which registers an entry for each folder in the file's path
123+
/// </summary>
124+
private static void RegisterFile(string projectname, string filename, FilePath folder, bool filenameInFilter, string[] filter, bool isPinnedDoc = false)
125+
{
126+
RegisterFileForFolder(projectname, filename, folder, filenameInFilter, filter);
127+
128+
// Register file
129+
var foldername = projectname + "/" + folder.ToString() + "/" + filename;
130+
foldername = foldername.Replace("//", "/");
131+
TreeItem item;
132+
if (!_treeDictionary.TryGetValue(foldername, out item))
133+
item = new TreeItem { ProjectVirtualPath = folder };
134+
135+
item.IsExpanded = item.IsExpanded || filenameInFilter;
136+
item.IsEnabled = item.IsEnabled || filenameInFilter;
137+
_treeDictionary[foldername] = item;
138+
}
139+
140+
/// <summary>
141+
/// Recursive routine which registers an entry for each folder in the file's path
142+
/// </summary>
143+
private static string RegisterFileForFolder(string projectname, string filename, FilePath folder, bool filenameInFilter, string[] filter)
144+
{
145+
if (folder == null || folder.IsEmpty)
146+
return projectname;
147+
148+
// Enter recursion
149+
var foldername = RegisterFileForFolder(projectname, filename, folder.ParentDirectory, filenameInFilter, filter) + $"/" + folder.FileName;
150+
foldername = foldername.Replace("//", "/");
151+
// Register file in dictionary
152+
TreeItem item;
153+
if (!_treeDictionary.TryGetValue(foldername, out item))
154+
item = new TreeItem { ProjectVirtualPath = folder };
155+
item.IsExpanded = item.IsExpanded || filenameInFilter || IsFilePathExpanded(folder, filter);
156+
item.IsEnabled = true;
157+
_treeDictionary[foldername] = item;
158+
159+
return foldername;
160+
}
161+
162+
private static bool IsFilePathExpanded(FilePath folder, string[] filter)
163+
{
164+
foreach (var key in filter)
165+
{
166+
if (folder.FileName.ToLower().Contains(key))
167+
return true;
168+
}
169+
return false;
170+
}
171+
172+
private static string GetFoldername(ProjectFolder folder)
173+
{
174+
var parent = folder.Parent;
175+
if (parent is Project project)
176+
return project.Name + "/" + folder.Name;
177+
178+
// Enter recursion
179+
return GetFoldername(parent as ProjectFolder) + $"/" + folder.Name;
180+
}
181+
182+
private static string GetKeyFor(object dataObject)
183+
{
184+
string key;
185+
switch (dataObject)
186+
{
187+
case ProjectFile file:
188+
key = file.Project.Name + "/" + file.ProjectVirtualPath.ToString();
189+
break;
190+
case ProjectFolder folder:
191+
key = GetFoldername(folder);
192+
break;
193+
case Project project:
194+
key = project.Name;
195+
break;
196+
default:
197+
key = string.Empty;
198+
break;
199+
}
200+
key = key.Replace("//", "/");
201+
return key;
202+
}
203+
204+
public static bool IsProjectItemVisible(object dataItem)
205+
{
206+
if (dataItem is ProjectFile || dataItem is ProjectFolder)
207+
{
208+
var key = GetKeyFor(dataItem);
209+
return _treeDictionary.TryGetValue(key, out _);
210+
}
211+
else if (dataItem is Project project)
212+
{
213+
return _treeDictionary.Keys.FindIndex((key) => key.Contains(project.Name)) != -1;
214+
}
215+
return false;
216+
}
217+
218+
public static bool IsProjectItemEnabled(object dataItem)
219+
{
220+
if (dataItem is ProjectFile || dataItem is ProjectFolder)
221+
{
222+
var key = GetKeyFor(dataItem);
223+
TreeItem item;
224+
if (!_treeDictionary.TryGetValue(key, out item))
225+
return false;
226+
return item.IsEnabled;
227+
}
228+
else if (dataItem is Project project)
229+
{
230+
return true;
231+
}
232+
return false;
233+
}
234+
235+
public static bool IsProjectItemExpanded(object dataItem)
236+
{
237+
if (dataItem is ProjectFile || dataItem is ProjectFolder)
238+
{
239+
var key = GetKeyFor(dataItem);
240+
TreeItem item;
241+
242+
if (dataItem is ProjectFile pf && pf.DependentChildren.Where(f => f.FilePath.FileName.EndsWith(".designer.cs")).Any())
243+
return false;
244+
245+
var found = _treeDictionary.TryGetValue(key, out item);
246+
return found && item.IsExpanded;
247+
}
248+
else if (dataItem is Project project)
249+
{
250+
return _treeDictionary.Keys.FindIndex((key) => key.Contains(project.Name)) != -1;
251+
}
252+
return false;
253+
}
254+
255+
public static new string ToString()
256+
{
257+
var str = "";
258+
var maxLength = 0;
259+
260+
foreach (var item in _treeDictionary)
261+
{
262+
if (item.Key.Length > maxLength)
263+
maxLength = item.Key.Length;
264+
}
265+
maxLength += 1;
266+
267+
str += $"\n{{FilteredProjectCache - TreeDictionary}}\n";
268+
foreach (var item in _treeDictionary)
269+
{
270+
str += $"\t- {item.Key.PadRight(maxLength, '.')}\t=> IsExpanded: {item.Value.IsExpanded}\t=> IsEnabled: {item.Value.IsEnabled}\n";
271+
}
272+
return str;
273+
}
274+
}
275+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using MonoDevelop.Components.Commands;
2+
using MonoDevelop.Ide;
3+
using MonoDevelop.Ide.Gui.Pads;
4+
using MonoDevelop.Projects;
5+
using VisualStudioMac.SolutionTreeFilter.Gui;
6+
using VisualStudioMac.SolutionTreeFilter.Helpers;
7+
using VisualStudioMac.SolutionTreeFilter.Helpers.ExtensionSettings;
8+
9+
namespace VisualStudioMac.SolutionTreeFilter.CommandHandlers.Editor
10+
{
11+
public class PinCommandHandler : CommandHandler
12+
{
13+
protected override void Update(CommandInfo info)
14+
{
15+
base.Update(info);
16+
info.Enabled = false;
17+
if (IdeApp.Workbench.ActiveDocument != null && IdeApp.Workbench.ActiveDocument.IsFile)
18+
{
19+
info.Enabled = true;
20+
var isPinned = FilterSettings.IsPinned(IdeApp.Workbench.ActiveDocument);
21+
info.Text = isPinned ? "Unpin from Solution Tree" : "Pin on Solution Tree";
22+
}
23+
}
24+
25+
protected override void Run()
26+
{
27+
if (IdeApp.Workbench.ActiveDocument != null && IdeApp.Workbench.ActiveDocument.IsFile)
28+
{
29+
var isPinned = FilterSettings.IsPinned(IdeApp.Workbench.ActiveDocument);
30+
if (isPinned)
31+
FilterSettings.RemovePinnedDocument(IdeApp.Workbench.ActiveDocument);
32+
else
33+
FilterSettings.AddPinnedDocument(IdeApp.Workbench.ActiveDocument);
34+
35+
var pad = (SolutionPad)IdeApp.Workbench.Pads.SolutionPad.Content;
36+
if (pad == null)
37+
return;
38+
39+
var node = pad.Controller.GetSelectedNode();
40+
if (node != null && node.DataItem is ProjectFile projectfile)
41+
{
42+
if (projectfile.FilePath.FullPath == IdeApp.Workbench.ActiveDocument.FilePath.FullPath)
43+
{
44+
pad.RefreshSelectedNode();
45+
}
46+
}
47+
else
48+
{
49+
var SolutionPad = (FilterPad)IdeApp.Workbench.GetPad<FilterPad>().Content;
50+
if (SolutionPad != null)
51+
{
52+
((FilterPadWidget)SolutionPad.Control).FilterSolutionPad();
53+
}
54+
}
55+
}
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)