diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt
index 9e605257ca..2ddc4a8242 100644
--- a/.github/actions/spell-check/expect.txt
+++ b/.github/actions/spell-check/expect.txt
@@ -1527,6 +1527,7 @@ PCWSTR
pdb
pdbonly
pdf
+pdfpreviewhandler
pdo
pdto
pdtobj
diff --git a/.pipelines/ci/templates/build-powertoys-steps.yml b/.pipelines/ci/templates/build-powertoys-steps.yml
index 80fc0383d3..1da8d83229 100644
--- a/.pipelines/ci/templates/build-powertoys-steps.yml
+++ b/.pipelines/ci/templates/build-powertoys-steps.yml
@@ -122,6 +122,8 @@ steps:
testAssemblyVer2: |
**\UnitTests-SvgThumbnailProvider.dll
**\Microsoft.PowerToys.Settings.UI.UnitTests.dll
+ **\UnitTests-MarkdownPreviewHandler.dll
+ **\UnitTests-PdfPreviewHandler.dll
**\UnitTests-SvgPreviewHandler.dll
**\UnitTests-PreviewHandlerCommon.dll
**\PreviewPaneUnitTests.dll
diff --git a/.pipelines/pipeline.user.windows.yml b/.pipelines/pipeline.user.windows.yml
index fdaea129f6..9fe3f92fbc 100644
--- a/.pipelines/pipeline.user.windows.yml
+++ b/.pipelines/pipeline.user.windows.yml
@@ -108,6 +108,8 @@ build:
- 'modules\FileExplorerPreview\ManagedTelemetry.dll'
- 'modules\FileExplorerPreview\MarkdownPreviewHandler.dll'
- 'modules\FileExplorerPreview\MarkdownPreviewHandler.comhost.dll'
+ - 'modules\FileExplorerPreview\PdfPreviewHandler.dll'
+ - 'modules\FileExplorerPreview\PdfPreviewHandler.comhost.dll'
- 'modules\FileExplorerPreview\powerpreview.dll'
- 'modules\FileExplorerPreview\PreviewHandlerCommon.dll'
- 'modules\FileExplorerPreview\SvgPreviewHandler.dll'
diff --git a/PowerToys.sln b/PowerToys.sln
index 4d0c415207..d58e52fadd 100644
--- a/PowerToys.sln
+++ b/PowerToys.sln
@@ -166,7 +166,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PreviewHandlerCommon", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MarkdownPreviewHandler", "src\modules\previewpane\MarkdownPreviewHandler\MarkdownPreviewHandler.csproj", "{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-MarkdownPreviewHandler", "src\modules\previewpane\PreviewPaneUnitTests\UnitTests-MarkdownPreviewHandler.csproj", "{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-MarkdownPreviewHandler", "src\modules\previewpane\UnitTests-MarkdownPreviewHandler\UnitTests-MarkdownPreviewHandler.csproj", "{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SvgPreviewHandler", "src\modules\previewpane\SvgPreviewHandler\SvgPreviewHandler.csproj", "{DA425894-6E13-404F-8DCB-78584EC0557A}"
EndProject
@@ -305,6 +305,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Telemetry", "Telemetry", "{
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Common.UI", "src\common\Microsoft.PowerToys.Common.UI\Microsoft.PowerToys.Common.UI.csproj", "{C3A17DCA-217B-462C-BB0C-BE086AF80081}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfPreviewHandler", "src\modules\previewpane\PdfPreviewHandler\PdfPreviewHandler.csproj", "{69E1EE8D-143A-4060-9129-4658ACF14AAF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-PdfPreviewHandler", "src\modules\previewpane\UnitTests-PdfPreviewHandler\UnitTests-PdfPreviewHandler.csproj", "{ECC20689-002A-4354-95A6-B58DF089C6FF}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.Registry", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\Microsoft.PowerToys.Run.Plugin.Registry.csproj", "{4BABF3FE-3451-42FD-873F-3C332E18DCEF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.Registry.UnitTests", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry.UnitTest\Microsoft.PowerToys.Run.Plugin.Registry.UnitTests.csproj", "{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}"
@@ -796,6 +800,18 @@ Global
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x64.ActiveCfg = Release|x64
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x64.Build.0 = Release|x64
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x86.ActiveCfg = Release|x64
+ {69E1EE8D-143A-4060-9129-4658ACF14AAF}.Debug|x64.ActiveCfg = Debug|x64
+ {69E1EE8D-143A-4060-9129-4658ACF14AAF}.Debug|x64.Build.0 = Debug|x64
+ {69E1EE8D-143A-4060-9129-4658ACF14AAF}.Debug|x86.ActiveCfg = Debug|x64
+ {69E1EE8D-143A-4060-9129-4658ACF14AAF}.Release|x64.ActiveCfg = Release|x64
+ {69E1EE8D-143A-4060-9129-4658ACF14AAF}.Release|x64.Build.0 = Release|x64
+ {69E1EE8D-143A-4060-9129-4658ACF14AAF}.Release|x86.ActiveCfg = Release|x64
+ {ECC20689-002A-4354-95A6-B58DF089C6FF}.Debug|x64.ActiveCfg = Debug|x64
+ {ECC20689-002A-4354-95A6-B58DF089C6FF}.Debug|x64.Build.0 = Debug|x64
+ {ECC20689-002A-4354-95A6-B58DF089C6FF}.Debug|x86.ActiveCfg = Debug|x64
+ {ECC20689-002A-4354-95A6-B58DF089C6FF}.Release|x64.ActiveCfg = Release|x64
+ {ECC20689-002A-4354-95A6-B58DF089C6FF}.Release|x64.Build.0 = Release|x64
+ {ECC20689-002A-4354-95A6-B58DF089C6FF}.Release|x86.ActiveCfg = Release|x64
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x64.ActiveCfg = Debug|x64
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x64.Build.0 = Debug|x64
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x86.ActiveCfg = Debug|x64
@@ -1019,6 +1035,8 @@ Global
{B39DC643-4663-475E-B329-03F0C9918D48} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{8F62026A-294B-41C6-8839-87463613F216} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{C3A17DCA-217B-462C-BB0C-BE086AF80081} = {1AFB6476-670D-4E80-A464-657E01DFF482}
+ {69E1EE8D-143A-4060-9129-4658ACF14AAF} = {2F305555-C296-497E-AC20-5FA1B237996A}
+ {ECC20689-002A-4354-95A6-B58DF089C6FF} = {2F305555-C296-497E-AC20-5FA1B237996A}
{4BABF3FE-3451-42FD-873F-3C332E18DCEF} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
diff --git a/installer/MSIX/appxmanifest.xml b/installer/MSIX/appxmanifest.xml
index a57983a327..90c4d6b381 100644
--- a/installer/MSIX/appxmanifest.xml
+++ b/installer/MSIX/appxmanifest.xml
@@ -79,11 +79,20 @@
+
+
+
+ .pdf
+
+
+
+
+
diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs
index 1810508c85..e52b052521 100644
--- a/installer/PowerToysSetup/Product.wxs
+++ b/installer/PowerToysSetup/Product.wxs
@@ -239,7 +239,6 @@
-
@@ -499,6 +498,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -511,6 +523,10 @@
+
+
+
+
@@ -523,6 +539,10 @@
+
+
+
+
@@ -784,6 +804,11 @@
+
+
+
+
+
@@ -1022,7 +1047,10 @@
-
+
+
+
+
diff --git a/src/modules/previewpane/PdfPreviewHandler/LocProject.json b/src/modules/previewpane/PdfPreviewHandler/LocProject.json
new file mode 100644
index 0000000000..b9ffe307fa
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandler/LocProject.json
@@ -0,0 +1,14 @@
+{
+ "Projects": [
+ {
+ "LanguageSet": "Azure_Languages",
+ "LocItems": [
+ {
+ "SourceFile": "src\\modules\\previewpane\\PdfPreviewHandler\\Properties\\Resources.resx",
+ "CopyOption": "LangIDOnName",
+ "OutputPath": "src\\modules\\previewpane\\PdfPreviewHandler\\Properties"
+ }
+ ]
+ }
+ ]
+}
diff --git a/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.cs b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.cs
new file mode 100644
index 0000000000..2f4d962287
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.cs
@@ -0,0 +1,73 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using Common;
+using Microsoft.PowerToys.Telemetry;
+
+namespace Microsoft.PowerToys.PreviewHandler.Pdf
+{
+ ///
+ /// Implementation of preview handler for pdf files.
+ ///
+ [Guid("07665729-6243-4746-95b7-79579308d1b2")]
+ [ClassInterface(ClassInterfaceType.None)]
+ [ComVisible(true)]
+ public class PdfPreviewHandler : StreamBasedPreviewHandler, IDisposable
+ {
+ private PdfPreviewHandlerControl _pdfPreviewHandlerControl;
+ private bool _disposedValue;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PdfPreviewHandler()
+ {
+ Initialize();
+ }
+
+ ///
+ public override void DoPreview()
+ {
+ _pdfPreviewHandlerControl.DoPreview(Stream);
+ }
+
+ ///
+ protected override IPreviewHandlerControl CreatePreviewHandlerControl()
+ {
+ PowerToysTelemetry.Log.WriteEvent(new Telemetry.Events.PdfFileHandlerLoaded());
+ _pdfPreviewHandlerControl = new PdfPreviewHandlerControl();
+
+ return _pdfPreviewHandlerControl;
+ }
+
+ ///
+ /// Disposes objects
+ ///
+ /// Is Disposing
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposedValue)
+ {
+ if (disposing)
+ {
+ _pdfPreviewHandlerControl.Dispose();
+ }
+
+ // TODO: free unmanaged resources (unmanaged objects) and override finalizer
+ // TODO: set large fields to null
+ _disposedValue = true;
+ }
+ }
+
+ ///
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+ }
+}
diff --git a/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj
new file mode 100644
index 0000000000..a49bb3b7b3
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj
@@ -0,0 +1,72 @@
+
+
+ x64
+ true
+ PdfPreviewHandler
+ PowerToys PdfPreviewHandler
+ Microsoft Corp.
+ Copyright (C) 2020 Microsoft Corporation
+ PowerToys
+ PdfPreviewHandler
+ Microsoft Corp.
+ PowerToys
+ en-US
+ PowerToys PdfPreviewHandler
+ Copyright (C) 2020 Microsoft Corporation
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\PdfPreviewPaneDocumentation.xml
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\
+ false
+ false
+ true
+
+
+
+ {69E1EE8D-143A-4060-9129-4658ACF14AAF}
+ Microsoft.PowerToys.PreviewHandler.Pdf
+ netcoreapp3.1
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\obj\$(AssemblyName)\
+
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+ all
+
+
+ all
+
+
+
+
+
+
+
+ StyleCop.json
+
+
+
+
+
+
+
+
+
+
+ $(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.17134.0\Windows.winmd
+ true
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandlerControl.cs b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandlerControl.cs
new file mode 100644
index 0000000000..8e17d9811b
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandlerControl.cs
@@ -0,0 +1,299 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+using System;
+using System.Drawing;
+using System.IO;
+using System.Runtime.InteropServices.ComTypes;
+using System.Windows.Forms;
+
+using Common;
+using Common.Utilities;
+using Microsoft.PowerToys.PreviewHandler.Pdf.Properties;
+using Microsoft.PowerToys.PreviewHandler.Pdf.Telemetry.Events;
+using Microsoft.PowerToys.Telemetry;
+using Windows.Data.Pdf;
+using Windows.Storage.Streams;
+using Windows.UI.ViewManagement;
+
+namespace Microsoft.PowerToys.PreviewHandler.Pdf
+{
+ ///
+ /// Win Form Implementation for Pdf Preview Handler.
+ ///
+ public class PdfPreviewHandlerControl : FormHandlerControl
+ {
+ ///
+ /// RichTextBox control to display error message.
+ ///
+ private RichTextBox _infoBar;
+
+ ///
+ /// FlowLayoutPanel control to display the image of the pdf.
+ ///
+ private FlowLayoutPanel _flowLayoutPanel;
+
+ ///
+ /// Use UISettings to get system colors and scroll bar size.
+ ///
+ private static UISettings _uISettings = new UISettings();
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PdfPreviewHandlerControl()
+ {
+ SetBackgroundColor(GetBackgroundColor());
+ }
+
+ ///
+ /// Start the preview on the Control.
+ ///
+ /// Stream reference to access source file.
+ public override void DoPreview(T dataSource)
+ {
+ this.SuspendLayout();
+
+ try
+ {
+ using (var dataStream = new ReadonlyStream(dataSource as IStream))
+ {
+ var memStream = new MemoryStream();
+ dataStream.CopyTo(memStream);
+ memStream.Position = 0;
+
+ try
+ {
+ // AsRandomAccessStream() extension method from System.Runtime.WindowsRuntime
+ var pdf = PdfDocument.LoadFromStreamAsync(memStream.AsRandomAccessStream()).GetAwaiter().GetResult();
+
+ if (pdf.PageCount > 0)
+ {
+ InvokeOnControlThread(() =>
+ {
+ _flowLayoutPanel = new FlowLayoutPanel
+ {
+ AutoScroll = true,
+ AutoSize = true,
+ Dock = DockStyle.Fill,
+ FlowDirection = FlowDirection.TopDown,
+ WrapContents = false,
+ };
+ _flowLayoutPanel.Resize += FlowLayoutPanel_Resize;
+
+ // Only show first 10 pages.
+ for (uint i = 0; i < pdf.PageCount && i < 10; i++)
+ {
+ using (var page = pdf.GetPage(i))
+ {
+ var image = PageToImage(page);
+
+ var picturePanel = new Panel()
+ {
+ Name = "picturePanel",
+ Margin = new Padding(6, 6, 6, 0),
+ Size = CalculateSize(image),
+ BorderStyle = BorderStyle.FixedSingle,
+ };
+
+ var picture = new PictureBox
+ {
+ Dock = DockStyle.Fill,
+ Image = image,
+ SizeMode = PictureBoxSizeMode.Zoom,
+ };
+
+ picturePanel.Controls.Add(picture);
+ _flowLayoutPanel.Controls.Add(picturePanel);
+ }
+ }
+
+ if (pdf.PageCount > 10)
+ {
+ var messageBox = new RichTextBox
+ {
+ Name = "messageBox",
+ Text = Resources.PdfMorePagesMessage,
+ BackColor = Color.LightYellow,
+ Dock = DockStyle.Fill,
+ Multiline = true,
+ ReadOnly = true,
+ ScrollBars = RichTextBoxScrollBars.None,
+ BorderStyle = BorderStyle.None,
+ };
+ messageBox.ContentsResized += RTBContentsResized;
+
+ _flowLayoutPanel.Controls.Add(messageBox);
+ }
+
+ Controls.Add(_flowLayoutPanel);
+ });
+ }
+ }
+#pragma warning disable CA1031 // Password protected files throws an generic Exception
+ catch (Exception ex)
+#pragma warning restore CA1031
+ {
+ if (ex.Message.Contains("Unable to update the password. The value provided as the current password is incorrect.", StringComparison.Ordinal))
+ {
+ InvokeOnControlThread(() =>
+ {
+ Controls.Clear();
+ _infoBar = GetTextBoxControl(Resources.PdfPasswordProtectedError);
+ Controls.Add(_infoBar);
+ });
+ }
+ else
+ {
+ throw;
+ }
+ }
+ finally
+ {
+ memStream.Dispose();
+ }
+ }
+
+ PowerToysTelemetry.Log.WriteEvent(new PdfFilePreviewed());
+ }
+#pragma warning disable CA1031 // Do not catch general exception types
+ catch (Exception ex)
+#pragma warning restore CA1031 // Do not catch general exception types
+ {
+ PowerToysTelemetry.Log.WriteEvent(new PdfFilePreviewError { Message = ex.Message });
+
+ InvokeOnControlThread(() =>
+ {
+ Controls.Clear();
+ _infoBar = GetTextBoxControl(Resources.PdfNotPreviewedError);
+ Controls.Add(_infoBar);
+ });
+ }
+ finally
+ {
+ base.DoPreview(dataSource);
+ }
+
+ this.ResumeLayout(false);
+ this.PerformLayout();
+ }
+
+ ///
+ /// Resize the Panels on FlowLayoutPanel resize based on the size of the image.
+ ///
+ /// sender (not used)
+ /// args (not used)
+ private void FlowLayoutPanel_Resize(object sender, EventArgs e)
+ {
+ this.SuspendLayout();
+ _flowLayoutPanel.SuspendLayout();
+
+ foreach (Panel panel in _flowLayoutPanel.Controls.Find("picturePanel", false))
+ {
+ var pictureBox = panel.Controls[0] as PictureBox;
+ var image = pictureBox.Image;
+
+ panel.Size = CalculateSize(image);
+ }
+
+ _flowLayoutPanel.ResumeLayout(false);
+ this.ResumeLayout(false);
+ }
+
+ ///
+ /// Transform the PdfPage to an Image.
+ ///
+ /// The page to transform to an Image.
+ /// An object of type
+ private Image PageToImage(PdfPage page)
+ {
+ Image imageOfPage;
+
+ using (var stream = new InMemoryRandomAccessStream())
+ {
+ page.RenderToStreamAsync(stream, new PdfPageRenderOptions()
+ {
+ DestinationWidth = (uint)this.ClientSize.Width,
+ }).GetAwaiter().GetResult();
+
+ imageOfPage = Image.FromStream(stream.AsStream());
+ }
+
+ return imageOfPage;
+ }
+
+ ///
+ /// Calculate the size of the control based on the size of the image/pdf page.
+ ///
+ /// Image of pdf page.
+ /// New size off the panel.
+ private Size CalculateSize(Image pdfImage)
+ {
+ var hasScrollBar = _flowLayoutPanel.VerticalScroll.Visible;
+
+ // Add 12px margin to the image by making it 12px smaller.
+ int width = this.ClientSize.Width - 12;
+
+ // If the vertical scroll bar is visible, make the image smaller.
+ var scrollBarSizeWidth = (int)_uISettings.ScrollBarSize.Width;
+ if (hasScrollBar && width > scrollBarSizeWidth)
+ {
+ width -= scrollBarSizeWidth;
+ }
+
+ int originalWidth = pdfImage.Width;
+ int originalHeight = pdfImage.Height;
+ float percentWidth = (float)width / originalWidth;
+
+ int newHeight = (int)(originalHeight * percentWidth);
+
+ return new Size(width, newHeight);
+ }
+
+ ///
+ /// Get the system background color, based on the selected theme.
+ ///
+ /// An object of type .
+ private static Color GetBackgroundColor()
+ {
+ var systemBackgroundColor = _uISettings.GetColorValue(UIColorType.Background);
+
+ return Color.FromArgb(systemBackgroundColor.A, systemBackgroundColor.R, systemBackgroundColor.G, systemBackgroundColor.B);
+ }
+
+ ///
+ /// Gets a textbox control.
+ ///
+ /// Message to be displayed in textbox.
+ /// An object of type .
+ private RichTextBox GetTextBoxControl(string message)
+ {
+ var textBox = new RichTextBox
+ {
+ Text = message,
+ BackColor = Color.LightYellow,
+ Multiline = true,
+ Dock = DockStyle.Top,
+ ReadOnly = true,
+ ScrollBars = RichTextBoxScrollBars.None,
+ BorderStyle = BorderStyle.None,
+ };
+ textBox.ContentsResized += RTBContentsResized;
+
+ return textBox;
+ }
+
+ ///
+ /// Callback when RichTextBox is resized.
+ ///
+ /// Reference to resized control.
+ /// Provides data for the resize event.
+ private void RTBContentsResized(object sender, ContentsResizedEventArgs e)
+ {
+ var richTextBox = (RichTextBox)sender;
+
+ // Add 5px extra height to the textbox.
+ richTextBox.Height = e.NewRectangle.Height + 5;
+ }
+ }
+}
diff --git a/src/modules/previewpane/PdfPreviewHandler/Properties/Resources.Designer.cs b/src/modules/previewpane/PdfPreviewHandler/Properties/Resources.Designer.cs
new file mode 100644
index 0000000000..f8531f334e
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandler/Properties/Resources.Designer.cs
@@ -0,0 +1,104 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Microsoft.PowerToys.PreviewHandler.Pdf.Properties
+{
+ using System;
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources()
+ {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if (object.ReferenceEquals(resourceMan, null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.PowerToys.PreviewHandler.Pdf.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to This pdf could not be preview due to an internal error..
+ ///
+ internal static string PdfNotPreviewedError
+ {
+ get
+ {
+ return ResourceManager.GetString("PdfNotPreviewedError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Can't preview pdf. This pdf is password protected..
+ ///
+ internal static string PdfPasswordProtectedError
+ {
+ get
+ {
+ return ResourceManager.GetString("PdfPasswordProtectedError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to This PDF contains more pages, this preview only shows the first 10 pages. Open PDF to view all pages..
+ ///
+ internal static string PdfMorePagesMessage
+ {
+ get
+ {
+ return ResourceManager.GetString("PdfMorePagesMessage", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/modules/previewpane/PdfPreviewHandler/Properties/Resources.resx b/src/modules/previewpane/PdfPreviewHandler/Properties/Resources.resx
new file mode 100644
index 0000000000..809efc52b8
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandler/Properties/Resources.resx
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ This PDF contains more than 10 pages. Open the document to view all pages.
+ This text is displayed if PDF has more than 10 pages.
+
+
+ This PDF could not be previewed due to an internal error.
+ This text is displayed if PDF fails to preview
+
+
+ Can't preview file. This PDF is password protected.
+ This text is displayed if PDF is password protected.
+
+
diff --git a/src/modules/previewpane/PdfPreviewHandler/Telemetry/Events/PdfFileHandlerLoaded.cs b/src/modules/previewpane/PdfPreviewHandler/Telemetry/Events/PdfFileHandlerLoaded.cs
new file mode 100644
index 0000000000..9cd16b0b78
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandler/Telemetry/Events/PdfFileHandlerLoaded.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Tracing;
+using Microsoft.PowerToys.Telemetry;
+using Microsoft.PowerToys.Telemetry.Events;
+
+namespace Microsoft.PowerToys.PreviewHandler.Pdf.Telemetry.Events
+{
+ ///
+ /// A telemetry event that is triggered when a pdf file is viewed in the preview pane.
+ ///
+ [EventData]
+ public class PdfFileHandlerLoaded : EventBase, IEvent
+ {
+ ///
+ public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
+ }
+}
diff --git a/src/modules/previewpane/PdfPreviewHandler/Telemetry/Events/PdfFilePreviewError.cs b/src/modules/previewpane/PdfPreviewHandler/Telemetry/Events/PdfFilePreviewError.cs
new file mode 100644
index 0000000000..73dec91265
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandler/Telemetry/Events/PdfFilePreviewError.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.PowerToys.Telemetry;
+using Microsoft.PowerToys.Telemetry.Events;
+
+namespace Microsoft.PowerToys.PreviewHandler.Pdf.Telemetry.Events
+{
+ ///
+ /// A telemetry event that is triggered when an error occurs while attempting to view a markdown file in the preview pane.
+ ///
+ public class PdfFilePreviewError : EventBase, IEvent
+ {
+ ///
+ /// Gets or sets the error message.
+ ///
+ public string Message { get; set; }
+
+ ///
+ public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServicePerformance;
+ }
+}
diff --git a/src/modules/previewpane/PdfPreviewHandler/Telemetry/Events/PdfFilePreviewed.cs b/src/modules/previewpane/PdfPreviewHandler/Telemetry/Events/PdfFilePreviewed.cs
new file mode 100644
index 0000000000..e9eee5d17e
--- /dev/null
+++ b/src/modules/previewpane/PdfPreviewHandler/Telemetry/Events/PdfFilePreviewed.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Tracing;
+using Microsoft.PowerToys.Telemetry;
+using Microsoft.PowerToys.Telemetry.Events;
+
+namespace Microsoft.PowerToys.PreviewHandler.Pdf.Telemetry.Events
+{
+ ///
+ /// A telemetry event that is triggered when a markdown file is viewed in the preview pane.
+ ///
+ [EventData]
+ public class PdfFilePreviewed : EventBase, IEvent
+ {
+ ///
+ public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
+ }
+}
diff --git a/src/modules/previewpane/PreviewPaneUnitTests/HTMLParsingExtensionTest.cs b/src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HTMLParsingExtensionTest.cs
similarity index 100%
rename from src/modules/previewpane/PreviewPaneUnitTests/HTMLParsingExtensionTest.cs
rename to src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HTMLParsingExtensionTest.cs
diff --git a/src/modules/previewpane/PreviewPaneUnitTests/HelperFiles/MarkdownWithExternalImage.txt b/src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HelperFiles/MarkdownWithExternalImage.txt
similarity index 98%
rename from src/modules/previewpane/PreviewPaneUnitTests/HelperFiles/MarkdownWithExternalImage.txt
rename to src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HelperFiles/MarkdownWithExternalImage.txt
index 1439071e7a..3cdaf321c1 100644
--- a/src/modules/previewpane/PreviewPaneUnitTests/HelperFiles/MarkdownWithExternalImage.txt
+++ b/src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HelperFiles/MarkdownWithExternalImage.txt
@@ -1,2 +1,2 @@
-
+
\ No newline at end of file
diff --git a/src/modules/previewpane/PreviewPaneUnitTests/HelperFiles/MarkdownWithHTMLImageTag.txt b/src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HelperFiles/MarkdownWithHTMLImageTag.txt
similarity index 97%
rename from src/modules/previewpane/PreviewPaneUnitTests/HelperFiles/MarkdownWithHTMLImageTag.txt
rename to src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HelperFiles/MarkdownWithHTMLImageTag.txt
index 5cd2ab8a77..98d78a5c1d 100644
--- a/src/modules/previewpane/PreviewPaneUnitTests/HelperFiles/MarkdownWithHTMLImageTag.txt
+++ b/src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HelperFiles/MarkdownWithHTMLImageTag.txt
@@ -1,2 +1,2 @@
-## Something
+## Something
\ No newline at end of file
diff --git a/src/modules/previewpane/PreviewPaneUnitTests/HelperFiles/MarkdownWithscript.txt b/src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HelperFiles/MarkdownWithscript.txt
similarity index 100%
rename from src/modules/previewpane/PreviewPaneUnitTests/HelperFiles/MarkdownWithscript.txt
rename to src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HelperFiles/MarkdownWithscript.txt
diff --git a/src/modules/previewpane/PreviewPaneUnitTests/MarkdownPreviewHandlerTest.cs b/src/modules/previewpane/UnitTests-MarkdownPreviewHandler/MarkdownPreviewHandlerTest.cs
similarity index 99%
rename from src/modules/previewpane/PreviewPaneUnitTests/MarkdownPreviewHandlerTest.cs
rename to src/modules/previewpane/UnitTests-MarkdownPreviewHandler/MarkdownPreviewHandlerTest.cs
index e1b525dc9d..eb43a18a0e 100644
--- a/src/modules/previewpane/PreviewPaneUnitTests/MarkdownPreviewHandlerTest.cs
+++ b/src/modules/previewpane/UnitTests-MarkdownPreviewHandler/MarkdownPreviewHandlerTest.cs
@@ -9,7 +9,7 @@ using Microsoft.PowerToys.STATestExtension;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PreviewHandlerCommon;
-namespace PreviewPaneUnitTests
+namespace MarkdownPreviewHandlerUnitTests
{
[STATestClass]
public class MarkdownPreviewHandlerTest
diff --git a/src/modules/previewpane/PreviewPaneUnitTests/UnitTests-MarkdownPreviewHandler.csproj b/src/modules/previewpane/UnitTests-MarkdownPreviewHandler/UnitTests-MarkdownPreviewHandler.csproj
similarity index 100%
rename from src/modules/previewpane/PreviewPaneUnitTests/UnitTests-MarkdownPreviewHandler.csproj
rename to src/modules/previewpane/UnitTests-MarkdownPreviewHandler/UnitTests-MarkdownPreviewHandler.csproj
diff --git a/src/modules/previewpane/UnitTests-PdfPreviewHandler/HelperFiles/sample.pdf b/src/modules/previewpane/UnitTests-PdfPreviewHandler/HelperFiles/sample.pdf
new file mode 100644
index 0000000000..96304d9b21
Binary files /dev/null and b/src/modules/previewpane/UnitTests-PdfPreviewHandler/HelperFiles/sample.pdf differ
diff --git a/src/modules/previewpane/UnitTests-PdfPreviewHandler/PdfPreviewHandlerTest.cs b/src/modules/previewpane/UnitTests-PdfPreviewHandler/PdfPreviewHandlerTest.cs
new file mode 100644
index 0000000000..492ed80ba0
--- /dev/null
+++ b/src/modules/previewpane/UnitTests-PdfPreviewHandler/PdfPreviewHandlerTest.cs
@@ -0,0 +1,89 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Drawing;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+using System.Windows.Forms;
+using Microsoft.PowerToys.PreviewHandler.Pdf;
+using Microsoft.PowerToys.STATestExtension;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+
+namespace PdfPreviewHandlerUnitTests
+{
+ [STATestClass]
+ public class PdfPreviewHandlerTest
+ {
+ [TestMethod]
+ public void PdfPreviewHandlerControlAddsControlsToFormWhenDoPreviewIsCalled()
+ {
+ // Arrange
+ using (var pdfPreviewHandlerControl = new PdfPreviewHandlerControl())
+ {
+ // Act
+ var file = File.ReadAllBytes("HelperFiles/sample.pdf");
+
+ pdfPreviewHandlerControl.DoPreview(GetMockStream(file));
+
+ var flowLayoutPanel = pdfPreviewHandlerControl.Controls[0] as FlowLayoutPanel;
+
+ // Assert
+ Assert.AreEqual(1, pdfPreviewHandlerControl.Controls.Count);
+ }
+ }
+
+ [TestMethod]
+ public void PdfPreviewHandlerControlShouldAddValidInfoBarIfPdfPreviewThrows()
+ {
+ // Arrange
+ using (var pdfPreviewHandlerControl = new PdfPreviewHandlerControl())
+ {
+ var mockStream = new Mock();
+ mockStream
+ .Setup(x => x.Read(It.IsAny(), It.IsAny(), It.IsAny()))
+ .Throws(new Exception());
+
+ // Act
+ pdfPreviewHandlerControl.DoPreview(mockStream.Object);
+ var textBox = pdfPreviewHandlerControl.Controls[0] as RichTextBox;
+
+ // Assert
+ Assert.IsFalse(string.IsNullOrWhiteSpace(textBox.Text));
+ Assert.AreEqual(1, pdfPreviewHandlerControl.Controls.Count);
+ Assert.AreEqual(DockStyle.Top, textBox.Dock);
+ Assert.AreEqual(Color.LightYellow, textBox.BackColor);
+ Assert.IsTrue(textBox.Multiline);
+ Assert.IsTrue(textBox.ReadOnly);
+ Assert.AreEqual(RichTextBoxScrollBars.None, textBox.ScrollBars);
+ Assert.AreEqual(BorderStyle.None, textBox.BorderStyle);
+ }
+ }
+
+ private static IStream GetMockStream(byte[] sourceArray)
+ {
+ var streamMock = new Mock();
+ var firstCall = true;
+ streamMock
+ .Setup(x => x.Read(It.IsAny(), It.IsAny(), It.IsAny()))
+ .Callback((buffer, countToRead, bytesReadPtr) =>
+ {
+ if (firstCall)
+ {
+ Array.Copy(sourceArray, 0, buffer, 0, sourceArray.Length);
+ Marshal.WriteInt32(bytesReadPtr, sourceArray.Length);
+ firstCall = false;
+ }
+ else
+ {
+ Marshal.WriteInt32(bytesReadPtr, 0);
+ }
+ });
+
+ return streamMock.Object;
+ }
+ }
+}
diff --git a/src/modules/previewpane/UnitTests-PdfPreviewHandler/UnitTests-PdfPreviewHandler.csproj b/src/modules/previewpane/UnitTests-PdfPreviewHandler/UnitTests-PdfPreviewHandler.csproj
new file mode 100644
index 0000000000..4fdfd32c98
--- /dev/null
+++ b/src/modules/previewpane/UnitTests-PdfPreviewHandler/UnitTests-PdfPreviewHandler.csproj
@@ -0,0 +1,67 @@
+
+
+ x64
+ UnitTests-PdfPreviewHandler
+ PowerToys UnitTests-PdfPreviewHandler
+ Microsoft Corp.
+ Copyright (C) 2020 Microsoft Corp.
+ PowerToys
+ UnitTests-PdfPreviewHandler
+ Microsoft Corp.
+ PowerToys
+ en-US
+ PowerToys UnitTests-PdfPreviewHandler
+ Copyright (C) 2020 Microsoft Corp.
+
+
+
+ {ECC20689-002A-4354-95A6-B58DF089C6FF}
+ PreviewPaneUnitTests
+ PreviewPaneUnitTests
+ netcoreapp3.1
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+ $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
+ StyleCop.json
+
+
+
+
+ all
+
+
+
\ No newline at end of file
diff --git a/src/modules/previewpane/powerpreview/CLSID.h b/src/modules/previewpane/powerpreview/CLSID.h
index 64fc376a45..104e2d8ef8 100644
--- a/src/modules/previewpane/powerpreview/CLSID.h
+++ b/src/modules/previewpane/powerpreview/CLSID.h
@@ -16,6 +16,12 @@ const CLSID CLSID_SHIMActivateMdPreviewHandler = { 0xE0907A95, 0x6F9A, 0x4D1B, {
// 45769bcc-e8fd-42d0-947e-02beef77a1f5
const CLSID CLSID_MdPreviewHandler = { 0x45769bcc, 0xe8fd, 0x42d0, { 0x94, 0x7e, 0x02, 0xbe, 0xef, 0x77, 0xa1, 0xf5 } };
+// 4F6D533B-4185-43A6-AD75-9B20034B14CA
+const CLSID CLSID_SHIMActivatePdfPreviewHandler = { 0x4f6d533b, 0x4185, 0x43a6, { 0xad, 0x75, 0x9b, 0x20, 0x3, 0x4b, 0x14, 0xca } };
+
+// 07665729-6243-4746-95b7-79579308d1b2
+const CLSID CLSID_PdfPreviewHandler = { 0x07665729, 0x6243, 0x4746, { 0x95, 0xb7, 0x79, 0x57, 0x93, 0x08, 0xd1, 0xb2 } };
+
// 9C723B8C-4F5C-4147-9DE4-C2808F9AF66B
const CLSID CLSID_SHIMActivateSvgThumbnailProvider = { 0x9C723B8C, 0x4F5C, 0x4147, { 0x9D, 0xE4, 0xC2, 0x80, 0x8F, 0x9A, 0xF6, 0x6B } };
@@ -23,8 +29,9 @@ const CLSID CLSID_SHIMActivateSvgThumbnailProvider = { 0x9C723B8C, 0x4F5C, 0x414
const CLSID CLSID_SvgThumbnailProvider = { 0x36B27788, 0xA8BB, 0x4698, { 0xA7, 0x56, 0xDF, 0x9F, 0x11, 0xF6, 0x4F, 0x84 } };
// Pairs of NativeClsid vs ManagedClsid used for preview handlers.
-const std::vector> NativeToManagedClsid({
+const std::vector> NativeToManagedClsid({
{ CLSID_SHIMActivateMdPreviewHandler, CLSID_MdPreviewHandler },
+ { CLSID_SHIMActivatePdfPreviewHandler, CLSID_PdfPreviewHandler },
{ CLSID_SHIMActivateSvgPreviewHandler, CLSID_SvgPreviewHandler },
{ CLSID_SHIMActivateSvgThumbnailProvider, CLSID_SvgThumbnailProvider }
});
\ No newline at end of file
diff --git a/src/modules/previewpane/powerpreview/Resources.resx b/src/modules/previewpane/powerpreview/Resources.resx
index 0b4cbf17bd..7af9b5effe 100644
--- a/src/modules/previewpane/powerpreview/Resources.resx
+++ b/src/modules/previewpane/powerpreview/Resources.resx
@@ -167,5 +167,11 @@
Don't show again
-
+
+
+ PDF Previewer
+
+
+ PDF Previewer
+
\ No newline at end of file
diff --git a/src/modules/previewpane/powerpreview/powerpreview.cpp b/src/modules/previewpane/powerpreview/powerpreview.cpp
index 8856834445..27e6a482f6 100644
--- a/src/modules/previewpane/powerpreview/powerpreview.cpp
+++ b/src/modules/previewpane/powerpreview/powerpreview.cpp
@@ -33,6 +33,14 @@ PowerPreviewModule::PowerPreviewModule() :
L"Markdown Preview Handler",
std::make_unique()));
+ m_fileExplorerModules.emplace_back(std::make_unique(
+ true,
+ L"pdf-previewer-toggle-setting",
+ GET_RESOURCE_STRING(IDS_PREVPANE_PDF_SETTINGS_DESCRIPTION),
+ L"{07665729-6243-4746-95b7-79579308d1b2}",
+ L"PDF Preview Handler",
+ std::make_unique()));
+
m_fileExplorerModules.emplace_back(std::make_unique(
true,
L"svg-thumbnail-toggle-setting",
diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/PowerPreviewProperties.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/PowerPreviewProperties.cs
index 6e7e4b4297..8a5b5f7c83 100644
--- a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/PowerPreviewProperties.cs
+++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/PowerPreviewProperties.cs
@@ -63,6 +63,23 @@ namespace Microsoft.PowerToys.Settings.UI.Library
}
}
+ private bool enablePdfPreview = true;
+
+ [JsonPropertyName("pdf-previewer-toggle-setting")]
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool EnablePdfPreview
+ {
+ get => enablePdfPreview;
+ set
+ {
+ if (value != enablePdfPreview)
+ {
+ LogTelemetryEvent(value);
+ enablePdfPreview = value;
+ }
+ }
+ }
+
public PowerPreviewProperties()
{
}
diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/ViewModels/PowerPreviewViewModel.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/ViewModels/PowerPreviewViewModel.cs
index 911620fee1..ea1f22ea2a 100644
--- a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/ViewModels/PowerPreviewViewModel.cs
+++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/ViewModels/PowerPreviewViewModel.cs
@@ -49,10 +49,12 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
_svgRenderIsEnabled = Settings.Properties.EnableSvgPreview;
_svgThumbnailIsEnabled = Settings.Properties.EnableSvgThumbnail;
_mdRenderIsEnabled = Settings.Properties.EnableMdPreview;
+ _pdfRenderIsEnabled = Settings.Properties.EnablePdfPreview;
}
private bool _svgRenderIsEnabled;
private bool _mdRenderIsEnabled;
+ private bool _pdfRenderIsEnabled;
private bool _svgThumbnailIsEnabled;
public bool SVGRenderIsEnabled
@@ -109,6 +111,24 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
}
}
+ public bool PDFRenderIsEnabled
+ {
+ get
+ {
+ return _pdfRenderIsEnabled;
+ }
+
+ set
+ {
+ if (value != _pdfRenderIsEnabled)
+ {
+ _pdfRenderIsEnabled = value;
+ Settings.Properties.EnablePdfPreview = value;
+ RaisePropertyChanged();
+ }
+ }
+ }
+
public string GetSettingsSubPath()
{
return _settingsConfigFileFolder + "\\" + ModuleName;
diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerPreview.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerPreview.cs
index 07b03abb90..878069c8a9 100644
--- a/src/settings-ui/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerPreview.cs
+++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerPreview.cs
@@ -57,6 +57,7 @@ namespace ViewModelTests
// Verify that the old settings persisted
Assert.AreEqual(originalGeneralSettings.IsElevated, viewModel.IsElevated);
Assert.AreEqual(originalSettings.Properties.EnableMdPreview, viewModel.MDRenderIsEnabled);
+ Assert.AreEqual(originalSettings.Properties.EnablePdfPreview, viewModel.PDFRenderIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableSvgPreview, viewModel.SVGRenderIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableSvgThumbnail, viewModel.SVGThumbnailIsEnabled);
@@ -118,5 +119,23 @@ namespace ViewModelTests
// act
viewModel.MDRenderIsEnabled = true;
}
+
+ [TestMethod]
+ public void PDFRenderIsEnabledShouldPrevHandlerWhenSuccessful()
+ {
+ // Assert
+ Func sendMockIPCConfigMSG = msg =>
+ {
+ SndModuleSettings snd = JsonSerializer.Deserialize>(msg);
+ Assert.IsTrue(snd.PowertoysSetting.FileExplorerPreviewSettings.Properties.EnablePdfPreview);
+ return 0;
+ };
+
+ // arrange
+ PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository.GetInstance(mockPowerPreviewSettingsUtils.Object), SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, PowerPreviewSettings.ModuleName);
+
+ // act
+ viewModel.PDFRenderIsEnabled = true;
+ }
}
}
diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Controls/Setting/Setting.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Controls/Setting/Setting.xaml
index 382d4972bc..49c4122c0f 100644
--- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Controls/Setting/Setting.xaml
+++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Controls/Setting/Setting.xaml
@@ -58,7 +58,6 @@
Foreground="{ThemeResource CardPrimaryForegroundBrush}"
VerticalAlignment="Center"/>
-
Enable SVG (.svg) preview
Do you want this feature on / off
+
+ Enable PDF (.pdf) preview
+ Do you want this feature on / off
+
Enable SVG (.svg) thumbnails
Do you want this feature on / off
diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/PowerPreviewPage.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/PowerPreviewPage.xaml
index 12d43ef077..5693f88554 100644
--- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/PowerPreviewPage.xaml
+++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/PowerPreviewPage.xaml
@@ -18,7 +18,6 @@
ModuleImageSource="ms-appx:///Assets/Modules/PowerPreview.png">
-
+
+
+
+
+
+
-
-
-
+
diff --git a/tools/BugReportTool/BugReportTool/RegistryUtils.cpp b/tools/BugReportTool/BugReportTool/RegistryUtils.cpp
index d1a1fc5ffb..6acad09576 100644
--- a/tools/BugReportTool/BugReportTool/RegistryUtils.cpp
+++ b/tools/BugReportTool/BugReportTool/RegistryUtils.cpp
@@ -19,12 +19,14 @@ namespace
{ HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\AppUserModelId\\PowerToysRun" },
{ HKEY_CLASSES_ROOT, L".svg\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" },
{ HKEY_CLASSES_ROOT, L".svg\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" },
- { HKEY_CLASSES_ROOT, L".md\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" }
+ { HKEY_CLASSES_ROOT, L".md\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" },
+ { HKEY_CLASSES_ROOT, L".pdf\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" }
};
vector> registryValues = {
{ HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{ddee2b8a-6807-48a6-bb20-2338174ff779}" },
{ HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{45769bcc-e8fd-42d0-947e-02beef77a1f5}" },
+ { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{07665729-6243-4746-95b7-79579308d1b2}" },
{ HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION", L"prevhost.exe" },
{ HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION", L"dllhost.exe" }
};