[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:
Pedro Lamas
2021-12-10 11:53:01 +00:00
committed by GitHub
parent dfe9169e39
commit 1e0033166f
37 changed files with 56826 additions and 3 deletions

View File

@@ -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);
}
}
}

View File

@@ -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>

View File

@@ -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);
}
}
}

View File

@@ -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>

View File

@@ -0,0 +1,14 @@
{
"Projects": [
{
"LanguageSet": "Azure_Languages",
"LocItems": [
{
"SourceFile": "src\\modules\\previewpane\\GcodePreviewHandler\\Resources.resx",
"CopyOption": "LangIDOnName",
"OutputPath": "src\\modules\\previewpane\\GcodePreviewHandler"
}
]
}
]
}

View 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);
}
}
}
}

View 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>

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}