From 2f4da263d83f9bf3f05e81ff18ca97084930b2ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Kon=C3=AD=C4=8Dek?= Date: Sat, 16 Jun 2018 20:27:11 +0200 Subject: [PATCH 1/6] Using builtin file & folder icons --- .../GitHub.VisualStudio.csproj | 8 +++ ...ectoryIsExpandedToImageMonikerConverter.cs | 20 ++++++ .../FileNameToImageMonikerConverter.cs | 71 +++++++++++++++++++ .../GitHubPane/PullRequestDetailView.xaml | 2 + .../GitHubPane/PullRequestFilesView.xaml | 31 +++----- src/GitHub.VisualStudio/packages.config | 2 + 6 files changed, 112 insertions(+), 22 deletions(-) create mode 100644 src/GitHub.VisualStudio/Views/GitHubPane/DirectoryIsExpandedToImageMonikerConverter.cs create mode 100644 src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs diff --git a/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj b/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj index a985af82ba..800e010dcd 100644 --- a/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj +++ b/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj @@ -141,6 +141,12 @@ ..\..\packages\Microsoft.VisualStudio.Editor.14.3.25407\lib\net45\Microsoft.VisualStudio.Editor.dll True + + ..\..\packages\Microsoft.VisualStudio.ImageCatalog.14.3.25407\lib\net45\Microsoft.VisualStudio.ImageCatalog.dll + + + ..\..\packages\Microsoft.VisualStudio.Imaging.14.3.25407\lib\net45\Microsoft.VisualStudio.Imaging.dll + True ..\..\packages\Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.14.3.25407\lib\Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.dll @@ -386,6 +392,8 @@ RepositoryRecloneView.xaml + + LoggedOutView.xaml diff --git a/src/GitHub.VisualStudio/Views/GitHubPane/DirectoryIsExpandedToImageMonikerConverter.cs b/src/GitHub.VisualStudio/Views/GitHubPane/DirectoryIsExpandedToImageMonikerConverter.cs new file mode 100644 index 0000000000..133ef421a9 --- /dev/null +++ b/src/GitHub.VisualStudio/Views/GitHubPane/DirectoryIsExpandedToImageMonikerConverter.cs @@ -0,0 +1,20 @@ +using System; +using System.Globalization; +using System.Windows.Data; +using Microsoft.VisualStudio.Imaging; + +namespace GitHub.VisualStudio.Views.GitHubPane +{ + internal sealed class DirectoryIsExpandedToImageMonikerConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return (bool)value ? KnownMonikers.FolderOpened : KnownMonikers.FolderClosed; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs b/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs new file mode 100644 index 0000000000..0d9689eb56 --- /dev/null +++ b/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs @@ -0,0 +1,71 @@ +using System; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Windows.Data; +using Microsoft.VisualStudio.Imaging; +using Microsoft.VisualStudio.Imaging.Interop; +using Microsoft.VisualStudio.Shell; + +namespace GitHub.VisualStudio.Views.GitHubPane +{ + internal sealed class FileNameToImageMonikerConverter : IValueConverter + { + private const string shellFileAssociations = "ShellFileAssociations"; + private const string defaultIconMoniker = "DefaultIconMoniker"; + private const string knownMonikersPrefix = "KnownMonikers."; + + private readonly Package package; + + public FileNameToImageMonikerConverter() + { + package = (Package)Services.GitHubServiceProvider.GetService(typeof(Package)); + } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return TryGetIcon((string)value) ?? KnownMonikers.Document; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + + private ImageMoniker? TryGetIcon(string fileName) + { + var extension = Path.GetExtension(fileName); + + if (string.IsNullOrEmpty(extension)) + return null; + + using (var key = package.ApplicationRegistryRoot.OpenSubKey(shellFileAssociations + "\\" + extension)) + { + if (key?.GetValue(defaultIconMoniker) is string str) + return TryParseImageMoniker(str); + } + + return null; + } + + private static ImageMoniker? TryParseImageMoniker(string str) + { + // This is the common case: KnownMonikers.Foo + + if (str.StartsWith(knownMonikersPrefix, StringComparison.Ordinal)) + { + var propertyName = str.Substring(knownMonikersPrefix.Length); + var property = typeof(KnownMonikers).GetProperty(propertyName, BindingFlags.Public | BindingFlags.Static); + + return property?.GetValue(null) as ImageMoniker?; + } + + // Custom icon - this will look like: cb4a8fc6-efe7-424a-b611-23adf22b568e:6 + + if (ImagingUtilities.TryParseImageMoniker(str, out var imageMoniker)) + return imageMoniker; + + return null; + } + } +} diff --git a/src/GitHub.VisualStudio/Views/GitHubPane/PullRequestDetailView.xaml b/src/GitHub.VisualStudio/Views/GitHubPane/PullRequestDetailView.xaml index 67f493c3a5..843158820d 100644 --- a/src/GitHub.VisualStudio/Views/GitHubPane/PullRequestDetailView.xaml +++ b/src/GitHub.VisualStudio/Views/GitHubPane/PullRequestDetailView.xaml @@ -8,8 +8,10 @@ xmlns:prop="clr-namespace:GitHub.VisualStudio.UI;assembly=GitHub.VisualStudio.UI" xmlns:markdig="clr-namespace:Markdig.Wpf;assembly=Markdig.Wpf" xmlns:vsui="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.14.0" + xmlns:theming="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Imaging" Background="{DynamicResource GitHubVsToolWindowBackground}" Foreground="{DynamicResource GitHubVsWindowText}" + theming:ImageThemingUtilities.ImageBackgroundColor="{Binding RelativeSource={RelativeSource Self}, Path=Background.Color}" DataContext="{Binding ViewModel}" d:DesignWidth="356" d:DesignHeight="800" diff --git a/src/GitHub.VisualStudio/Views/GitHubPane/PullRequestFilesView.xaml b/src/GitHub.VisualStudio/Views/GitHubPane/PullRequestFilesView.xaml index b344d21c01..0927db4184 100644 --- a/src/GitHub.VisualStudio/Views/GitHubPane/PullRequestFilesView.xaml +++ b/src/GitHub.VisualStudio/Views/GitHubPane/PullRequestFilesView.xaml @@ -4,7 +4,9 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:ghfvs="https://github.com/github/VisualStudio" + xmlns:local="clr-namespace:GitHub.VisualStudio.Views.GitHubPane" xmlns:prop="clr-namespace:GitHub.VisualStudio.UI;assembly=GitHub.VisualStudio.UI" + xmlns:imaging="clr-namespace:Microsoft.VisualStudio.Imaging;assembly=Microsoft.VisualStudio.Imaging" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Name="root"> @@ -47,10 +49,14 @@ + + + - + @@ -60,27 +66,8 @@ Tag="{Binding DataContext, ElementName=root}" KeyboardNavigation.DirectionalNavigation="None"> - - - - - - - + diff --git a/src/GitHub.VisualStudio/packages.config b/src/GitHub.VisualStudio/packages.config index dfdd36c63a..c5bc58b2e2 100644 --- a/src/GitHub.VisualStudio/packages.config +++ b/src/GitHub.VisualStudio/packages.config @@ -9,6 +9,8 @@ + + From 8cf9a268c497adb4fc0a14572253165e179dd11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Kon=C3=AD=C4=8Dek?= Date: Sun, 17 Jun 2018 12:28:28 +0200 Subject: [PATCH 2/6] Removing C# 7 language features --- .../Views/GitHubPane/FileNameToImageMonikerConverter.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs b/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs index 0d9689eb56..e0211f22cf 100644 --- a/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs +++ b/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs @@ -41,7 +41,8 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu using (var key = package.ApplicationRegistryRoot.OpenSubKey(shellFileAssociations + "\\" + extension)) { - if (key?.GetValue(defaultIconMoniker) is string str) + var str = key?.GetValue(defaultIconMoniker) as string; + if (str != null) return TryParseImageMoniker(str); } @@ -62,7 +63,8 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu // Custom icon - this will look like: cb4a8fc6-efe7-424a-b611-23adf22b568e:6 - if (ImagingUtilities.TryParseImageMoniker(str, out var imageMoniker)) + ImageMoniker imageMoniker; + if (ImagingUtilities.TryParseImageMoniker(str, out imageMoniker)) return imageMoniker; return null; From 054d10ce0004bcf1faf24e75e7619a39920bd449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Kon=C3=AD=C4=8Dek?= Date: Sun, 17 Jun 2018 12:45:21 +0200 Subject: [PATCH 3/6] Adding suppression for CA1812 --- .../GitHubPane/DirectoryIsExpandedToImageMonikerConverter.cs | 2 ++ .../Views/GitHubPane/FileNameToImageMonikerConverter.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/GitHub.VisualStudio/Views/GitHubPane/DirectoryIsExpandedToImageMonikerConverter.cs b/src/GitHub.VisualStudio/Views/GitHubPane/DirectoryIsExpandedToImageMonikerConverter.cs index 133ef421a9..e69f4c8568 100644 --- a/src/GitHub.VisualStudio/Views/GitHubPane/DirectoryIsExpandedToImageMonikerConverter.cs +++ b/src/GitHub.VisualStudio/Views/GitHubPane/DirectoryIsExpandedToImageMonikerConverter.cs @@ -1,10 +1,12 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Windows.Data; using Microsoft.VisualStudio.Imaging; namespace GitHub.VisualStudio.Views.GitHubPane { + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Used in XAML")] internal sealed class DirectoryIsExpandedToImageMonikerConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) diff --git a/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs b/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs index e0211f22cf..ae962b4b75 100644 --- a/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs +++ b/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Reflection; @@ -9,6 +10,7 @@ namespace GitHub.VisualStudio.Views.GitHubPane { + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Used in XAML")] internal sealed class FileNameToImageMonikerConverter : IValueConverter { private const string shellFileAssociations = "ShellFileAssociations"; From 49e46af2549b3cf224797e545523875d9ea404b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Kon=C3=AD=C4=8Dek?= Date: Sun, 17 Jun 2018 12:58:34 +0200 Subject: [PATCH 4/6] Using IVsImageService2.TryParseImageMoniker, which supports both formats From the doc: Parses a moniker string. The moniker can be of the form "{guid};id" or the name of a well-known moniker (e.g. "KnownMonikers.FolderClosed") --- .../FileNameToImageMonikerConverter.cs | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs b/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs index ae962b4b75..f98316b2b4 100644 --- a/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs +++ b/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs @@ -2,11 +2,11 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; -using System.Reflection; using System.Windows.Data; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; namespace GitHub.VisualStudio.Views.GitHubPane { @@ -15,13 +15,14 @@ internal sealed class FileNameToImageMonikerConverter : IValueConverter { private const string shellFileAssociations = "ShellFileAssociations"; private const string defaultIconMoniker = "DefaultIconMoniker"; - private const string knownMonikersPrefix = "KnownMonikers."; private readonly Package package; + private readonly IVsImageService2 imageService; public FileNameToImageMonikerConverter() { package = (Package)Services.GitHubServiceProvider.GetService(typeof(Package)); + imageService = (IVsImageService2)Package.GetGlobalService(typeof(SVsImageService)); } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) @@ -51,22 +52,10 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu return null; } - private static ImageMoniker? TryParseImageMoniker(string str) + private ImageMoniker? TryParseImageMoniker(string str) { - // This is the common case: KnownMonikers.Foo - - if (str.StartsWith(knownMonikersPrefix, StringComparison.Ordinal)) - { - var propertyName = str.Substring(knownMonikersPrefix.Length); - var property = typeof(KnownMonikers).GetProperty(propertyName, BindingFlags.Public | BindingFlags.Static); - - return property?.GetValue(null) as ImageMoniker?; - } - - // Custom icon - this will look like: cb4a8fc6-efe7-424a-b611-23adf22b568e:6 - ImageMoniker imageMoniker; - if (ImagingUtilities.TryParseImageMoniker(str, out imageMoniker)) + if (imageService.TryParseImageMoniker(str, out imageMoniker)) return imageMoniker; return null; From be54a160e4b5400ec377e27262e7687adf486090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Kon=C3=AD=C4=8Dek?= Date: Sun, 17 Jun 2018 13:14:16 +0200 Subject: [PATCH 5/6] Using IVsImageService2.GetImageMonikerForFile --- .../FileNameToImageMonikerConverter.cs | 36 +------------------ 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs b/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs index f98316b2b4..a598238d93 100644 --- a/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs +++ b/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs @@ -1,10 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.IO; using System.Windows.Data; -using Microsoft.VisualStudio.Imaging; -using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; @@ -13,52 +10,21 @@ namespace GitHub.VisualStudio.Views.GitHubPane [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Used in XAML")] internal sealed class FileNameToImageMonikerConverter : IValueConverter { - private const string shellFileAssociations = "ShellFileAssociations"; - private const string defaultIconMoniker = "DefaultIconMoniker"; - - private readonly Package package; private readonly IVsImageService2 imageService; public FileNameToImageMonikerConverter() { - package = (Package)Services.GitHubServiceProvider.GetService(typeof(Package)); imageService = (IVsImageService2)Package.GetGlobalService(typeof(SVsImageService)); } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return TryGetIcon((string)value) ?? KnownMonikers.Document; + return imageService.GetImageMonikerForFile((string)value); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } - - private ImageMoniker? TryGetIcon(string fileName) - { - var extension = Path.GetExtension(fileName); - - if (string.IsNullOrEmpty(extension)) - return null; - - using (var key = package.ApplicationRegistryRoot.OpenSubKey(shellFileAssociations + "\\" + extension)) - { - var str = key?.GetValue(defaultIconMoniker) as string; - if (str != null) - return TryParseImageMoniker(str); - } - - return null; - } - - private ImageMoniker? TryParseImageMoniker(string str) - { - ImageMoniker imageMoniker; - if (imageService.TryParseImageMoniker(str, out imageMoniker)) - return imageMoniker; - - return null; - } } } From b2945cb3952be224f5c04cbd3092b1dd9f57d4e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Kon=C3=AD=C4=8Dek?= Date: Mon, 18 Jun 2018 13:27:05 +0200 Subject: [PATCH 6/6] Fixing crash in WPF designer --- .../Views/GitHubPane/FileNameToImageMonikerConverter.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs b/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs index a598238d93..f89de42a53 100644 --- a/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs +++ b/src/GitHub.VisualStudio/Views/GitHubPane/FileNameToImageMonikerConverter.cs @@ -1,7 +1,10 @@ using System; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Windows; using System.Windows.Data; +using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; @@ -19,6 +22,10 @@ public FileNameToImageMonikerConverter() public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { + // In design mode, imageService will be null + if (DesignerProperties.GetIsInDesignMode(new DependencyObject())) + return default(ImageMoniker); + return imageService.GetImageMonikerForFile((string)value); }