Implemented exporting received messages to Tapeti.Cmd compatible JSON file
This commit is contained in:
parent
785ddbd5b2
commit
2505dad190
16
PettingZoo.Core/Export/ExportFormatProvider.cs
Normal file
16
PettingZoo.Core/Export/ExportFormatProvider.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace PettingZoo.Core.Export
|
||||||
|
{
|
||||||
|
public class ExportFormatProvider : IExportFormatProvider
|
||||||
|
{
|
||||||
|
private readonly List<IExportFormat> formats;
|
||||||
|
|
||||||
|
public IEnumerable<IExportFormat> Formats => formats;
|
||||||
|
|
||||||
|
public ExportFormatProvider(params IExportFormat[] formats)
|
||||||
|
{
|
||||||
|
this.formats = new List<IExportFormat>(formats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
PettingZoo.Core/Export/IExportFormat.cs
Normal file
14
PettingZoo.Core/Export/IExportFormat.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using PettingZoo.Core.Connection;
|
||||||
|
|
||||||
|
namespace PettingZoo.Core.Export
|
||||||
|
{
|
||||||
|
public interface IExportFormat
|
||||||
|
{
|
||||||
|
public string Filter { get; }
|
||||||
|
|
||||||
|
public Task Export(Stream stream, IEnumerable<ReceivedMessageInfo> messages);
|
||||||
|
}
|
||||||
|
}
|
9
PettingZoo.Core/Export/IExportFormatProvider.cs
Normal file
9
PettingZoo.Core/Export/IExportFormatProvider.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace PettingZoo.Core.Export
|
||||||
|
{
|
||||||
|
public interface IExportFormatProvider
|
||||||
|
{
|
||||||
|
public IEnumerable<IExportFormat> Formats { get; }
|
||||||
|
}
|
||||||
|
}
|
119
PettingZoo.Tapeti/Export/TapetiCmdExportFormat.cs
Normal file
119
PettingZoo.Tapeti/Export/TapetiCmdExportFormat.cs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using PettingZoo.Core.Connection;
|
||||||
|
using PettingZoo.Core.Export;
|
||||||
|
|
||||||
|
namespace PettingZoo.Tapeti.Export
|
||||||
|
{
|
||||||
|
public class TapetiCmdExportFormat : IExportFormat
|
||||||
|
{
|
||||||
|
public string Filter => TapetiCmdExportStrings.TapetiCmdFilter;
|
||||||
|
|
||||||
|
|
||||||
|
private static readonly JsonSerializerSettings SerializerSettings = new()
|
||||||
|
{
|
||||||
|
NullValueHandling = NullValueHandling.Ignore
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public async Task Export(Stream stream, IEnumerable<ReceivedMessageInfo> messages)
|
||||||
|
{
|
||||||
|
await using var exportFile = new StreamWriter(stream, Encoding.UTF8);
|
||||||
|
|
||||||
|
foreach (var message in messages)
|
||||||
|
{
|
||||||
|
var serializableMessage = new SerializableMessage
|
||||||
|
{
|
||||||
|
Exchange = message.Exchange,
|
||||||
|
RoutingKey = message.RoutingKey,
|
||||||
|
Properties = new SerializableMessageProperties
|
||||||
|
{
|
||||||
|
AppId = message.Properties.AppId,
|
||||||
|
ContentEncoding = message.Properties.ContentEncoding,
|
||||||
|
ContentType = message.Properties.ContentType,
|
||||||
|
CorrelationId = message.Properties.CorrelationId,
|
||||||
|
DeliveryMode = message.Properties.DeliveryMode switch
|
||||||
|
{
|
||||||
|
MessageDeliveryMode.Persistent => 2,
|
||||||
|
_ => 1
|
||||||
|
},
|
||||||
|
Expiration = message.Properties.Expiration,
|
||||||
|
Headers = message.Properties.Headers.Count > 0 ? message.Properties.Headers.ToDictionary(p => p.Key, p => p.Value) : null,
|
||||||
|
MessageId = message.Properties.MessageId,
|
||||||
|
Priority = message.Properties.Priority,
|
||||||
|
ReplyTo = message.Properties.ReplyTo,
|
||||||
|
Timestamp = message.Properties.Timestamp.HasValue ? new DateTimeOffset(message.Properties.Timestamp.Value).ToUnixTimeSeconds() : null,
|
||||||
|
Type = message.Properties.Type,
|
||||||
|
UserId = message.Properties.UserId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var useRawBody = true;
|
||||||
|
if (message.Properties.ContentType == @"application/json")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (JToken.Parse(Encoding.UTF8.GetString(message.Body)) is JObject jsonBody)
|
||||||
|
{
|
||||||
|
serializableMessage.Body = jsonBody;
|
||||||
|
useRawBody = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Use raw body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useRawBody)
|
||||||
|
serializableMessage.RawBody = message.Body;
|
||||||
|
|
||||||
|
var serialized = JsonConvert.SerializeObject(serializableMessage, SerializerSettings);
|
||||||
|
await exportFile.WriteLineAsync(serialized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// It would be nicer if Tapeti.Cmd exposed it's file format in a NuGet package... if only I knew the author ¯\_(ツ)_/¯
|
||||||
|
public class SerializableMessage
|
||||||
|
{
|
||||||
|
//public ulong DeliveryTag;
|
||||||
|
//public bool Redelivered;
|
||||||
|
public string? Exchange;
|
||||||
|
public string? RoutingKey;
|
||||||
|
//public string? Queue;
|
||||||
|
|
||||||
|
// ReSharper disable once FieldCanBeMadeReadOnly.Local - must be settable by JSON deserialization
|
||||||
|
public SerializableMessageProperties? Properties;
|
||||||
|
|
||||||
|
public JObject? Body;
|
||||||
|
public byte[]? RawBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class SerializableMessageProperties
|
||||||
|
{
|
||||||
|
public string? AppId;
|
||||||
|
//public string? ClusterId;
|
||||||
|
public string? ContentEncoding;
|
||||||
|
public string? ContentType;
|
||||||
|
public string? CorrelationId;
|
||||||
|
public byte? DeliveryMode;
|
||||||
|
public string? Expiration;
|
||||||
|
public IDictionary<string, string>? Headers;
|
||||||
|
public string? MessageId;
|
||||||
|
public byte? Priority;
|
||||||
|
public string? ReplyTo;
|
||||||
|
public long? Timestamp;
|
||||||
|
public string? Type;
|
||||||
|
public string? UserId;
|
||||||
|
}
|
||||||
|
}
|
72
PettingZoo.Tapeti/Export/TapetiCmdExportStrings.Designer.cs
generated
Normal file
72
PettingZoo.Tapeti/Export/TapetiCmdExportStrings.Designer.cs
generated
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <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 PettingZoo.Tapeti.Export {
|
||||||
|
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 TapetiCmdExportStrings {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal TapetiCmdExportStrings() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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("PettingZoo.Tapeti.Export.TapetiCmdExportStrings", typeof(TapetiCmdExportStrings).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 Tapeti.Cmd single-file JSON (*.json)|*.json.
|
||||||
|
/// </summary>
|
||||||
|
internal static string TapetiCmdFilter {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TapetiCmdFilter", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
123
PettingZoo.Tapeti/Export/TapetiCmdExportStrings.resx
Normal file
123
PettingZoo.Tapeti/Export/TapetiCmdExportStrings.resx
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<?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=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="TapetiCmdFilter" xml:space="preserve">
|
||||||
|
<value>Tapeti.Cmd single-file JSON (*.json)|*.json</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
@ -32,6 +32,11 @@
|
|||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
<DependentUpon>AssemblyParserStrings.resx</DependentUpon>
|
<DependentUpon>AssemblyParserStrings.resx</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Update="Export\TapetiCmdExportStrings.Designer.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>TapetiCmdExportStrings.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Update="UI\ClassSelection\ClassSelectionStrings.Designer.cs">
|
<Compile Update="UI\ClassSelection\ClassSelectionStrings.Designer.cs">
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
@ -57,6 +62,10 @@
|
|||||||
<Generator>ResXFileCodeGenerator</Generator>
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
<LastGenOutput>AssemblyParserStrings.Designer.cs</LastGenOutput>
|
<LastGenOutput>AssemblyParserStrings.Designer.cs</LastGenOutput>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Update="Export\TapetiCmdExportStrings.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>TapetiCmdExportStrings.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Update="UI\ClassSelection\ClassSelectionStrings.resx">
|
<EmbeddedResource Update="UI\ClassSelection\ClassSelectionStrings.resx">
|
||||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||||
<LastGenOutput>ClassSelectionStrings.Designer.cs</LastGenOutput>
|
<LastGenOutput>ClassSelectionStrings.Designer.cs</LastGenOutput>
|
||||||
|
@ -34,8 +34,6 @@ namespace PettingZoo.Tapeti
|
|||||||
.WithSourcesFrom(Path.Combine(PettingZooPaths.InstallationRoot, @"nuget.config"))
|
.WithSourcesFrom(Path.Combine(PettingZooPaths.InstallationRoot, @"nuget.config"))
|
||||||
.WithSourcesFrom(Path.Combine(PettingZooPaths.AppDataRoot, @"nuget.config"));
|
.WithSourcesFrom(Path.Combine(PettingZooPaths.AppDataRoot, @"nuget.config"));
|
||||||
|
|
||||||
var dispatcher = Dispatcher.CurrentDispatcher;
|
|
||||||
|
|
||||||
var viewModel = new PackageSelectionViewModel(packageManager);
|
var viewModel = new PackageSelectionViewModel(packageManager);
|
||||||
var selectionWindow = new PackageSelectionWindow(viewModel)
|
var selectionWindow = new PackageSelectionWindow(viewModel)
|
||||||
{
|
{
|
||||||
@ -44,7 +42,7 @@ namespace PettingZoo.Tapeti
|
|||||||
|
|
||||||
viewModel.Select += (_, args) =>
|
viewModel.Select += (_, args) =>
|
||||||
{
|
{
|
||||||
dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
var windowBounds = selectionWindow.RestoreBounds;
|
var windowBounds = selectionWindow.RestoreBounds;
|
||||||
selectionWindow.Close();
|
selectionWindow.Close();
|
||||||
@ -65,7 +63,7 @@ namespace PettingZoo.Tapeti
|
|||||||
// var classes =
|
// var classes =
|
||||||
var examples = LoadExamples(assemblies);
|
var examples = LoadExamples(assemblies);
|
||||||
|
|
||||||
dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
progressWindow.Close();
|
progressWindow.Close();
|
||||||
progressWindow = null;
|
progressWindow = null;
|
||||||
@ -90,7 +88,7 @@ namespace PettingZoo.Tapeti
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
// ReSharper disable once ConstantConditionalAccessQualifier - if I remove it, there's a "Dereference of a possibly null reference" warning instead
|
// ReSharper disable once ConstantConditionalAccessQualifier - if I remove it, there's a "Dereference of a possibly null reference" warning instead
|
||||||
progressWindow?.Close();
|
progressWindow?.Close();
|
||||||
|
23
PettingZoo/Images/Export.svg
Normal file
23
PettingZoo/Images/Export.svg
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 58 58" style="enable-background:new 0 0 58 58;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<polygon style="fill:#EFEBDE;" points="46.5,14 32.5,0 1.5,0 1.5,58 46.5,58 "/>
|
||||||
|
<g>
|
||||||
|
<path style="fill:#D5D0BB;" d="M11.5,23h25c0.552,0,1-0.447,1-1s-0.448-1-1-1h-25c-0.552,0-1,0.447-1,1S10.948,23,11.5,23z"/>
|
||||||
|
<path style="fill:#D5D0BB;" d="M11.5,15h10c0.552,0,1-0.447,1-1s-0.448-1-1-1h-10c-0.552,0-1,0.447-1,1S10.948,15,11.5,15z"/>
|
||||||
|
<path style="fill:#D5D0BB;" d="M36.5,29h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S37.052,29,36.5,29z"/>
|
||||||
|
<path style="fill:#D5D0BB;" d="M36.5,37h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S37.052,37,36.5,37z"/>
|
||||||
|
<path style="fill:#D5D0BB;" d="M36.5,45h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S37.052,45,36.5,45z"/>
|
||||||
|
</g>
|
||||||
|
<polygon style="fill:#D5D0BB;" points="32.5,0 32.5,14 46.5,14 "/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<rect x="34.5" y="36" style="fill:#21AE5E;" width="22" height="22"/>
|
||||||
|
<rect x="44.5" y="37.586" style="fill:#FFFFFF;" width="2" height="16"/>
|
||||||
|
<polygon style="fill:#FFFFFF;" points="45.5,55 38.5,48.293 39.976,46.879 45.5,52.172 51.024,46.879 52.5,48.293 "/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
23
PettingZoo/Images/Import.svg
Normal file
23
PettingZoo/Images/Import.svg
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 58 58" style="enable-background:new 0 0 58 58;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<polygon style="fill:#EFEBDE;" points="46,14 32,0 1,0 1,58 46,58 "/>
|
||||||
|
<g>
|
||||||
|
<path style="fill:#D5D0BB;" d="M11,23h25c0.552,0,1-0.447,1-1s-0.448-1-1-1H11c-0.552,0-1,0.447-1,1S10.448,23,11,23z"/>
|
||||||
|
<path style="fill:#D5D0BB;" d="M11,15h10c0.552,0,1-0.447,1-1s-0.448-1-1-1H11c-0.552,0-1,0.447-1,1S10.448,15,11,15z"/>
|
||||||
|
<path style="fill:#D5D0BB;" d="M36,29H11c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S36.552,29,36,29z"/>
|
||||||
|
<path style="fill:#D5D0BB;" d="M36,37H11c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S36.552,37,36,37z"/>
|
||||||
|
<path style="fill:#D5D0BB;" d="M36,45H11c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S36.552,45,36,45z"/>
|
||||||
|
</g>
|
||||||
|
<polygon style="fill:#D5D0BB;" points="32,0 32,14 46,14 "/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<rect x="35" y="36" style="fill:#48A0DC;" width="22" height="22"/>
|
||||||
|
<rect x="45" y="42" style="fill:#FFFFFF;" width="2" height="16"/>
|
||||||
|
<polygon style="fill:#FFFFFF;" points="51.293,48.707 46,43.414 40.707,48.707 39.293,47.293 46,40.586 52.707,47.293 "/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
@ -23,7 +23,9 @@
|
|||||||
<None Remove="Images\Dock.svg" />
|
<None Remove="Images\Dock.svg" />
|
||||||
<None Remove="Images\Error.svg" />
|
<None Remove="Images\Error.svg" />
|
||||||
<None Remove="Images\Example.svg" />
|
<None Remove="Images\Example.svg" />
|
||||||
|
<None Remove="Images\Export.svg" />
|
||||||
<None Remove="Images\Folder.svg" />
|
<None Remove="Images\Folder.svg" />
|
||||||
|
<None Remove="Images\Import.svg" />
|
||||||
<None Remove="Images\Ok.svg" />
|
<None Remove="Images\Ok.svg" />
|
||||||
<None Remove="Images\PublishSend.svg" />
|
<None Remove="Images\PublishSend.svg" />
|
||||||
<None Remove="Images\Undock.svg" />
|
<None Remove="Images\Undock.svg" />
|
||||||
@ -36,7 +38,9 @@
|
|||||||
<Resource Include="Images\Dock.svg" />
|
<Resource Include="Images\Dock.svg" />
|
||||||
<Resource Include="Images\Error.svg" />
|
<Resource Include="Images\Error.svg" />
|
||||||
<Resource Include="Images\Example.svg" />
|
<Resource Include="Images\Example.svg" />
|
||||||
|
<Resource Include="Images\Export.svg" />
|
||||||
<Resource Include="Images\Folder.svg" />
|
<Resource Include="Images\Folder.svg" />
|
||||||
|
<Resource Include="Images\Import.svg" />
|
||||||
<Resource Include="Images\Ok.svg" />
|
<Resource Include="Images\Ok.svg" />
|
||||||
<Resource Include="Images\Publish.svg" />
|
<Resource Include="Images\Publish.svg" />
|
||||||
<Resource Include="Images\PublishSend.svg" />
|
<Resource Include="Images\PublishSend.svg" />
|
||||||
|
@ -4,14 +4,17 @@ using System.IO;
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Markup;
|
using System.Windows.Markup;
|
||||||
using PettingZoo.Core.Connection;
|
using PettingZoo.Core.Connection;
|
||||||
|
using PettingZoo.Core.Export;
|
||||||
using PettingZoo.Core.Generator;
|
using PettingZoo.Core.Generator;
|
||||||
using PettingZoo.Core.Settings;
|
using PettingZoo.Core.Settings;
|
||||||
using PettingZoo.RabbitMQ;
|
using PettingZoo.RabbitMQ;
|
||||||
using PettingZoo.Settings.LiteDB;
|
using PettingZoo.Settings.LiteDB;
|
||||||
using PettingZoo.Tapeti;
|
using PettingZoo.Tapeti;
|
||||||
|
using PettingZoo.Tapeti.Export;
|
||||||
using PettingZoo.UI.Connection;
|
using PettingZoo.UI.Connection;
|
||||||
using PettingZoo.UI.Main;
|
using PettingZoo.UI.Main;
|
||||||
using PettingZoo.UI.Subscribe;
|
using PettingZoo.UI.Subscribe;
|
||||||
|
using PettingZoo.UI.Tab;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using SimpleInjector;
|
using SimpleInjector;
|
||||||
|
|
||||||
@ -79,6 +82,10 @@ namespace PettingZoo
|
|||||||
container.Register<IConnectionSettingsRepository, LiteDBConnectionSettingsRepository>();
|
container.Register<IConnectionSettingsRepository, LiteDBConnectionSettingsRepository>();
|
||||||
container.Register<IUISettingsRepository, LiteDBUISettingsRepository>();
|
container.Register<IUISettingsRepository, LiteDBUISettingsRepository>();
|
||||||
container.Register<IExampleGenerator, TapetiClassLibraryExampleGenerator>();
|
container.Register<IExampleGenerator, TapetiClassLibraryExampleGenerator>();
|
||||||
|
container.Register<ITabHostProvider, TabHostProvider>();
|
||||||
|
container.Register<ITabFactory, ViewTabFactory>();
|
||||||
|
|
||||||
|
container.RegisterInstance<IExportFormatProvider>(new ExportFormatProvider(new TapetiCmdExportFormat()));
|
||||||
|
|
||||||
container.Register<MainWindow>();
|
container.Register<MainWindow>();
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
Should-have
|
Should-have
|
||||||
-----------
|
-----------
|
||||||
- Save / load publisher messages (either as templates or to disk)
|
- Save / load publisher messages (either as templates or to disk)
|
||||||
- Tapeti: export received messages to Tapeti.Cmd JSON file / Tapeti.Cmd command-line
|
|
||||||
- Tapeti: import Tapeti.Cmd JSON file into Subscriber-esque tab for easier browsing
|
- Tapeti: import Tapeti.Cmd JSON file into Subscriber-esque tab for easier browsing
|
||||||
- Tapeti: fetch NuGet dependencies to improve the chances of succesfully loading the assembly, instead of the current "extraAssembliesPaths" workaround
|
- Tapeti: fetch NuGet dependencies to improve the chances of succesfully loading the assembly, instead of the current "extraAssembliesPaths" workaround
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ using System.Windows.Controls;
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using PettingZoo.Core.Connection;
|
using PettingZoo.Core.Connection;
|
||||||
using PettingZoo.Core.Generator;
|
|
||||||
using PettingZoo.UI.Connection;
|
using PettingZoo.UI.Connection;
|
||||||
using PettingZoo.UI.Subscribe;
|
using PettingZoo.UI.Subscribe;
|
||||||
using PettingZoo.UI.Tab;
|
using PettingZoo.UI.Tab;
|
||||||
@ -20,11 +19,12 @@ namespace PettingZoo.UI.Main
|
|||||||
public bool WasMaximized;
|
public bool WasMaximized;
|
||||||
|
|
||||||
|
|
||||||
public MainWindow(IConnectionFactory connectionFactory, IConnectionDialog connectionDialog, ISubscribeDialog subscribeDialog, IExampleGenerator exampleGenerator)
|
public MainWindow(IConnectionFactory connectionFactory, IConnectionDialog connectionDialog, ISubscribeDialog subscribeDialog,
|
||||||
|
ITabHostProvider tabHostProvider, ITabFactory tabFactory)
|
||||||
{
|
{
|
||||||
WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
||||||
|
|
||||||
viewModel = new MainWindowViewModel(connectionFactory, connectionDialog, subscribeDialog, this, exampleGenerator)
|
viewModel = new MainWindowViewModel(connectionFactory, connectionDialog, subscribeDialog, this, tabHostProvider, tabFactory)
|
||||||
{
|
{
|
||||||
TabHostWindow = this
|
TabHostWindow = this
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,6 @@ using System.Threading.Tasks;
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using PettingZoo.Core.Connection;
|
using PettingZoo.Core.Connection;
|
||||||
using PettingZoo.Core.Generator;
|
|
||||||
using PettingZoo.UI.Connection;
|
using PettingZoo.UI.Connection;
|
||||||
using PettingZoo.UI.Subscribe;
|
using PettingZoo.UI.Subscribe;
|
||||||
using PettingZoo.UI.Tab;
|
using PettingZoo.UI.Tab;
|
||||||
@ -29,6 +28,7 @@ namespace PettingZoo.UI.Main
|
|||||||
private readonly IConnectionDialog connectionDialog;
|
private readonly IConnectionDialog connectionDialog;
|
||||||
private readonly ISubscribeDialog subscribeDialog;
|
private readonly ISubscribeDialog subscribeDialog;
|
||||||
private readonly ITabContainer tabContainer;
|
private readonly ITabContainer tabContainer;
|
||||||
|
private readonly ITabHostProvider tabHostProvider;
|
||||||
private readonly ITabFactory tabFactory;
|
private readonly ITabFactory tabFactory;
|
||||||
|
|
||||||
private SubscribeDialogParams? subscribeDialogParams;
|
private SubscribeDialogParams? subscribeDialogParams;
|
||||||
@ -103,12 +103,16 @@ namespace PettingZoo.UI.Main
|
|||||||
|
|
||||||
|
|
||||||
public MainWindowViewModel(IConnectionFactory connectionFactory, IConnectionDialog connectionDialog,
|
public MainWindowViewModel(IConnectionFactory connectionFactory, IConnectionDialog connectionDialog,
|
||||||
ISubscribeDialog subscribeDialog, ITabContainer tabContainer, IExampleGenerator exampleGenerator)
|
ISubscribeDialog subscribeDialog, ITabContainer tabContainer, ITabHostProvider tabHostProvider, ITabFactory tabFactory)
|
||||||
{
|
{
|
||||||
|
tabHostProvider.SetInstance(this);
|
||||||
|
|
||||||
this.connectionFactory = connectionFactory;
|
this.connectionFactory = connectionFactory;
|
||||||
this.connectionDialog = connectionDialog;
|
this.connectionDialog = connectionDialog;
|
||||||
this.subscribeDialog = subscribeDialog;
|
this.subscribeDialog = subscribeDialog;
|
||||||
this.tabContainer = tabContainer;
|
this.tabContainer = tabContainer;
|
||||||
|
this.tabHostProvider = tabHostProvider;
|
||||||
|
this.tabFactory = tabFactory;
|
||||||
|
|
||||||
connectionStatus = GetConnectionStatus(null);
|
connectionStatus = GetConnectionStatus(null);
|
||||||
connectionStatusType = ConnectionStatusType.Error;
|
connectionStatusType = ConnectionStatusType.Error;
|
||||||
@ -120,8 +124,6 @@ namespace PettingZoo.UI.Main
|
|||||||
subscribeCommand = new DelegateCommand(SubscribeExecute, IsConnectedCanExecute);
|
subscribeCommand = new DelegateCommand(SubscribeExecute, IsConnectedCanExecute);
|
||||||
closeTabCommand = new DelegateCommand(CloseTabExecute, HasActiveTabCanExecute);
|
closeTabCommand = new DelegateCommand(CloseTabExecute, HasActiveTabCanExecute);
|
||||||
undockTabCommand = new DelegateCommand(UndockTabExecute, HasActiveTabCanExecute);
|
undockTabCommand = new DelegateCommand(UndockTabExecute, HasActiveTabCanExecute);
|
||||||
|
|
||||||
tabFactory = new ViewTabFactory(this, exampleGenerator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -226,7 +228,7 @@ namespace PettingZoo.UI.Main
|
|||||||
if (tab == null)
|
if (tab == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var tabHostWindow = UndockedTabHostWindow.Create(this, tab, tabContainer.TabWidth, tabContainer.TabHeight);
|
var tabHostWindow = UndockedTabHostWindow.Create(tabHostProvider, tab, tabContainer.TabWidth, tabContainer.TabHeight);
|
||||||
undockedTabs.Add(tab, tabHostWindow);
|
undockedTabs.Add(tab, tabHostWindow);
|
||||||
|
|
||||||
tabHostWindow.Show();
|
tabHostWindow.Show();
|
||||||
@ -330,7 +332,7 @@ namespace PettingZoo.UI.Main
|
|||||||
|
|
||||||
public class DesignTimeMainWindowViewModel : MainWindowViewModel
|
public class DesignTimeMainWindowViewModel : MainWindowViewModel
|
||||||
{
|
{
|
||||||
public DesignTimeMainWindowViewModel() : base(null!, null!, null!, null!, null!)
|
public DesignTimeMainWindowViewModel() : base(null!, null!, null!, null!, null!, null!)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
PettingZoo/UI/Tab/ITabHostProvider.cs
Normal file
9
PettingZoo/UI/Tab/ITabHostProvider.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace PettingZoo.UI.Tab
|
||||||
|
{
|
||||||
|
public interface ITabHostProvider
|
||||||
|
{
|
||||||
|
public ITabHost Instance { get; }
|
||||||
|
|
||||||
|
public void SetInstance(ITabHost instance);
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,7 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
private readonly IConnection connection;
|
private readonly IConnection connection;
|
||||||
private readonly IExampleGenerator exampleGenerator;
|
private readonly IExampleGenerator exampleGenerator;
|
||||||
private readonly ITabFactory tabFactory;
|
private readonly ITabFactory tabFactory;
|
||||||
private readonly ITabHost tabHost;
|
private readonly ITabHostProvider tabHostProvider;
|
||||||
|
|
||||||
private bool sendToExchange = true;
|
private bool sendToExchange = true;
|
||||||
private string exchange = "";
|
private string exchange = "";
|
||||||
@ -156,12 +156,12 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
string IPublishDestination.RoutingKey => SendToExchange ? RoutingKey : Queue;
|
string IPublishDestination.RoutingKey => SendToExchange ? RoutingKey : Queue;
|
||||||
|
|
||||||
|
|
||||||
public PublisherViewModel(ITabHost tabHost, ITabFactory tabFactory, IConnection connection, IExampleGenerator exampleGenerator, ReceivedMessageInfo? fromReceivedMessage = null)
|
public PublisherViewModel(ITabHostProvider tabHostProvider, ITabFactory tabFactory, IConnection connection, IExampleGenerator exampleGenerator, ReceivedMessageInfo? fromReceivedMessage = null)
|
||||||
{
|
{
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.exampleGenerator = exampleGenerator;
|
this.exampleGenerator = exampleGenerator;
|
||||||
this.tabFactory = tabFactory;
|
this.tabFactory = tabFactory;
|
||||||
this.tabHost = tabHost;
|
this.tabHostProvider = tabHostProvider;
|
||||||
|
|
||||||
publishCommand = new DelegateCommand(PublishExecute, PublishCanExecute);
|
publishCommand = new DelegateCommand(PublishExecute, PublishCanExecute);
|
||||||
|
|
||||||
@ -287,7 +287,7 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
|
|
||||||
var subscriber = connection.Subscribe();
|
var subscriber = connection.Subscribe();
|
||||||
var tab = tabFactory.CreateSubscriberTab(connection, subscriber);
|
var tab = tabFactory.CreateSubscriberTab(connection, subscriber);
|
||||||
tabHost.AddTab(tab);
|
tabHostProvider.Instance.AddTab(tab);
|
||||||
|
|
||||||
subscriber.Start();
|
subscriber.Start();
|
||||||
return subscriber.QueueName;
|
return subscriber.QueueName;
|
||||||
|
@ -124,7 +124,7 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
{
|
{
|
||||||
exampleGenerator.Select(tabHostWindow, example =>
|
exampleGenerator.Select(tabHostWindow, example =>
|
||||||
{
|
{
|
||||||
Dispatcher.CurrentDispatcher.BeginInvoke(() =>
|
Application.Current.Dispatcher.BeginInvoke(() =>
|
||||||
{
|
{
|
||||||
switch (example)
|
switch (example)
|
||||||
{
|
{
|
||||||
|
@ -1,26 +1,33 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Threading;
|
using Microsoft.Win32;
|
||||||
using PettingZoo.Core.Connection;
|
using PettingZoo.Core.Connection;
|
||||||
|
using PettingZoo.Core.Export;
|
||||||
using PettingZoo.Core.Rendering;
|
using PettingZoo.Core.Rendering;
|
||||||
using PettingZoo.WPF.ViewModel;
|
using PettingZoo.WPF.ViewModel;
|
||||||
|
using Serilog;
|
||||||
|
using IConnection = PettingZoo.Core.Connection.IConnection;
|
||||||
|
|
||||||
namespace PettingZoo.UI.Tab.Subscriber
|
namespace PettingZoo.UI.Tab.Subscriber
|
||||||
{
|
{
|
||||||
public class SubscriberViewModel : BaseViewModel, ITabToolbarCommands, ITabActivate
|
public class SubscriberViewModel : BaseViewModel, ITabToolbarCommands, ITabActivate
|
||||||
{
|
{
|
||||||
private readonly ITabHost tabHost;
|
private readonly ILogger logger;
|
||||||
|
private readonly ITabHostProvider tabHostProvider;
|
||||||
private readonly ITabFactory tabFactory;
|
private readonly ITabFactory tabFactory;
|
||||||
private readonly IConnection connection;
|
private readonly IConnection connection;
|
||||||
private readonly ISubscriber subscriber;
|
private readonly ISubscriber subscriber;
|
||||||
private readonly Dispatcher dispatcher;
|
private readonly IExportFormatProvider exportFormatProvider;
|
||||||
private ReceivedMessageInfo? selectedMessage;
|
private ReceivedMessageInfo? selectedMessage;
|
||||||
private readonly DelegateCommand clearCommand;
|
private readonly DelegateCommand clearCommand;
|
||||||
|
private readonly DelegateCommand exportCommand;
|
||||||
private readonly TabToolbarCommand[] toolbarCommands;
|
private readonly TabToolbarCommand[] toolbarCommands;
|
||||||
private IDictionary<string, string>? selectedMessageProperties;
|
private IDictionary<string, string>? selectedMessageProperties;
|
||||||
|
|
||||||
@ -32,6 +39,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
|||||||
|
|
||||||
|
|
||||||
public ICommand ClearCommand => clearCommand;
|
public ICommand ClearCommand => clearCommand;
|
||||||
|
public ICommand ExportCommand => exportCommand;
|
||||||
|
|
||||||
// ReSharper disable once UnusedMember.Global - it is, but via a proxy
|
// ReSharper disable once UnusedMember.Global - it is, but via a proxy
|
||||||
public ICommand CreatePublisherCommand => createPublisherCommand;
|
public ICommand CreatePublisherCommand => createPublisherCommand;
|
||||||
@ -70,22 +78,25 @@ namespace PettingZoo.UI.Tab.Subscriber
|
|||||||
public IEnumerable<TabToolbarCommand> ToolbarCommands => toolbarCommands;
|
public IEnumerable<TabToolbarCommand> ToolbarCommands => toolbarCommands;
|
||||||
|
|
||||||
|
|
||||||
public SubscriberViewModel(ITabHost tabHost, ITabFactory tabFactory, IConnection connection, ISubscriber subscriber)
|
public SubscriberViewModel(ILogger logger, ITabHostProvider tabHostProvider, ITabFactory tabFactory, IConnection connection, ISubscriber subscriber, IExportFormatProvider exportFormatProvider)
|
||||||
{
|
{
|
||||||
this.tabHost = tabHost;
|
this.logger = logger;
|
||||||
|
this.tabHostProvider = tabHostProvider;
|
||||||
this.tabFactory = tabFactory;
|
this.tabFactory = tabFactory;
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.subscriber = subscriber;
|
this.subscriber = subscriber;
|
||||||
|
this.exportFormatProvider = exportFormatProvider;
|
||||||
dispatcher = Dispatcher.CurrentDispatcher;
|
|
||||||
|
|
||||||
Messages = new ObservableCollectionEx<ReceivedMessageInfo>();
|
Messages = new ObservableCollectionEx<ReceivedMessageInfo>();
|
||||||
UnreadMessages = new ObservableCollectionEx<ReceivedMessageInfo>();
|
UnreadMessages = new ObservableCollectionEx<ReceivedMessageInfo>();
|
||||||
clearCommand = new DelegateCommand(ClearExecute, ClearCanExecute);
|
|
||||||
|
clearCommand = new DelegateCommand(ClearExecute, HasMessagesCanExecute);
|
||||||
|
exportCommand = new DelegateCommand(ExportExecute, HasMessagesCanExecute);
|
||||||
|
|
||||||
toolbarCommands = new[]
|
toolbarCommands = new[]
|
||||||
{
|
{
|
||||||
new TabToolbarCommand(ClearCommand, SubscriberViewStrings.CommandClear, SvgIconHelper.LoadFromResource("/Images/Clear.svg"))
|
new TabToolbarCommand(ClearCommand, SubscriberViewStrings.CommandClear, SvgIconHelper.LoadFromResource("/Images/Clear.svg")),
|
||||||
|
new TabToolbarCommand(ExportCommand, SubscriberViewStrings.CommandExport, SvgIconHelper.LoadFromResource("/Images/Export.svg"))
|
||||||
};
|
};
|
||||||
|
|
||||||
createPublisherCommand = new DelegateCommand(CreatePublisherExecute, CreatePublisherCanExecute);
|
createPublisherCommand = new DelegateCommand(CreatePublisherExecute, CreatePublisherCanExecute);
|
||||||
@ -94,26 +105,82 @@ namespace PettingZoo.UI.Tab.Subscriber
|
|||||||
subscriber.Start();
|
subscriber.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void ClearExecute()
|
private void ClearExecute()
|
||||||
{
|
{
|
||||||
Messages.Clear();
|
Messages.Clear();
|
||||||
UnreadMessages.Clear();
|
UnreadMessages.Clear();
|
||||||
|
|
||||||
|
HasMessagesChanged();
|
||||||
RaisePropertyChanged(nameof(UnreadMessagesVisibility));
|
RaisePropertyChanged(nameof(UnreadMessagesVisibility));
|
||||||
clearCommand.RaiseCanExecuteChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private bool ClearCanExecute()
|
private bool HasMessagesCanExecute()
|
||||||
{
|
{
|
||||||
return Messages.Count > 0;
|
return Messages.Count > 0 || UnreadMessages.Count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void HasMessagesChanged()
|
||||||
|
{
|
||||||
|
clearCommand.RaiseCanExecuteChanged();
|
||||||
|
exportCommand.RaiseCanExecuteChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ExportExecute()
|
||||||
|
{
|
||||||
|
var formats = exportFormatProvider.Formats.ToArray();
|
||||||
|
|
||||||
|
var dialog = new SaveFileDialog
|
||||||
|
{
|
||||||
|
Filter = string.Join('|', formats.Select(f => f.Filter))
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!dialog.ShowDialog().GetValueOrDefault())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 1-based? Seriously?
|
||||||
|
if (dialog.FilterIndex <= 0 || dialog.FilterIndex > formats.Length)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var messages = Messages.Concat(UnreadMessages).ToArray();
|
||||||
|
var filename = dialog.FileName;
|
||||||
|
var format = formats[dialog.FilterIndex - 1];
|
||||||
|
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await using var exportFile = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||||
|
await format.Export(exportFile, messages);
|
||||||
|
|
||||||
|
await Application.Current.Dispatcher.BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
MessageBox.Show(string.Format(SubscriberViewStrings.ExportSuccess, messages.Length, filename),
|
||||||
|
SubscriberViewStrings.ExportResultTitle,
|
||||||
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error(e, "Error while exporting messages");
|
||||||
|
|
||||||
|
await Application.Current.Dispatcher.BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
MessageBox.Show(string.Format(SubscriberViewStrings.ExportError, e.Message),
|
||||||
|
SubscriberViewStrings.ExportResultTitle,
|
||||||
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void CreatePublisherExecute()
|
private void CreatePublisherExecute()
|
||||||
{
|
{
|
||||||
var publisherTab = tabFactory.CreatePublisherTab(connection, SelectedMessage);
|
var publisherTab = tabFactory.CreatePublisherTab(connection, SelectedMessage);
|
||||||
tabHost.AddTab(publisherTab);
|
tabHostProvider.Instance.AddTab(publisherTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -125,7 +192,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
|||||||
|
|
||||||
private void SubscriberMessageReceived(object? sender, MessageReceivedEventArgs args)
|
private void SubscriberMessageReceived(object? sender, MessageReceivedEventArgs args)
|
||||||
{
|
{
|
||||||
dispatcher.BeginInvoke(() =>
|
Application.Current.Dispatcher.BeginInvoke(() =>
|
||||||
{
|
{
|
||||||
if (!tabActive)
|
if (!tabActive)
|
||||||
{
|
{
|
||||||
@ -139,7 +206,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
|||||||
else
|
else
|
||||||
Messages.Add(args.MessageInfo);
|
Messages.Add(args.MessageInfo);
|
||||||
|
|
||||||
clearCommand.RaiseCanExecuteChanged();
|
HasMessagesChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +235,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
|||||||
newMessageTimer = new Timer(
|
newMessageTimer = new Timer(
|
||||||
_ =>
|
_ =>
|
||||||
{
|
{
|
||||||
dispatcher.BeginInvoke(() =>
|
Application.Current.Dispatcher.BeginInvoke(() =>
|
||||||
{
|
{
|
||||||
if (UnreadMessages.Count == 0)
|
if (UnreadMessages.Count == 0)
|
||||||
return;
|
return;
|
||||||
@ -210,7 +277,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
|||||||
|
|
||||||
public class DesignTimeSubscriberViewModel : SubscriberViewModel
|
public class DesignTimeSubscriberViewModel : SubscriberViewModel
|
||||||
{
|
{
|
||||||
public DesignTimeSubscriberViewModel() : base(null!, null!, null!, new DesignTimeSubscriber())
|
public DesignTimeSubscriberViewModel() : base(null!, null!, null!, null!, new DesignTimeSubscriber(), null!)
|
||||||
{
|
{
|
||||||
for (var i = 1; i <= 5; i++)
|
for (var i = 1; i <= 5; i++)
|
||||||
(i > 2 ? UnreadMessages : Messages).Add(new ReceivedMessageInfo(
|
(i > 2 ? UnreadMessages : Messages).Add(new ReceivedMessageInfo(
|
||||||
|
@ -69,6 +69,15 @@ namespace PettingZoo.UI.Tab.Subscriber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Export....
|
||||||
|
/// </summary>
|
||||||
|
public static string CommandExport {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("CommandExport", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Open in new Publisher tab.
|
/// Looks up a localized string similar to Open in new Publisher tab.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -96,6 +105,33 @@ namespace PettingZoo.UI.Tab.Subscriber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Error while exporting messages: {0}.
|
||||||
|
/// </summary>
|
||||||
|
public static string ExportError {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ExportError", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Export.
|
||||||
|
/// </summary>
|
||||||
|
public static string ExportResultTitle {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ExportResultTitle", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Exported {0} message(s) to {1}.
|
||||||
|
/// </summary>
|
||||||
|
public static string ExportSuccess {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ExportSuccess", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to New messages.
|
/// Looks up a localized string similar to New messages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -120,6 +120,9 @@
|
|||||||
<data name="CommandClear" xml:space="preserve">
|
<data name="CommandClear" xml:space="preserve">
|
||||||
<value>Clear</value>
|
<value>Clear</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CommandExport" xml:space="preserve">
|
||||||
|
<value>Export...</value>
|
||||||
|
</data>
|
||||||
<data name="ContextPublish" xml:space="preserve">
|
<data name="ContextPublish" xml:space="preserve">
|
||||||
<value>Open in new Publisher tab</value>
|
<value>Open in new Publisher tab</value>
|
||||||
</data>
|
</data>
|
||||||
@ -129,6 +132,15 @@
|
|||||||
<data name="DeliveryModePersistent" xml:space="preserve">
|
<data name="DeliveryModePersistent" xml:space="preserve">
|
||||||
<value>Persistent</value>
|
<value>Persistent</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ExportError" xml:space="preserve">
|
||||||
|
<value>Error while exporting messages: {0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExportResultTitle" xml:space="preserve">
|
||||||
|
<value>Export</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExportSuccess" xml:space="preserve">
|
||||||
|
<value>Exported {0} message(s) to {1}</value>
|
||||||
|
</data>
|
||||||
<data name="LabelNewMessages" xml:space="preserve">
|
<data name="LabelNewMessages" xml:space="preserve">
|
||||||
<value>New messages</value>
|
<value>New messages</value>
|
||||||
</data>
|
</data>
|
||||||
|
18
PettingZoo/UI/Tab/TabHostProvider.cs
Normal file
18
PettingZoo/UI/Tab/TabHostProvider.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PettingZoo.UI.Tab
|
||||||
|
{
|
||||||
|
public class TabHostProvider : ITabHostProvider
|
||||||
|
{
|
||||||
|
private ITabHost? instance;
|
||||||
|
|
||||||
|
public ITabHost Instance => instance ?? throw new InvalidOperationException("ITabHost instance must be initialized before acquiring");
|
||||||
|
|
||||||
|
|
||||||
|
// ReSharper disable once ParameterHidesMember
|
||||||
|
public void SetInstance(ITabHost instance)
|
||||||
|
{
|
||||||
|
this.instance = instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@ namespace PettingZoo.UI.Tab.Undocked
|
|||||||
{
|
{
|
||||||
public class UndockedTabHostViewModel : BaseViewModel, ITabActivate
|
public class UndockedTabHostViewModel : BaseViewModel, ITabActivate
|
||||||
{
|
{
|
||||||
private readonly ITabHost tabHost;
|
private readonly ITabHostProvider tabHostProvider;
|
||||||
private readonly ITab tab;
|
private readonly ITab tab;
|
||||||
private readonly DelegateCommand dockCommand;
|
private readonly DelegateCommand dockCommand;
|
||||||
|
|
||||||
@ -25,9 +25,9 @@ namespace PettingZoo.UI.Tab.Undocked
|
|||||||
public ICommand DockCommand => dockCommand;
|
public ICommand DockCommand => dockCommand;
|
||||||
|
|
||||||
|
|
||||||
public UndockedTabHostViewModel(ITabHost tabHost, ITab tab)
|
public UndockedTabHostViewModel(ITabHostProvider tabHostProvider, ITab tab)
|
||||||
{
|
{
|
||||||
this.tabHost = tabHost;
|
this.tabHostProvider = tabHostProvider;
|
||||||
this.tab = tab;
|
this.tab = tab;
|
||||||
|
|
||||||
tab.PropertyChanged += (_, args) =>
|
tab.PropertyChanged += (_, args) =>
|
||||||
@ -43,13 +43,13 @@ namespace PettingZoo.UI.Tab.Undocked
|
|||||||
|
|
||||||
private void DockCommandExecute()
|
private void DockCommandExecute()
|
||||||
{
|
{
|
||||||
tabHost.DockTab(tab);
|
tabHostProvider.Instance.DockTab(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void WindowClosed()
|
public void WindowClosed()
|
||||||
{
|
{
|
||||||
tabHost.UndockedTabClosed(tab);
|
tabHostProvider.Instance.UndockedTabClosed(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,9 +10,9 @@ namespace PettingZoo.UI.Tab.Undocked
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class UndockedTabHostWindow
|
public partial class UndockedTabHostWindow
|
||||||
{
|
{
|
||||||
public static UndockedTabHostWindow Create(ITabHost tabHost, ITab tab, double width, double height)
|
public static UndockedTabHostWindow Create(ITabHostProvider tabHostProvider, ITab tab, double width, double height)
|
||||||
{
|
{
|
||||||
var viewModel = new UndockedTabHostViewModel(tabHost, tab);
|
var viewModel = new UndockedTabHostViewModel(tabHostProvider, tab);
|
||||||
var window = new UndockedTabHostWindow(viewModel)
|
var window = new UndockedTabHostWindow(viewModel)
|
||||||
{
|
{
|
||||||
Width = width,
|
Width = width,
|
||||||
|
@ -1,26 +1,32 @@
|
|||||||
using PettingZoo.Core.Connection;
|
using PettingZoo.Core.Connection;
|
||||||
|
using PettingZoo.Core.Export;
|
||||||
using PettingZoo.Core.Generator;
|
using PettingZoo.Core.Generator;
|
||||||
using PettingZoo.UI.Tab.Publisher;
|
using PettingZoo.UI.Tab.Publisher;
|
||||||
using PettingZoo.UI.Tab.Subscriber;
|
using PettingZoo.UI.Tab.Subscriber;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace PettingZoo.UI.Tab
|
namespace PettingZoo.UI.Tab
|
||||||
{
|
{
|
||||||
public class ViewTabFactory : ITabFactory
|
public class ViewTabFactory : ITabFactory
|
||||||
{
|
{
|
||||||
private readonly ITabHost tabHost;
|
private readonly ILogger logger;
|
||||||
|
private readonly ITabHostProvider tabHostProvider;
|
||||||
private readonly IExampleGenerator exampleGenerator;
|
private readonly IExampleGenerator exampleGenerator;
|
||||||
|
private readonly IExportFormatProvider exportFormatProvider;
|
||||||
|
|
||||||
|
|
||||||
public ViewTabFactory(ITabHost tabHost, IExampleGenerator exampleGenerator)
|
public ViewTabFactory(ILogger logger, ITabHostProvider tabHostProvider, IExampleGenerator exampleGenerator, IExportFormatProvider exportFormatProvider)
|
||||||
{
|
{
|
||||||
this.tabHost = tabHost;
|
this.logger = logger;
|
||||||
|
this.tabHostProvider = tabHostProvider;
|
||||||
this.exampleGenerator = exampleGenerator;
|
this.exampleGenerator = exampleGenerator;
|
||||||
|
this.exportFormatProvider = exportFormatProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ITab CreateSubscriberTab(IConnection connection, ISubscriber subscriber)
|
public ITab CreateSubscriberTab(IConnection connection, ISubscriber subscriber)
|
||||||
{
|
{
|
||||||
var viewModel = new SubscriberViewModel(tabHost, this, connection, subscriber);
|
var viewModel = new SubscriberViewModel(logger, tabHostProvider, this, connection, subscriber, exportFormatProvider);
|
||||||
return new ViewTab<SubscriberView, SubscriberViewModel>(
|
return new ViewTab<SubscriberView, SubscriberViewModel>(
|
||||||
new SubscriberView(viewModel),
|
new SubscriberView(viewModel),
|
||||||
viewModel,
|
viewModel,
|
||||||
@ -30,7 +36,7 @@ namespace PettingZoo.UI.Tab
|
|||||||
|
|
||||||
public ITab CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null)
|
public ITab CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null)
|
||||||
{
|
{
|
||||||
var viewModel = new PublisherViewModel(tabHost, this, connection, exampleGenerator, fromReceivedMessage);
|
var viewModel = new PublisherViewModel(tabHostProvider, this, connection, exampleGenerator, fromReceivedMessage);
|
||||||
return new ViewTab<PublisherView, PublisherViewModel>(
|
return new ViewTab<PublisherView, PublisherViewModel>(
|
||||||
new PublisherView(viewModel),
|
new PublisherView(viewModel),
|
||||||
viewModel,
|
viewModel,
|
||||||
|
Loading…
Reference in New Issue
Block a user