mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-15 19:27:56 +01:00
[FileExplorer]GcodeThumbnailProvider and GcodePreviewHandler (#14827)
* Adds the GcodeThumbnailProvider * Registers the GcodeThumbnailProvider * Adds Settings support * Reverts solution changes back to original * Corrects "Gcode" text with "G-code" * Adds gcode thumbnail setting description * Follow up on PR review comments * Adds GcodePreviewHandler * Follow up on PR review comments * Renames assemblies following #14903
This commit is contained in:
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -42,6 +42,8 @@ body:
|
||||
- Mouse Utilities
|
||||
- PDF Preview
|
||||
- PDF Thumbnail
|
||||
- G-code Preview
|
||||
- G-code Thumbnail
|
||||
- PowerRename
|
||||
- PowerToys Run
|
||||
- Shortcut Guide
|
||||
|
||||
1
.github/actions/spell-check/excludes.txt
vendored
1
.github/actions/spell-check/excludes.txt
vendored
@@ -12,6 +12,7 @@ ignore$
|
||||
\.bmp$
|
||||
\.dat$
|
||||
\.dll$
|
||||
\.gcode$
|
||||
\.gif$
|
||||
\.gitignore$
|
||||
\.ico$
|
||||
|
||||
4
.github/actions/spell-check/expect.txt
vendored
4
.github/actions/spell-check/expect.txt
vendored
@@ -140,12 +140,14 @@ backend
|
||||
backtracer
|
||||
bak
|
||||
bbwe
|
||||
bca
|
||||
bcc
|
||||
bck
|
||||
Bcl
|
||||
BEGINLABELEDIT
|
||||
betadele
|
||||
betsegaw
|
||||
bfee
|
||||
BGR
|
||||
bgra
|
||||
BGSOUNDS
|
||||
@@ -696,6 +698,8 @@ Gamebar
|
||||
GBs
|
||||
GCLP
|
||||
gcnew
|
||||
gcode
|
||||
gcodepreviewhandler
|
||||
gdi
|
||||
gdiplus
|
||||
GDISCALED
|
||||
|
||||
@@ -120,10 +120,12 @@ steps:
|
||||
configuration: '$(BuildConfiguration)'
|
||||
testSelector: 'testAssemblies'
|
||||
testAssemblyVer2: |
|
||||
**\UnitTests-GcodeThumbnailProvider.dll
|
||||
**\UnitTests-SvgThumbnailProvider.dll
|
||||
**\UnitTests-PdfThumbnailProvider.dll
|
||||
**\Microsoft.PowerToys.Settings.UI.UnitTests.dll
|
||||
**\UnitTests-MarkdownPreviewHandler.dll
|
||||
**\UnitTests-GcodePreviewHandler.dll
|
||||
**\UnitTests-PdfPreviewHandler.dll
|
||||
**\UnitTests-SvgPreviewHandler.dll
|
||||
**\UnitTests-PreviewHandlerCommon.dll
|
||||
|
||||
@@ -107,6 +107,10 @@ build:
|
||||
- 'modules\FancyZones\PowerToys.Interop.dll'
|
||||
- 'modules\FancyZones\Telemetry.dll'
|
||||
- 'modules\FancyZones\Microsoft.PowerToys.Common.UI.dll'
|
||||
- 'modules\FileExplorerPreview\PowerToys.GcodePreviewHandler.dll'
|
||||
- 'modules\FileExplorerPreview\PowerToys.GcodePreviewHandler.comhost.dll'
|
||||
- 'modules\FileExplorerPreview\PowerToys.GcodeThumbnailProvider.dll'
|
||||
- 'modules\FileExplorerPreview\PowerToys.GcodeThumbnailProvider.comhost.dll'
|
||||
- 'modules\FileExplorerPreview\PowerToys.ManagedTelemetry.dll'
|
||||
- 'modules\FileExplorerPreview\PowerToys.MarkdownPreviewHandler.dll'
|
||||
- 'modules\FileExplorerPreview\PowerToys.MarkdownPreviewHandler.comhost.dll'
|
||||
|
||||
@@ -374,6 +374,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FindMyMouse", "src\modules\
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MouseHighlighter", "src\modules\MouseUtils\MouseHighlighter\MouseHighlighter.vcxproj", "{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GcodeThumbnailProvider", "src\modules\previewpane\GcodeThumbnailProvider\GcodeThumbnailProvider.csproj", "{809AA252-E17A-4FA2-B0A1-0450976B763F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-GcodeThumbnailProvider", "src\modules\previewpane\UnitTests-GcodeThumbnailProvider\UnitTests-GcodeThumbnailProvider.csproj", "{133281D8-1BCE-4D07-B31E-796612A9609E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GcodePreviewHandler", "src\modules\previewpane\GcodePreviewHandler\GcodePreviewHandler.csproj", "{805306FF-A562-4415-8DEF-E493BDC45918}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-GcodePreviewHandler", "src\modules\previewpane\UnitTests-GcodePreviewHandler\UnitTests-GcodePreviewHandler.csproj", "{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -995,6 +1003,30 @@ Global
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Release|x64.ActiveCfg = Release|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Release|x64.Build.0 = Release|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Release|x86.ActiveCfg = Release|x64
|
||||
{809AA252-E17A-4FA2-B0A1-0450976B763F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{809AA252-E17A-4FA2-B0A1-0450976B763F}.Debug|x64.Build.0 = Debug|x64
|
||||
{809AA252-E17A-4FA2-B0A1-0450976B763F}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{809AA252-E17A-4FA2-B0A1-0450976B763F}.Release|x64.ActiveCfg = Release|x64
|
||||
{809AA252-E17A-4FA2-B0A1-0450976B763F}.Release|x64.Build.0 = Release|x64
|
||||
{809AA252-E17A-4FA2-B0A1-0450976B763F}.Release|x86.ActiveCfg = Release|x64
|
||||
{133281D8-1BCE-4D07-B31E-796612A9609E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{133281D8-1BCE-4D07-B31E-796612A9609E}.Debug|x64.Build.0 = Debug|x64
|
||||
{133281D8-1BCE-4D07-B31E-796612A9609E}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{133281D8-1BCE-4D07-B31E-796612A9609E}.Release|x64.ActiveCfg = Release|x64
|
||||
{133281D8-1BCE-4D07-B31E-796612A9609E}.Release|x64.Build.0 = Release|x64
|
||||
{133281D8-1BCE-4D07-B31E-796612A9609E}.Release|x86.ActiveCfg = Release|x64
|
||||
{805306FF-A562-4415-8DEF-E493BDC45918}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{805306FF-A562-4415-8DEF-E493BDC45918}.Debug|x64.Build.0 = Debug|x64
|
||||
{805306FF-A562-4415-8DEF-E493BDC45918}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{805306FF-A562-4415-8DEF-E493BDC45918}.Release|x64.ActiveCfg = Release|x64
|
||||
{805306FF-A562-4415-8DEF-E493BDC45918}.Release|x64.Build.0 = Release|x64
|
||||
{805306FF-A562-4415-8DEF-E493BDC45918}.Release|x86.ActiveCfg = Release|x64
|
||||
{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}.Debug|x64.Build.0 = Debug|x64
|
||||
{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}.Release|x64.ActiveCfg = Release|x64
|
||||
{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}.Release|x64.Build.0 = Release|x64
|
||||
{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}.Release|x86.ActiveCfg = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -1115,6 +1147,10 @@ Global
|
||||
{322566EF-20DC-43A6-B9F8-616AF942579A} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336} = {322566EF-20DC-43A6-B9F8-616AF942579A}
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88} = {322566EF-20DC-43A6-B9F8-616AF942579A}
|
||||
{809AA252-E17A-4FA2-B0A1-0450976B763F} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{133281D8-1BCE-4D07-B31E-796612A9609E} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{805306FF-A562-4415-8DEF-E493BDC45918} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<File DestinationPath="modules\PowerToys.PreviewHandlerCommon.dll" SourcePath="..\..\x64\Release\modules\PowerToys.PreviewHandlerCommon.dll"/>
|
||||
<File DestinationPath="modules\PowerToys.SvgPreviewHandler.dll" SourcePath="..\..\x64\Release\modules\PowerToys.SvgPreviewHandler.dll"/>
|
||||
<File DestinationPath="modules\PowerToys.MarkdownPreviewHandler.dll" SourcePath="..\..\x64\Release\modules\PowerToys.MarkdownPreviewHandler.dll"/>
|
||||
<File DestinationPath="modules\PowerToys.GcodePreviewHandler.dll" SourcePath="..\..\x64\Release\modules\PowerToys.GcodePreviewHandler.dll"/>
|
||||
<File DestinationPath="modules\Markdig.Signed.dll" SourcePath="..\..\x64\Release\modules\Markdig.Signed.dll"/>
|
||||
<File DestinationPath="modules\HtmlAgilityPack.dll" SourcePath="..\..\x64\Release\modules\HtmlAgilityPack.dll"/>
|
||||
<File DestinationPath="registry.dat" SourcePath="registry.dat"/>
|
||||
|
||||
@@ -87,12 +87,21 @@
|
||||
<desktop2:DesktopPreviewHandler Clsid="4F6D533B-4185-43A6-AD75-9B20034B14CA"/>
|
||||
</uap3:FileTypeAssociation>
|
||||
</uap:Extension>
|
||||
<uap:Extension Category="windows.fileTypeAssociation">
|
||||
<uap3:FileTypeAssociation Name="gcodepreviewhandler" desktop2:AllowSilentDefaultTakeOver="true">
|
||||
<uap:SupportedFileTypes>
|
||||
<uap:FileType>.gcode</uap:FileType>
|
||||
</uap:SupportedFileTypes>
|
||||
<desktop2:DesktopPreviewHandler Clsid="516CB24F-562F-422F-8B01-6B580474D093"/>
|
||||
</uap3:FileTypeAssociation>
|
||||
</uap:Extension>
|
||||
<com:Extension Category="windows.comServer">
|
||||
<com:ComServer>
|
||||
<com:SurrogateServer DisplayName="Preview Handler" AppId="E39A92FE-D89A-417B-9B9D-F0B6BD564B36" SystemSurrogate="PreviewHost">
|
||||
<com:Class Id="74619BDA-A66B-451D-864C-A7726F5FE650" Path="modules\PowerToys.powerpreview.dll" ThreadingModel="Both"/>
|
||||
<com:Class Id="E0907A95-6F9A-4D1B-A97A-7D9D2648881E" Path="modules\PowerToys.powerpreview.dll" ThreadingModel="Both"/>
|
||||
<com:Class Id="4F6D533B-4185-43A6-AD75-9B20034B14CA" Path="modules\PowerToys.powerpreview.dll" ThreadingModel="Both"/>
|
||||
<com:Class Id="516CB24F-562F-422F-8B01-6B580474D093" Path="modules\PowerToys.powerpreview.dll" ThreadingModel="Both"/>
|
||||
</com:SurrogateServer>
|
||||
</com:ComServer>
|
||||
</com:Extension>
|
||||
|
||||
@@ -813,6 +813,16 @@
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.PdfThumbnailProvider.comhost.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.PdfThumbnailProvider.runtimeconfig.json" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.PdfThumbnailProvider.deps.json" />
|
||||
<!-- File to include dll for G-code Preview Handler -->
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.GcodePreviewHandler.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.GcodePreviewHandler.comhost.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.GcodePreviewHandler.runtimeconfig.json" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.GcodePreviewHandler.deps.json" />
|
||||
<!-- File to include dll for G-code Thumbnail Provider -->
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.GcodeThumbnailProvider.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.GcodeThumbnailProvider.comhost.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.GcodeThumbnailProvider.runtimeconfig.json" />
|
||||
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PowerToys.GcodeThumbnailProvider.deps.json" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
@@ -1058,6 +1068,9 @@
|
||||
<Component Id="PDFPreviewHandler_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)FileExplorerPreviewInstallFolder">
|
||||
<File Id="PDFPreviewHandler_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\FileExplorerPreview\$(var.Language)\PowerToys.PdfPreviewHandler.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="GcodePreviewHandler_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)FileExplorerPreviewInstallFolder">
|
||||
<File Id="GcodePreviewHandler_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\FileExplorerPreview\$(var.Language)\PowerToys.GcodePreviewHandler.resources.dll" />
|
||||
</Component>
|
||||
<!-- PowerToys Run aka Launcher plugin resources -->
|
||||
<Component Id="Launcher_Calculator_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)CalculatorPluginFolder">
|
||||
<File Id="Launcher_Calculator_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Calculator\$(var.Language)\Microsoft.PowerToys.Run.Plugin.Calculator.resources.dll" />
|
||||
|
||||
@@ -50,6 +50,20 @@ inline registry::ChangeSet getPdfPreviewHandlerChangeSet(const std::wstring inst
|
||||
L".pdf");
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getGcodePreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
return generatePreviewHandler(PreviewHandlerType::preview,
|
||||
perUser,
|
||||
L"{ec52dea8-7c9f-4130-a77b-1737d0418507}",
|
||||
get_std_product_version(),
|
||||
(fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.GcodePreviewHandler.comhost.dll)d").wstring(),
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.PreviewHandler.Gcode.GcodePreviewHandler",
|
||||
L"G-code Preview Handler",
|
||||
L".gcode");
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getSvgThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
@@ -78,11 +92,27 @@ inline registry::ChangeSet getPdfThumbnailHandlerChangeSet(const std::wstring in
|
||||
L".pdf");
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getGcodeThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
return generatePreviewHandler(PreviewHandlerType::thumbnail,
|
||||
perUser,
|
||||
L"{BFEE99B4-B74D-4348-BCA5-E757029647FF}",
|
||||
get_std_product_version(),
|
||||
(fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PowerToys.GcodeThumbnailProvider.comhost.dll)d").wstring(),
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.ThumbnailHandler.Gcode.GcodeThumbnailProvider",
|
||||
L"G-code Thumbnail Provider",
|
||||
L".gcode");
|
||||
}
|
||||
|
||||
inline std::vector<registry::ChangeSet> getAllModulesChangeSets(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
return { getSvgPreviewHandlerChangeSet(installationDir, perUser),
|
||||
getMdPreviewHandlerChangeSet(installationDir, perUser),
|
||||
getPdfPreviewHandlerChangeSet(installationDir, perUser),
|
||||
getGcodePreviewHandlerChangeSet(installationDir, perUser),
|
||||
getSvgThumbnailHandlerChangeSet(installationDir, perUser),
|
||||
getPdfThumbnailHandlerChangeSet(installationDir, perUser) };
|
||||
getPdfThumbnailHandlerChangeSet(installationDir, perUser),
|
||||
getGcodeThumbnailHandlerChangeSet(installationDir, perUser) };
|
||||
}
|
||||
@@ -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.Gcode
|
||||
{
|
||||
/// <summary>
|
||||
/// Extends <see cref="StreamBasedPreviewHandler"/> for Gcode Preview Handler.
|
||||
/// </summary>
|
||||
[Guid("ec52dea8-7c9f-4130-a77b-1737d0418507")]
|
||||
[ClassInterface(ClassInterfaceType.None)]
|
||||
[ComVisible(true)]
|
||||
public class GcodePreviewHandler : StreamBasedPreviewHandler, IDisposable
|
||||
{
|
||||
private GcodePreviewHandlerControl _gcodePreviewControl;
|
||||
private bool disposedValue;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GcodePreviewHandler"/> class.
|
||||
/// </summary>
|
||||
public GcodePreviewHandler()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void DoPreview()
|
||||
{
|
||||
_gcodePreviewControl.DoPreview(Stream);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override IPreviewHandlerControl CreatePreviewHandlerControl()
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new Telemetry.Events.GcodeFileHandlerLoaded());
|
||||
_gcodePreviewControl = new GcodePreviewHandlerControl();
|
||||
|
||||
return _gcodePreviewControl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes objects
|
||||
/// </summary>
|
||||
/// <param name="disposing">Is Disposing</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_gcodePreviewControl.Dispose();
|
||||
}
|
||||
|
||||
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
|
||||
// TODO: set large fields to null
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<PropertyGroup>
|
||||
<Platforms>x64</Platforms>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<AssemblyTitle>PowerToys.GcodePreviewHandler</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys GcodePreviewHandler</AssemblyDescription>
|
||||
<AssemblyCompany>Microsoft Corp.</AssemblyCompany>
|
||||
<AssemblyCopyright>Copyright (C) 2020 Microsoft Corporation</AssemblyCopyright>
|
||||
<AssemblyProduct>PowerToys</AssemblyProduct>
|
||||
<Company>Microsoft Corp.</Company>
|
||||
<Product>PowerToys</Product>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<Description>PowerToys GcodePreviewHandler</Description>
|
||||
<Copyright>Copyright (C) 2020 Microsoft Corporation</Copyright>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<DocumentationFile>$(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\GcodePreviewPaneDocumentation.xml</DocumentationFile>
|
||||
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AssemblyName>PowerToys.GcodePreviewHandler</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{805306FF-A562-4415-8DEF-E493BDC45918}</ProjectGuid>
|
||||
<RootNamespace>Microsoft.PowerToys.PreviewHandler.Gcode</RootNamespace>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<EnableComHosting>true</EnableComHosting>
|
||||
<IntermediateOutputPath>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(AssemblyName)\</IntermediateOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\codeAnalysis\GlobalSuppressions.cs" Link="GlobalSuppressions.cs" />
|
||||
<Compile Update="GcodePreviewHandlerControl.cs" />
|
||||
<Compile Update="Resource.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resource.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.IO.Abstractions" Version="12.2.5" />
|
||||
<PackageReference Include="System.Runtime.WindowsRuntime" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="..\..\..\codeAnalysis\StyleCop.json">
|
||||
<Link>StyleCop.json</Link>
|
||||
</AdditionalFiles>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
<ProjectReference Include="..\common\PreviewHandlerCommon.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Windows">
|
||||
<HintPath>$(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Resource.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,219 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using Common;
|
||||
using Common.Utilities;
|
||||
using Microsoft.PowerToys.PreviewHandler.Gcode.Telemetry.Events;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
|
||||
namespace Microsoft.PowerToys.PreviewHandler.Gcode
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of Control for Gcode Preview Handler.
|
||||
/// </summary>
|
||||
public class GcodePreviewHandlerControl : FormHandlerControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Picture box control to display the G-code thumbnail.
|
||||
/// </summary>
|
||||
private PictureBox _pictureBox;
|
||||
|
||||
/// <summary>
|
||||
/// Text box to display the information about blocked elements from Svg.
|
||||
/// </summary>
|
||||
private RichTextBox _textBox;
|
||||
|
||||
/// <summary>
|
||||
/// Represent if an text box info bar is added for showing message.
|
||||
/// </summary>
|
||||
private bool _infoBarAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Start the preview on the Control.
|
||||
/// </summary>
|
||||
/// <param name="dataSource">Stream reference to access source file.</param>
|
||||
public override void DoPreview<T>(T dataSource)
|
||||
{
|
||||
InvokeOnControlThread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Bitmap thumbnail = null;
|
||||
|
||||
using (var stream = new ReadonlyStream(dataSource as IStream))
|
||||
{
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
#pragma warning disable CA2000 // Do not dispose here
|
||||
thumbnail = GetThumbnail(reader);
|
||||
#pragma warning restore CA2000
|
||||
}
|
||||
}
|
||||
|
||||
_infoBarAdded = false;
|
||||
|
||||
if (thumbnail == null)
|
||||
{
|
||||
_infoBarAdded = true;
|
||||
AddTextBoxControl(Resource.GcodeWithoutEmbeddedThumbnails);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddPictureBoxControl(thumbnail);
|
||||
}
|
||||
|
||||
Resize += FormResized;
|
||||
base.DoPreview(dataSource);
|
||||
PowerToysTelemetry.Log.WriteEvent(new GcodeFilePreviewed());
|
||||
}
|
||||
#pragma warning disable CA1031 // Do not catch general exception types
|
||||
catch (Exception ex)
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
{
|
||||
PreviewError(ex, dataSource);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the G-code content searching for thumbnails and returns the largest.
|
||||
/// </summary>
|
||||
/// <param name="reader">The TextReader instance for the G-code content.</param>
|
||||
/// <returns>A thumbnail extracted from the G-code content.</returns>
|
||||
public static Bitmap GetThumbnail(TextReader reader)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap thumbnail = null;
|
||||
|
||||
var bitmapBase64 = GetBase64Thumbnails(reader)
|
||||
.OrderByDescending(x => x.Length)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (!string.IsNullOrEmpty(bitmapBase64))
|
||||
{
|
||||
var bitmapBytes = Convert.FromBase64String(bitmapBase64);
|
||||
|
||||
using (var bitmapStream = new MemoryStream(bitmapBytes))
|
||||
{
|
||||
thumbnail = new Bitmap(bitmapStream);
|
||||
}
|
||||
}
|
||||
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all thumbnails in base64 format found on the G-code data.
|
||||
/// </summary>
|
||||
/// <param name="reader">The TextReader instance for the G-code content.</param>
|
||||
/// <returns>An enumeration of thumbnails in base64 format found on the G-code.</returns>
|
||||
private static IEnumerable<string> GetBase64Thumbnails(TextReader reader)
|
||||
{
|
||||
string line;
|
||||
StringBuilder capturedText = null;
|
||||
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.StartsWith("; thumbnail begin", StringComparison.InvariantCulture))
|
||||
{
|
||||
capturedText = new StringBuilder();
|
||||
}
|
||||
else if (line == "; thumbnail end")
|
||||
{
|
||||
if (capturedText != null)
|
||||
{
|
||||
yield return capturedText.ToString();
|
||||
|
||||
capturedText = null;
|
||||
}
|
||||
}
|
||||
else if (capturedText != null)
|
||||
{
|
||||
capturedText.Append(line[2..]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when RichtextBox is resized.
|
||||
/// </summary>
|
||||
/// <param name="sender">Reference to resized control.</param>
|
||||
/// <param name="e">Provides data for the ContentsResized event.</param>
|
||||
private void RTBContentsResized(object sender, ContentsResizedEventArgs e)
|
||||
{
|
||||
var richTextBox = sender as RichTextBox;
|
||||
richTextBox.Height = e.NewRectangle.Height + 5;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when form is resized.
|
||||
/// </summary>
|
||||
/// <param name="sender">Reference to resized control.</param>
|
||||
/// <param name="e">Provides data for the resize event.</param>
|
||||
private void FormResized(object sender, EventArgs e)
|
||||
{
|
||||
if (_infoBarAdded)
|
||||
{
|
||||
_textBox.Width = Width;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PictureBox Control to Control Collection.
|
||||
/// </summary>
|
||||
/// <param name="image">Image to display on PictureBox Control.</param>
|
||||
private void AddPictureBoxControl(Image image)
|
||||
{
|
||||
_pictureBox = new PictureBox();
|
||||
_pictureBox.BackgroundImage = image;
|
||||
_pictureBox.BackgroundImageLayout = ImageLayout.Center;
|
||||
_pictureBox.Dock = DockStyle.Fill;
|
||||
Controls.Add(_pictureBox);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a Text Box in Controls for showing information about blocked elements.
|
||||
/// </summary>
|
||||
/// <param name="message">Message to be displayed in textbox.</param>
|
||||
private void AddTextBoxControl(string message)
|
||||
{
|
||||
_textBox = new RichTextBox();
|
||||
_textBox.Text = message;
|
||||
_textBox.BackColor = Color.LightYellow;
|
||||
_textBox.Multiline = true;
|
||||
_textBox.Dock = DockStyle.Top;
|
||||
_textBox.ReadOnly = true;
|
||||
_textBox.ContentsResized += RTBContentsResized;
|
||||
_textBox.ScrollBars = RichTextBoxScrollBars.None;
|
||||
_textBox.BorderStyle = BorderStyle.None;
|
||||
Controls.Add(_textBox);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when an error occurs during preview.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception which occurred.</param>
|
||||
/// <param name="dataSource">Stream reference to access source file.</param>
|
||||
private void PreviewError<T>(Exception exception, T dataSource)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new GcodeFilePreviewError { Message = exception.Message });
|
||||
Controls.Clear();
|
||||
_infoBarAdded = true;
|
||||
AddTextBoxControl(Resource.GcodeNotPreviewedError);
|
||||
base.DoPreview(dataSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
14
src/modules/previewpane/GcodePreviewHandler/LocProject.json
Normal file
14
src/modules/previewpane/GcodePreviewHandler/LocProject.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Projects": [
|
||||
{
|
||||
"LanguageSet": "Azure_Languages",
|
||||
"LocItems": [
|
||||
{
|
||||
"SourceFile": "src\\modules\\previewpane\\GcodePreviewHandler\\Resources.resx",
|
||||
"CopyOption": "LangIDOnName",
|
||||
"OutputPath": "src\\modules\\previewpane\\GcodePreviewHandler"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
81
src/modules/previewpane/GcodePreviewHandler/Resource.Designer.cs
generated
Normal file
81
src/modules/previewpane/GcodePreviewHandler/Resource.Designer.cs
generated
Normal file
@@ -0,0 +1,81 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 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.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.PowerToys.PreviewHandler.Gcode {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// 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", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resource {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resource() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[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.Gcode.Resource", typeof(Resource).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to This G-code could not be previewed due to an internal error..
|
||||
/// </summary>
|
||||
internal static string GcodeNotPreviewedError {
|
||||
get {
|
||||
return ResourceManager.GetString("GcodeNotPreviewedError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to This G-code does not contain any embedded thumbnails..
|
||||
/// </summary>
|
||||
internal static string GcodeWithoutEmbeddedThumbnails {
|
||||
get {
|
||||
return ResourceManager.GetString("GcodeWithoutEmbeddedThumbnails", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
127
src/modules/previewpane/GcodePreviewHandler/Resource.resx
Normal file
127
src/modules/previewpane/GcodePreviewHandler/Resource.resx
Normal file
@@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="GcodeNotPreviewedError" xml:space="preserve">
|
||||
<value>This G-code could not be previewed due to an internal error.</value>
|
||||
<comment>This text is displayed if G-code fails to preview</comment>
|
||||
</data>
|
||||
<data name="GcodeWithoutEmbeddedThumbnails" xml:space="preserve">
|
||||
<value>This G-code does not contain any embedded thumbnails.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -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.Gcode.Telemetry.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// A telemetry event to be raised when a svg file has been viewed in the preview pane.
|
||||
/// </summary>
|
||||
[EventData]
|
||||
public class GcodeFileHandlerLoaded : EventBase, IEvent
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// 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.Gcode.Telemetry.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// A telemetry event to be raised when an error has occurred in the preview pane.
|
||||
/// </summary>
|
||||
[EventData]
|
||||
public class GcodeFilePreviewError : EventBase, IEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the error message to log as part of the telemetry event.
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServicePerformance;
|
||||
}
|
||||
}
|
||||
@@ -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.Gcode.Telemetry.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// A telemetry event to be raised when a svg file has been viewed in the preview pane.
|
||||
/// </summary>
|
||||
[EventData]
|
||||
public class GcodeFilePreviewed : EventBase, IEvent
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text;
|
||||
using Common.ComInterlop;
|
||||
using Common.Utilities;
|
||||
|
||||
namespace Microsoft.PowerToys.ThumbnailHandler.Gcode
|
||||
{
|
||||
/// <summary>
|
||||
/// G-code Thumbnail Provider.
|
||||
/// </summary>
|
||||
[Guid("BFEE99B4-B74D-4348-BCA5-E757029647FF")]
|
||||
[ClassInterface(ClassInterfaceType.None)]
|
||||
[ComVisible(true)]
|
||||
public class GcodeThumbnailProvider : IInitializeWithStream, IThumbnailProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the stream object to access file.
|
||||
/// </summary>
|
||||
public IStream Stream { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum dimension (width or height) thumbnail we will generate.
|
||||
/// </summary>
|
||||
private const uint MaxThumbnailSize = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// Reads the G-code content searching for thumbnails and returns the largest.
|
||||
/// </summary>
|
||||
/// <param name="reader">The TextReader instance for the G-code content.</param>
|
||||
/// <param name="cx">The maximum thumbnail size, in pixels.</param>
|
||||
/// <returns>A thumbnail extracted from the G-code content.</returns>
|
||||
public static Bitmap GetThumbnail(TextReader reader, uint cx)
|
||||
{
|
||||
if (cx > MaxThumbnailSize || reader == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap thumbnail = null;
|
||||
|
||||
var bitmapBase64 = GetBase64Thumbnails(reader)
|
||||
.OrderByDescending(x => x.Length)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (!string.IsNullOrEmpty(bitmapBase64))
|
||||
{
|
||||
var bitmapBytes = Convert.FromBase64String(bitmapBase64);
|
||||
|
||||
using (var bitmapStream = new MemoryStream(bitmapBytes))
|
||||
{
|
||||
thumbnail = new Bitmap(bitmapStream);
|
||||
}
|
||||
|
||||
if (thumbnail.Width != cx && thumbnail.Height != cx)
|
||||
{
|
||||
// We are not the appropriate size for caller. Resize now while
|
||||
// respecting the aspect ratio.
|
||||
float scale = Math.Min((float)cx / thumbnail.Width, (float)cx / thumbnail.Height);
|
||||
int scaleWidth = (int)(thumbnail.Width * scale);
|
||||
int scaleHeight = (int)(thumbnail.Height * scale);
|
||||
thumbnail = ResizeImage(thumbnail, scaleWidth, scaleHeight);
|
||||
}
|
||||
}
|
||||
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all thumbnails in base64 format found on the G-code data.
|
||||
/// </summary>
|
||||
/// <param name="reader">The TextReader instance for the G-code content.</param>
|
||||
/// <returns>An enumeration of thumbnails in base64 format found on the G-code.</returns>
|
||||
private static IEnumerable<string> GetBase64Thumbnails(TextReader reader)
|
||||
{
|
||||
string line;
|
||||
StringBuilder capturedText = null;
|
||||
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.StartsWith("; thumbnail begin", StringComparison.InvariantCulture))
|
||||
{
|
||||
capturedText = new StringBuilder();
|
||||
}
|
||||
else if (line == "; thumbnail end")
|
||||
{
|
||||
if (capturedText != null)
|
||||
{
|
||||
yield return capturedText.ToString();
|
||||
|
||||
capturedText = null;
|
||||
}
|
||||
}
|
||||
else if (capturedText != null)
|
||||
{
|
||||
capturedText.Append(line[2..]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resize the image with high quality to the specified width and height.
|
||||
/// </summary>
|
||||
/// <param name="image">The image to resize.</param>
|
||||
/// <param name="width">The width to resize to.</param>
|
||||
/// <param name="height">The height to resize to.</param>
|
||||
/// <returns>The resized image.</returns>
|
||||
public static Bitmap ResizeImage(Image image, int width, int height)
|
||||
{
|
||||
if (width <= 0 ||
|
||||
height <= 0 ||
|
||||
width > MaxThumbnailSize ||
|
||||
height > MaxThumbnailSize ||
|
||||
image == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap destImage = new Bitmap(width, height);
|
||||
|
||||
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
|
||||
|
||||
using (var graphics = Graphics.FromImage(destImage))
|
||||
{
|
||||
graphics.CompositingMode = CompositingMode.SourceCopy;
|
||||
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
graphics.Clear(Color.White);
|
||||
graphics.DrawImage(image, 0, 0, width, height);
|
||||
}
|
||||
|
||||
return destImage;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Initialize(IStream pstream, uint grfMode)
|
||||
{
|
||||
// Ignore the grfMode always use read mode to access the file.
|
||||
this.Stream = pstream;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void GetThumbnail(uint cx, out IntPtr phbmp, out WTS_ALPHATYPE pdwAlpha)
|
||||
{
|
||||
phbmp = IntPtr.Zero;
|
||||
pdwAlpha = WTS_ALPHATYPE.WTSAT_UNKNOWN;
|
||||
|
||||
if (cx == 0 || cx > MaxThumbnailSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (var stream = new ReadonlyStream(this.Stream as IStream))
|
||||
{
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
using (Bitmap thumbnail = GetThumbnail(reader, cx))
|
||||
{
|
||||
if (thumbnail != null && thumbnail.Size.Width > 0 && thumbnail.Size.Height > 0)
|
||||
{
|
||||
phbmp = thumbnail.GetHbitmap();
|
||||
pdwAlpha = WTS_ALPHATYPE.WTSAT_RGB;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<PropertyGroup>
|
||||
<Platforms>x64</Platforms>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ProjectGuid>{809AA252-E17A-4FA2-B0A1-0450976B763F}</ProjectGuid>
|
||||
<RootNamespace>Microsoft.PowerToys.ThumbnailHandler.Gcode</RootNamespace>
|
||||
<AssemblyName>PowerToys.GcodeThumbnailProvider</AssemblyName>
|
||||
<AssemblyTitle>PowerToys.GcodeThumbnailProvider</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys GcodePreviewHandler</AssemblyDescription>
|
||||
<AssemblyCompany>Microsoft Corporation</AssemblyCompany>
|
||||
<AssemblyCopyright>Copyright (C) 2020 Microsoft Corporation</AssemblyCopyright>
|
||||
<AssemblyProduct>PowerToys</AssemblyProduct>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<EnableComHosting>true</EnableComHosting>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Company>Microsoft Corporation</Company>
|
||||
<Product>PowerToys</Product>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<Description>PowerToys GcodePreviewHandler</Description>
|
||||
<Copyright>Copyright (C) 2020 Microsoft Corporation</Copyright>
|
||||
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\</OutputPath>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.VersionCheckAnalyzer" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeQuality.Analyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NetCore.Analyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NetFramework.Analyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\codeAnalysis\GlobalSuppressions.cs" Link="GlobalSuppressions.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
<ProjectReference Include="..\Common\PreviewHandlerCommon.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="..\..\..\codeAnalysis\StyleCop.json">
|
||||
<Link>StyleCop.json</Link>
|
||||
</AdditionalFiles>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,91 @@
|
||||
// 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.Gcode;
|
||||
using Microsoft.PowerToys.STATestExtension;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
|
||||
namespace GcodePreviewHandlerUnitTests
|
||||
{
|
||||
[STATestClass]
|
||||
public class GcodePreviewHandlerTest
|
||||
{
|
||||
[TestMethod]
|
||||
public void GcodePreviewHandlerControlAddsControlsToFormWhenDoPreviewIsCalled()
|
||||
{
|
||||
// Arrange
|
||||
using (var gcodePreviewHandlerControl = new GcodePreviewHandlerControl())
|
||||
{
|
||||
// Act
|
||||
var file = File.ReadAllBytes("HelperFiles/sample.gcode");
|
||||
|
||||
gcodePreviewHandlerControl.DoPreview<IStream>(GetMockStream(file));
|
||||
|
||||
var flowLayoutPanel = gcodePreviewHandlerControl.Controls[0] as FlowLayoutPanel;
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(1, gcodePreviewHandlerControl.Controls.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GcodePreviewHandlerControlShouldAddValidInfoBarIfGcodePreviewThrows()
|
||||
{
|
||||
// Arrange
|
||||
using (var gcodePreviewHandlerControl = new GcodePreviewHandlerControl())
|
||||
{
|
||||
var mockStream = new Mock<IStream>();
|
||||
mockStream
|
||||
.Setup(x => x.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<IntPtr>()))
|
||||
.Throws(new Exception());
|
||||
|
||||
// Act
|
||||
gcodePreviewHandlerControl.DoPreview(mockStream.Object);
|
||||
var textBox = gcodePreviewHandlerControl.Controls[0] as RichTextBox;
|
||||
|
||||
// Assert
|
||||
Assert.IsFalse(string.IsNullOrWhiteSpace(textBox.Text));
|
||||
Assert.AreEqual(1, gcodePreviewHandlerControl.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<IStream>();
|
||||
int bytesRead = 0;
|
||||
|
||||
streamMock
|
||||
.Setup(x => x.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<IntPtr>()))
|
||||
.Callback<byte[], int, IntPtr>((buffer, countToRead, bytesReadPtr) =>
|
||||
{
|
||||
int actualCountToRead = Math.Min(sourceArray.Length - bytesRead, countToRead);
|
||||
if (actualCountToRead > 0)
|
||||
{
|
||||
Array.Copy(sourceArray, bytesRead, buffer, 0, actualCountToRead);
|
||||
Marshal.WriteInt32(bytesReadPtr, actualCountToRead);
|
||||
bytesRead += actualCountToRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
Marshal.WriteInt32(bytesReadPtr, 0);
|
||||
}
|
||||
});
|
||||
|
||||
return streamMock.Object;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Platforms>x64</Platforms>
|
||||
<AssemblyTitle>UnitTests-GcodePreviewHandler</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys UnitTests-GcodePreviewHandler</AssemblyDescription>
|
||||
<AssemblyCompany>Microsoft Corp.</AssemblyCompany>
|
||||
<AssemblyCopyright>Copyright (C) 2020 Microsoft Corp.</AssemblyCopyright>
|
||||
<AssemblyProduct>PowerToys</AssemblyProduct>
|
||||
<AssemblyTitle>UnitTests-GcodePreviewHandler</AssemblyTitle>
|
||||
<Company>Microsoft Corp.</Company>
|
||||
<Product>PowerToys</Product>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<Description>PowerToys UnitTests-GcodePreviewHandler</Description>
|
||||
<Copyright>Copyright (C) 2020 Microsoft Corp.</Copyright>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}</ProjectGuid>
|
||||
<RootNamespace>PdfPreviewHandlerUnitTests</RootNamespace>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||
<IsCodedUITest>False</IsCodedUITest>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="HelperFiles\sample.gcode" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.5" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.5" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\common\PreviewHandlerCommon.csproj" />
|
||||
<ProjectReference Include="..\GcodePreviewHandler\GcodePreviewHandler.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\codeAnalysis\GlobalSuppressions.cs" Link="GlobalSuppressions.cs" />
|
||||
<Content Include="HelperFiles\sample.gcode">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Compile Include="..\STATestClassAttribute.cs" Link="STATestClassAttribute.cs" />
|
||||
<Compile Include="..\STATestMethodAttribute.cs" Link="STATestMethodAttribute.cs" />
|
||||
<AdditionalFiles Include="..\..\..\codeAnalysis\StyleCop.json">
|
||||
<Link>StyleCop.json</Link>
|
||||
</AdditionalFiles>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,111 @@
|
||||
// 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 Common.ComInterlop;
|
||||
using Microsoft.PowerToys.STATestExtension;
|
||||
using Microsoft.PowerToys.ThumbnailHandler.Gcode;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
|
||||
namespace GcodeThumbnailProviderUnitTests
|
||||
{
|
||||
[STATestClass]
|
||||
public class GcodeThumbnailProviderTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void GetThumbnailValidStreamGcode()
|
||||
{
|
||||
// Act
|
||||
var file = File.ReadAllBytes("HelperFiles/sample.gcode");
|
||||
|
||||
GcodeThumbnailProvider provider = new GcodeThumbnailProvider();
|
||||
|
||||
provider.Initialize(GetMockStream(file), 0);
|
||||
|
||||
provider.GetThumbnail(256, out IntPtr bitmap, out WTS_ALPHATYPE alphaType);
|
||||
|
||||
Assert.IsTrue(bitmap != IntPtr.Zero);
|
||||
Assert.IsTrue(alphaType == WTS_ALPHATYPE.WTSAT_RGB);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetThumbnailInValidSizeGcode()
|
||||
{
|
||||
// Act
|
||||
var file = File.ReadAllBytes("HelperFiles/sample.gcode");
|
||||
|
||||
GcodeThumbnailProvider provider = new GcodeThumbnailProvider();
|
||||
|
||||
provider.Initialize(GetMockStream(file), 0);
|
||||
|
||||
provider.GetThumbnail(0, out IntPtr bitmap, out WTS_ALPHATYPE alphaType);
|
||||
|
||||
Assert.IsTrue(bitmap == IntPtr.Zero);
|
||||
Assert.IsTrue(alphaType == WTS_ALPHATYPE.WTSAT_UNKNOWN);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetThumbnailToBigGcode()
|
||||
{
|
||||
// Act
|
||||
var file = File.ReadAllBytes("HelperFiles/sample.gcode");
|
||||
|
||||
GcodeThumbnailProvider provider = new GcodeThumbnailProvider();
|
||||
|
||||
provider.Initialize(GetMockStream(file), 0);
|
||||
|
||||
provider.GetThumbnail(10001, out IntPtr bitmap, out WTS_ALPHATYPE alphaType);
|
||||
|
||||
Assert.IsTrue(bitmap == IntPtr.Zero);
|
||||
Assert.IsTrue(alphaType == WTS_ALPHATYPE.WTSAT_UNKNOWN);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CheckNoGcodeEmptyStringShouldReturnNullBitmap()
|
||||
{
|
||||
using (var reader = new StringReader(string.Empty))
|
||||
{
|
||||
Bitmap thumbnail = GcodeThumbnailProvider.GetThumbnail(reader, 256);
|
||||
Assert.IsTrue(thumbnail == null);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CheckNoGcodeNullStringShouldReturnNullBitmap()
|
||||
{
|
||||
Bitmap thumbnail = GcodeThumbnailProvider.GetThumbnail(null, 256);
|
||||
Assert.IsTrue(thumbnail == null);
|
||||
}
|
||||
|
||||
private static IStream GetMockStream(byte[] sourceArray)
|
||||
{
|
||||
var streamMock = new Mock<IStream>();
|
||||
int bytesRead = 0;
|
||||
|
||||
streamMock
|
||||
.Setup(x => x.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<IntPtr>()))
|
||||
.Callback<byte[], int, IntPtr>((buffer, countToRead, bytesReadPtr) =>
|
||||
{
|
||||
int actualCountToRead = Math.Min(sourceArray.Length - bytesRead, countToRead);
|
||||
if (actualCountToRead > 0)
|
||||
{
|
||||
Array.Copy(sourceArray, bytesRead, buffer, 0, actualCountToRead);
|
||||
Marshal.WriteInt32(bytesReadPtr, actualCountToRead);
|
||||
bytesRead += actualCountToRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
Marshal.WriteInt32(bytesReadPtr, 0);
|
||||
}
|
||||
});
|
||||
|
||||
return streamMock.Object;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Platforms>x64</Platforms>
|
||||
<AssemblyTitle>UnitTests-GcodeThumbnailProvider</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys UnitTests-GcodeThumbnailProvider</AssemblyDescription>
|
||||
<AssemblyCompany>Microsoft Corporation</AssemblyCompany>
|
||||
<AssemblyCopyright>Copyright (C) 2020 Microsoft Corporation</AssemblyCopyright>
|
||||
<AssemblyProduct>PowerToys</AssemblyProduct>
|
||||
<AssemblyTitle>UnitTests-GcodeThumbnailProvider</AssemblyTitle>
|
||||
<Company>Microsoft Corporation</Company>
|
||||
<Product>PowerToys</Product>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<Description>PowerToys UnitTests-GcodeThumbnailProvider</Description>
|
||||
<Copyright>Copyright (C) 2021 Microsoft Corporation</Copyright>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{133281D8-1BCE-4D07-B31E-796612A9609E}</ProjectGuid>
|
||||
<RootNamespace>GcodeThumbnailProviderUnitTests</RootNamespace>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||
<IsCodedUITest>False</IsCodedUITest>
|
||||
<TestProjectType>UnitTest</TestProjectType>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="HelperFiles\sample.gcode" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Castle.Core" Version="4.4.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.VersionCheckAnalyzer" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeQuality.Analyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NetCore.Analyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NetFramework.Analyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.5" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.5" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="5.0.0" />
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\PreviewHandlerCommon.csproj" />
|
||||
<ProjectReference Include="..\GcodeThumbnailProvider\GcodeThumbnailProvider.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\codeAnalysis\GlobalSuppressions.cs" Link="GlobalSuppressions.cs" />
|
||||
<Compile Include="..\STATestClassAttribute.cs" Link="STATestClassAttribute.cs" />
|
||||
<Compile Include="..\STATestMethodAttribute.cs" Link="STATestMethodAttribute.cs" />
|
||||
<AdditionalFiles Include="..\..\..\codeAnalysis\StyleCop.json">
|
||||
<Link>StyleCop.json</Link>
|
||||
</AdditionalFiles>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="HelperFiles\sample.gcode">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -30,11 +30,21 @@ const CLSID CLSID_SvgThumbnailProvider = { 0x36B27788, 0xA8BB, 0x4698, { 0xA7, 0
|
||||
|
||||
// BCC13D15-9720-4CC4-8371-EA74A274741E
|
||||
const GUID CLSID_PdfThumbnailProvider = { 0xbcc13d15, 0x9720, 0x4cc4, { 0x83, 0x71, 0xea, 0x74, 0xa2, 0x74, 0x74, 0x1e } };
|
||||
|
||||
// 516CB24F-562F-422F-8B01-6B580474D093
|
||||
const CLSID CLSID_SHIMActivateGcodePreviewHandler = { 0x516cb24f, 0x562f, 0x422f, { 0x8b, 0x1, 0x6b, 0x58, 0x4, 0x74, 0xd0, 0x93 } };
|
||||
|
||||
// ec52dea8-7c9f-4130-a77b-1737d0418507
|
||||
const CLSID CLSID_GcodePreviewHandler = { 0xec52dea8, 0x7c9f, 0x4130, { 0xa7, 0x7b, 0x17, 0x37, 0xd0, 0x41, 0x85, 0x07 } };
|
||||
|
||||
// BFEE99B4-B74D-4348-BCA5-E757029647FF
|
||||
const GUID CLSID_GcodeThumbnailProvider = { 0xbfee99b4, 0xb74d, 0x4348, { 0xbc, 0xa5, 0xe7, 0x57, 0x02, 0x96, 0x47, 0xff } };
|
||||
|
||||
// Pairs of NativeClsid vs ManagedClsid used for preview handlers.
|
||||
const std::vector<std::pair<CLSID, CLSID>> NativeToManagedClsid({
|
||||
{ CLSID_SHIMActivateMdPreviewHandler, CLSID_MdPreviewHandler },
|
||||
{ CLSID_SHIMActivatePdfPreviewHandler, CLSID_PdfPreviewHandler },
|
||||
{ CLSID_SHIMActivateGcodePreviewHandler, CLSID_GcodePreviewHandler },
|
||||
{ CLSID_SHIMActivateSvgPreviewHandler, CLSID_SvgPreviewHandler },
|
||||
{ CLSID_SHIMActivateSvgThumbnailProvider, CLSID_SvgThumbnailProvider }
|
||||
});
|
||||
@@ -177,4 +177,13 @@
|
||||
<data name="Pdf_Thumbnail_Provider_Settings_Description" xml:space="preserve">
|
||||
<value>Pdf Thumbnail Provider</value>
|
||||
</data>
|
||||
<data name="Gcode_Thumbnail_Provider_Settings_Description" xml:space="preserve">
|
||||
<value>G-code Thumbnail Provider</value>
|
||||
</data>
|
||||
<data name="Prevpane_Gcode_Settings_Description" xml:space="preserve">
|
||||
<value>G-code Previewer</value>
|
||||
</data>
|
||||
<data name="Prevpane_Gcode_Settings_Displayname" xml:space="preserve">
|
||||
<value>G-code Previewer</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -38,6 +38,10 @@ PowerPreviewModule::PowerPreviewModule() :
|
||||
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_PDF_SETTINGS_DESCRIPTION),
|
||||
.registryChanges = getPdfPreviewHandlerChangeSet(installationDir, installPerUser) });
|
||||
|
||||
m_fileExplorerModules.push_back({ .settingName = L"gcode-previewer-toggle-setting",
|
||||
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_GCODE_SETTINGS_DESCRIPTION),
|
||||
.registryChanges = getGcodePreviewHandlerChangeSet(installationDir, installPerUser) });
|
||||
|
||||
m_fileExplorerModules.push_back({ .settingName = L"svg-thumbnail-toggle-setting",
|
||||
.settingDescription = GET_RESOURCE_STRING(IDS_SVG_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
|
||||
.registryChanges = getSvgThumbnailHandlerChangeSet(installationDir, installPerUser) });
|
||||
@@ -45,6 +49,10 @@ PowerPreviewModule::PowerPreviewModule() :
|
||||
m_fileExplorerModules.push_back({ .settingName = L"pdf-thumbnail-toggle-setting",
|
||||
.settingDescription = GET_RESOURCE_STRING(IDS_PDF_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
|
||||
.registryChanges = getPdfThumbnailHandlerChangeSet(installationDir, installPerUser) });
|
||||
|
||||
m_fileExplorerModules.push_back({ .settingName = L"gcode-thumbnail-toggle-setting",
|
||||
.settingDescription = GET_RESOURCE_STRING(IDS_GCODE_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
|
||||
.registryChanges = getGcodeThumbnailHandlerChangeSet(installationDir, installPerUser) });
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -97,6 +97,40 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool enableGcodePreview = true;
|
||||
|
||||
[JsonPropertyName("gcode-previewer-toggle-setting")]
|
||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||
public bool EnableGcodePreview
|
||||
{
|
||||
get => enableGcodePreview;
|
||||
set
|
||||
{
|
||||
if (value != enableGcodePreview)
|
||||
{
|
||||
LogTelemetryEvent(value);
|
||||
enableGcodePreview = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool enableGcodeThumbnail = true;
|
||||
|
||||
[JsonPropertyName("gcode-thumbnail-toggle-setting")]
|
||||
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||
public bool EnableGcodeThumbnail
|
||||
{
|
||||
get => enableGcodeThumbnail;
|
||||
set
|
||||
{
|
||||
if (value != enableGcodeThumbnail)
|
||||
{
|
||||
LogTelemetryEvent(value);
|
||||
enableGcodeThumbnail = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PowerPreviewProperties()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -50,14 +50,18 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
_svgThumbnailIsEnabled = Settings.Properties.EnableSvgThumbnail;
|
||||
_mdRenderIsEnabled = Settings.Properties.EnableMdPreview;
|
||||
_pdfRenderIsEnabled = Settings.Properties.EnablePdfPreview;
|
||||
_gcodeRenderIsEnabled = Settings.Properties.EnableGcodePreview;
|
||||
_pdfThumbnailIsEnabled = Settings.Properties.EnablePdfThumbnail;
|
||||
_gcodeThumbnailIsEnabled = Settings.Properties.EnableGcodeThumbnail;
|
||||
}
|
||||
|
||||
private bool _svgRenderIsEnabled;
|
||||
private bool _mdRenderIsEnabled;
|
||||
private bool _pdfRenderIsEnabled;
|
||||
private bool _gcodeRenderIsEnabled;
|
||||
private bool _svgThumbnailIsEnabled;
|
||||
private bool _pdfThumbnailIsEnabled;
|
||||
private bool _gcodeThumbnailIsEnabled;
|
||||
|
||||
public bool SVGRenderIsEnabled
|
||||
{
|
||||
@@ -149,6 +153,42 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool GCODERenderIsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _gcodeRenderIsEnabled;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value != _gcodeRenderIsEnabled)
|
||||
{
|
||||
_gcodeRenderIsEnabled = value;
|
||||
Settings.Properties.EnableGcodePreview = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool GCODEThumbnailIsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _gcodeThumbnailIsEnabled;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value != _gcodeThumbnailIsEnabled)
|
||||
{
|
||||
_gcodeThumbnailIsEnabled = value;
|
||||
Settings.Properties.EnableGcodeThumbnail = value;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string GetSettingsSubPath()
|
||||
{
|
||||
return _settingsConfigFileFolder + "\\" + ModuleName;
|
||||
|
||||
@@ -58,9 +58,11 @@ namespace ViewModelTests
|
||||
Assert.AreEqual(originalGeneralSettings.IsElevated, viewModel.IsElevated);
|
||||
Assert.AreEqual(originalSettings.Properties.EnableMdPreview, viewModel.MDRenderIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnablePdfPreview, viewModel.PDFRenderIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnableGcodePreview, viewModel.GCODERenderIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnableSvgPreview, viewModel.SVGRenderIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnableSvgThumbnail, viewModel.SVGThumbnailIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnablePdfThumbnail, viewModel.PDFThumbnailIsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.EnableGcodeThumbnail, viewModel.GCODEThumbnailIsEnabled);
|
||||
|
||||
// Verify that the stub file was used
|
||||
var expectedCallCount = 2; // once via the view model, and once by the test (GetSettings<T>)
|
||||
@@ -121,6 +123,24 @@ namespace ViewModelTests
|
||||
viewModel.PDFThumbnailIsEnabled = true;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GCODEThumbnailIsEnabledShouldPrevHandlerWhenSuccessful()
|
||||
{
|
||||
// Assert
|
||||
Func<string, int> sendMockIPCConfigMSG = msg =>
|
||||
{
|
||||
SndModuleSettings<SndPowerPreviewSettings> snd = JsonSerializer.Deserialize<SndModuleSettings<SndPowerPreviewSettings>>(msg);
|
||||
Assert.IsTrue(snd.PowertoysSetting.FileExplorerPreviewSettings.Properties.EnableGcodeThumbnail);
|
||||
return 0;
|
||||
};
|
||||
|
||||
// arrange
|
||||
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, PowerPreviewSettings.ModuleName);
|
||||
|
||||
// act
|
||||
viewModel.GCODEThumbnailIsEnabled = true;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MDRenderIsEnabledShouldPrevHandlerWhenSuccessful()
|
||||
{
|
||||
@@ -156,5 +176,23 @@ namespace ViewModelTests
|
||||
// act
|
||||
viewModel.PDFRenderIsEnabled = true;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GCODERenderIsEnabledShouldPrevHandlerWhenSuccessful()
|
||||
{
|
||||
// Assert
|
||||
Func<string, int> sendMockIPCConfigMSG = msg =>
|
||||
{
|
||||
SndModuleSettings<SndPowerPreviewSettings> snd = JsonSerializer.Deserialize<SndModuleSettings<SndPowerPreviewSettings>>(msg);
|
||||
Assert.IsTrue(snd.PowertoysSetting.FileExplorerPreviewSettings.Properties.EnableGcodePreview);
|
||||
return 0;
|
||||
};
|
||||
|
||||
// arrange
|
||||
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, PowerPreviewSettings.ModuleName);
|
||||
|
||||
// act
|
||||
viewModel.GCODERenderIsEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1544,7 +1544,7 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
|
||||
<data name="EditButton.AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="ImageResizer_EditSize.AutomationProperties.Name" xml:space="preserve">
|
||||
<data name="ImageResizer_EditSize.AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Edit size</value>
|
||||
</data>
|
||||
<data name="No" xml:space="preserve">
|
||||
@@ -1828,4 +1828,18 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
|
||||
<data name="VideoConference_RunAsAdminRequired.Title" xml:space="preserve">
|
||||
<value>You need to run as administrator to modify these settings.</value>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_ToggleSwitch_GCODE_Thumbnail.Header" xml:space="preserve">
|
||||
<value>Enable G-code (.gcode) thumbnails</value>
|
||||
<comment>Do you want this feature on / off</comment>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_ToggleSwitch_GCODE_Thumbnail.Description" xml:space="preserve">
|
||||
<value>Only .gcode files with embedded thumbnails are supported</value>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_ToggleSwitch_Preview_GCODE.Description" xml:space="preserve">
|
||||
<value>Only .gcode files with embedded thumbnails are supported</value>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_ToggleSwitch_Preview_GCODE.Header" xml:space="preserve">
|
||||
<value>Enable G-code (.gcode) preview</value>
|
||||
<comment>Do you want this feature on / off</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -55,6 +55,13 @@
|
||||
IsEnabled="{Binding Mode=OneWay, Path=IsElevated}"/>
|
||||
</controls:Setting.ActionContent>
|
||||
</controls:Setting>
|
||||
|
||||
<controls:Setting x:Uid="FileExplorerPreview_ToggleSwitch_Preview_GCODE" Icon="">
|
||||
<controls:Setting.ActionContent>
|
||||
<ToggleSwitch IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.GCODERenderIsEnabled}"
|
||||
IsEnabled="{Binding Mode=OneWay, Path=IsElevated}"/>
|
||||
</controls:Setting.ActionContent>
|
||||
</controls:Setting>
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="FileExplorerPreview_IconThumbnail_GroupSettings">
|
||||
@@ -77,6 +84,13 @@
|
||||
IsEnabled="{Binding Mode=OneWay, Path=IsElevated}"/>
|
||||
</controls:Setting.ActionContent>
|
||||
</controls:Setting>
|
||||
|
||||
<controls:Setting x:Uid="FileExplorerPreview_ToggleSwitch_GCODE_Thumbnail" Icon="">
|
||||
<controls:Setting.ActionContent>
|
||||
<ToggleSwitch IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.GCODEThumbnailIsEnabled}"
|
||||
IsEnabled="{Binding Mode=OneWay, Path=IsElevated}"/>
|
||||
</controls:Setting.ActionContent>
|
||||
</controls:Setting>
|
||||
</controls:SettingsGroup>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
@@ -16,7 +16,9 @@ namespace
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{45769bcc-e8fd-42d0-947e-02beef77a1f5}" },
|
||||
{ HKEY_CLASSES_ROOT, L"AppID\\{CF142243-F059-45AF-8842-DBBE9783DB14}" },
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{07665729-6243-4746-95b7-79579308d1b2}" },
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{ec52dea8-7c9f-4130-a77b-1737d0418507}" },
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{BCC13D15-9720-4CC4-8371-EA74A274741E}" },
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{BFEE99B4-B74D-4348-BCA5-E757029647FF}" },
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{51B4D7E5-7568-4234-B4BB-47FB3C016A69}\\InprocServer32" },
|
||||
{ HKEY_CLASSES_ROOT, L"CLSID\\{0440049F-D1DC-4E46-B27B-98393D79486B}" },
|
||||
{ HKEY_CLASSES_ROOT, L"AllFileSystemObjects\\ShellEx\\ContextMenuHandlers\\PowerRenameExt" },
|
||||
@@ -25,13 +27,16 @@ namespace
|
||||
{ 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".pdf\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" },
|
||||
{ HKEY_CLASSES_ROOT, L".pdf\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" }
|
||||
{ HKEY_CLASSES_ROOT, L".pdf\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" },
|
||||
{ HKEY_CLASSES_ROOT, L".gcode\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" },
|
||||
{ HKEY_CLASSES_ROOT, L".gcode\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" }
|
||||
};
|
||||
|
||||
vector<tuple<HKEY, wstring, wstring>> 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\\Windows\\CurrentVersion\\PreviewHandlers", L"{ec52dea8-7c9f-4130-a77b-1737d0418507}" },
|
||||
{ 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" }
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user