Merge branch 'release/1.3'
This commit is contained in:
commit
2cfb341f47
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace PettingZoo.Core.Connection
|
||||
{
|
||||
public interface ISubscriber : IAsyncDisposable
|
||||
public interface ISubscriber : IDisposable
|
||||
{
|
||||
string? QueueName { get; }
|
||||
string? Exchange {get; }
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using PettingZoo.Core.Connection;
|
||||
|
||||
namespace PettingZoo.Core.ExportImport
|
||||
@ -13,7 +12,10 @@ namespace PettingZoo.Core.ExportImport
|
||||
public string? QueueName { get; }
|
||||
public string? Exchange => null;
|
||||
public string? RoutingKey => null;
|
||||
|
||||
#pragma warning disable CS0067 // "The event ... is never used" - it's part of the interface so it's required.
|
||||
public event EventHandler<MessageReceivedEventArgs>? MessageReceived;
|
||||
#pragma warning restore CS0067
|
||||
|
||||
|
||||
public ImportSubscriber(string filename, IReadOnlyList<ReceivedMessageInfo> messages)
|
||||
@ -23,10 +25,9 @@ namespace PettingZoo.Core.ExportImport
|
||||
}
|
||||
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
return default;
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,7 +58,7 @@ namespace PettingZoo.Core.ExportImport
|
||||
public StreamWrapper(StreamProgressDecorator owner, Stream decoratedStream)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.DecoratedStream = decoratedStream;
|
||||
DecoratedStream = decoratedStream;
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,11 +17,13 @@ namespace PettingZoo.Core.Generator
|
||||
|
||||
public interface IClassTypeExample : IExample
|
||||
{
|
||||
public string AssemblyName { get; }
|
||||
public string? Namespace { get; }
|
||||
public string ClassName { get; }
|
||||
string AssemblyName { get; }
|
||||
string? Namespace { get; }
|
||||
string ClassName { get; }
|
||||
|
||||
public string FullClassName => (!string.IsNullOrEmpty(Namespace) ? Namespace + "." : "") + ClassName;
|
||||
string FullClassName => (!string.IsNullOrEmpty(Namespace) ? Namespace + "." : "") + ClassName;
|
||||
|
||||
bool TryGetPublishDestination(out string exchange, out string routingKey);
|
||||
}
|
||||
|
||||
|
||||
|
22
PettingZoo.Core/Macros/BasePayloadMacro.cs
Normal file
22
PettingZoo.Core/Macros/BasePayloadMacro.cs
Normal file
@ -0,0 +1,22 @@
|
||||
namespace PettingZoo.Core.Macros
|
||||
{
|
||||
public abstract class BasePayloadMacro : IPayloadMacro
|
||||
{
|
||||
public string DisplayName { get; }
|
||||
public string MacroText { get; }
|
||||
|
||||
public string MacroCommand { get; }
|
||||
|
||||
|
||||
protected BasePayloadMacro(string macroCommand, string displayName)
|
||||
{
|
||||
MacroCommand = macroCommand;
|
||||
|
||||
DisplayName = displayName;
|
||||
MacroText = "{{" + macroCommand + "}}";
|
||||
}
|
||||
|
||||
|
||||
public abstract string GetValue();
|
||||
}
|
||||
}
|
18
PettingZoo.Core/Macros/DateTimePayloadMacro.cs
Normal file
18
PettingZoo.Core/Macros/DateTimePayloadMacro.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace PettingZoo.Core.Macros
|
||||
{
|
||||
public class JsonDateTimePayloadMacro : BasePayloadMacro
|
||||
{
|
||||
public JsonDateTimePayloadMacro()
|
||||
: base("JsonUtcNow", "Current date/time (yyyy-mm-ddThh:mm:ss.mmmZ)")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override string GetValue()
|
||||
{
|
||||
return DateTime.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'");
|
||||
}
|
||||
}
|
||||
}
|
18
PettingZoo.Core/Macros/IPayloadMacroProcessor.cs
Normal file
18
PettingZoo.Core/Macros/IPayloadMacroProcessor.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PettingZoo.Core.Macros
|
||||
{
|
||||
public interface IPayloadMacroProcessor
|
||||
{
|
||||
string Apply(string payload);
|
||||
|
||||
IEnumerable<IPayloadMacro> Macros { get; }
|
||||
}
|
||||
|
||||
|
||||
public interface IPayloadMacro
|
||||
{
|
||||
public string DisplayName { get; }
|
||||
public string MacroText { get; }
|
||||
}
|
||||
}
|
18
PettingZoo.Core/Macros/NewGuidPayloadMacro.cs
Normal file
18
PettingZoo.Core/Macros/NewGuidPayloadMacro.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace PettingZoo.Core.Macros
|
||||
{
|
||||
public class NewGuidPayloadMacro : BasePayloadMacro
|
||||
{
|
||||
public NewGuidPayloadMacro()
|
||||
: base("NewGuid", "Generate GUID")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override string GetValue()
|
||||
{
|
||||
return Guid.NewGuid().ToString();
|
||||
}
|
||||
}
|
||||
}
|
41
PettingZoo.Core/Macros/PayloadMacroProcessor.cs
Normal file
41
PettingZoo.Core/Macros/PayloadMacroProcessor.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace PettingZoo.Core.Macros
|
||||
{
|
||||
public class PayloadMacroProcessor : IPayloadMacroProcessor
|
||||
{
|
||||
private readonly BasePayloadMacro[] macros;
|
||||
public IEnumerable<IPayloadMacro> Macros => macros;
|
||||
|
||||
|
||||
public PayloadMacroProcessor()
|
||||
{
|
||||
macros = new BasePayloadMacro[]
|
||||
{
|
||||
new NewGuidPayloadMacro(),
|
||||
new JsonDateTimePayloadMacro()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// For now we only support simple one-keyboard macros, but this could be extended with parameters if required
|
||||
private static readonly Regex MacroRegex = new("{{(.+?)}}", RegexOptions.Compiled);
|
||||
|
||||
|
||||
public string Apply(string payload)
|
||||
{
|
||||
return MacroRegex.Replace(payload, match =>
|
||||
{
|
||||
var macroCommand = match.Groups[1].Value.Trim();
|
||||
var macro = macros.FirstOrDefault(m => string.Equals(m.MacroCommand, macroCommand, StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
return macro != null
|
||||
? macro.GetValue()
|
||||
: match.Groups[0].Value;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using PettingZoo.Core.Connection;
|
||||
using RabbitMQ.Client;
|
||||
using RabbitMQ.Client.Events;
|
||||
@ -29,14 +28,12 @@ namespace PettingZoo.RabbitMQ
|
||||
}
|
||||
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
if (model != null && consumerTag != null && model.IsOpen)
|
||||
model.BasicCancelNoWait(consumerTag);
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,6 +7,7 @@ using System.Runtime.Loader;
|
||||
using Newtonsoft.Json;
|
||||
using PettingZoo.Core.Generator;
|
||||
using PettingZoo.Core.Validation;
|
||||
using Tapeti.Default;
|
||||
|
||||
namespace PettingZoo.Tapeti.AssemblyParser
|
||||
{
|
||||
@ -83,6 +84,24 @@ namespace PettingZoo.Tapeti.AssemblyParser
|
||||
}
|
||||
|
||||
|
||||
public bool TryGetPublishDestination(out string exchange, out string routingKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Assume default strategies are used
|
||||
exchange = new NamespaceMatchExchangeStrategy().GetExchange(type);
|
||||
routingKey = new TypeNameRoutingKeyStrategy().GetRoutingKey(type);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
exchange = "";
|
||||
routingKey = "";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool CanValidate()
|
||||
{
|
||||
return InitializeValidation();
|
||||
|
@ -17,6 +17,7 @@
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="6.0.0" />
|
||||
<PackageReference Include="Tapeti" Version="2.8.2" />
|
||||
<PackageReference Include="Tapeti.Annotations" Version="3.0.0" />
|
||||
<PackageReference Include="Tapeti.DataAnnotations.Extensions" Version="3.0.0" />
|
||||
</ItemGroup>
|
||||
|
@ -5,7 +5,6 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using PettingZoo.Core.Generator;
|
||||
using PettingZoo.Core.Settings;
|
||||
using PettingZoo.Tapeti.AssemblyLoader;
|
||||
|
@ -300,6 +300,14 @@ namespace PettingZoo.Tapeti.UI.ClassSelection
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
public bool TryGetPublishDestination(out string exchange, out string routingKey)
|
||||
{
|
||||
exchange = "";
|
||||
routingKey = "";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,12 @@
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ButtonIcon" TargetType="{x:Type Image}">
|
||||
<Setter Property="Margin" Value="0,0,8,0" />
|
||||
<Setter Property="Width" Value="16" />
|
||||
<Setter Property="Height" Value="16" />
|
||||
</Style>
|
||||
|
||||
|
||||
<Style x:Key="Timestamp" TargetType="{x:Type TextBlock}">
|
||||
<Style.Triggers>
|
||||
|
6
PettingZoo/Images/RabbitMQ.svg
Normal file
6
PettingZoo/Images/RabbitMQ.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="256px" height="271px" viewBox="0 0 256 271" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<g>
|
||||
<path d="M245.44,108.307692 L160.349538,108.307692 C156.081231,108.307692 152.615385,104.841846 152.615385,100.573538 L152.615385,11.8941538 C152.615385,5.32676923 147.288615,0 140.726154,0 L110.350769,0 C103.783385,0 98.4615385,5.32676923 98.4615385,11.8941538 L98.4615385,100.036923 C98.4615385,104.610462 94.7643077,108.327385 90.1907692,108.347077 L62.3064615,108.48 C57.6935385,108.504615 53.9470769,104.763077 53.9569231,100.155077 L54.1292308,11.9138462 C54.144,5.33661538 48.8172308,0 42.24,0 L11.8892308,0 C5.32184615,0 0,5.32676923 0,11.8941538 L0,260.209231 C0,266.043077 4.72615385,270.769231 10.5550769,270.769231 L245.44,270.769231 C251.273846,270.769231 256,266.043077 256,260.209231 L256,118.867692 C256,113.033846 251.273846,108.307692 245.44,108.307692 L245.44,108.307692 Z M205.538462,201.540923 C205.538462,209.186462 199.340308,215.384615 191.694769,215.384615 L167.689846,215.384615 C160.044308,215.384615 153.846154,209.186462 153.846154,201.540923 L153.846154,177.536 C153.846154,169.890462 160.044308,163.692308 167.689846,163.692308 L191.694769,163.692308 C199.340308,163.692308 205.538462,169.890462 205.538462,177.536 L205.538462,201.540923 L205.538462,201.540923 Z" fill="#FF6600"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
BIN
PettingZoo/Images/Tapeti.png
Normal file
BIN
PettingZoo/Images/Tapeti.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
@ -28,6 +28,8 @@
|
||||
<None Remove="Images\Import.svg" />
|
||||
<None Remove="Images\Ok.svg" />
|
||||
<None Remove="Images\PublishSend.svg" />
|
||||
<None Remove="Images\RabbitMQ.svg" />
|
||||
<None Remove="Images\Tapeti.png" />
|
||||
<None Remove="Images\Undock.svg" />
|
||||
</ItemGroup>
|
||||
|
||||
@ -44,6 +46,7 @@
|
||||
<Resource Include="Images\Ok.svg" />
|
||||
<Resource Include="Images\Publish.svg" />
|
||||
<Resource Include="Images\PublishSend.svg" />
|
||||
<Resource Include="Images\RabbitMQ.svg" />
|
||||
<Resource Include="Images\Subscribe.svg" />
|
||||
</ItemGroup>
|
||||
|
||||
@ -66,6 +69,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\Tapeti.png" />
|
||||
<Resource Include="Images\Undock.svg" />
|
||||
<Resource Include="Images\Busy.svg" />
|
||||
</ItemGroup>
|
||||
@ -144,7 +148,7 @@
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="UI\Tab\Publisher\PayloadEditorStrings.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>PayloadEditorStrings.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="UI\Tab\Publisher\TapetiPublisherViewStrings.resx">
|
||||
|
@ -6,6 +6,7 @@ using System.Windows.Markup;
|
||||
using PettingZoo.Core.Connection;
|
||||
using PettingZoo.Core.ExportImport;
|
||||
using PettingZoo.Core.Generator;
|
||||
using PettingZoo.Core.Macros;
|
||||
using PettingZoo.Core.Settings;
|
||||
using PettingZoo.RabbitMQ;
|
||||
using PettingZoo.Settings.LiteDB;
|
||||
@ -84,6 +85,7 @@ namespace PettingZoo
|
||||
container.Register<IExampleGenerator, TapetiClassLibraryExampleGenerator>();
|
||||
container.RegisterSingleton<ITabHostProvider, TabHostProvider>();
|
||||
container.Register<ITabFactory, ViewTabFactory>();
|
||||
container.RegisterSingleton<IPayloadMacroProcessor, PayloadMacroProcessor>();
|
||||
|
||||
container.RegisterInstance<IExportImportFormatProvider>(new ExportImportFormatProvider(
|
||||
new TapetiCmdExportFormat(),
|
||||
|
@ -4,9 +4,6 @@
|
||||
|
||||
Should-have
|
||||
-----------
|
||||
- Single tab for responses, don't create a new subscriber tab for 1 message each time
|
||||
Use the CorrelationId in the list for such cases instead of the routing key (which is the name of the dynamic queue for the responses).
|
||||
Set the CorrelationId to the request routing key for example, so the different responses can be somewhat identified.
|
||||
|
||||
|
||||
Nice-to-have
|
||||
|
@ -170,7 +170,7 @@ namespace PettingZoo.UI.Main
|
||||
if (connectionSettings.Subscribe)
|
||||
{
|
||||
var subscriber = connection.Subscribe(connectionSettings.Exchange, connectionSettings.RoutingKey);
|
||||
AddTab(tabFactory.CreateSubscriberTab(connection, subscriber));
|
||||
tabFactory.CreateSubscriberTab(connection, subscriber);
|
||||
}
|
||||
|
||||
ConnectionChanged();
|
||||
@ -214,7 +214,7 @@ namespace PettingZoo.UI.Main
|
||||
subscribeDialogParams = newParams;
|
||||
|
||||
var subscriber = connection.Subscribe(subscribeDialogParams.Exchange, subscribeDialogParams.RoutingKey);
|
||||
AddTab(tabFactory.CreateSubscriberTab(connection, subscriber));
|
||||
tabFactory.CreateSubscriberTab(connection, subscriber);
|
||||
}
|
||||
|
||||
|
||||
@ -223,7 +223,7 @@ namespace PettingZoo.UI.Main
|
||||
if (connection == null)
|
||||
return;
|
||||
|
||||
AddTab(tabFactory.CreatePublisherTab(connection));
|
||||
tabFactory.CreatePublisherTab(connection);
|
||||
}
|
||||
|
||||
|
||||
@ -235,7 +235,8 @@ namespace PettingZoo.UI.Main
|
||||
|
||||
private void CloseTabExecute()
|
||||
{
|
||||
RemoveActiveTab();
|
||||
var tab = RemoveActiveTab();
|
||||
(tab as IDisposable)?.Dispose();
|
||||
}
|
||||
|
||||
|
||||
@ -300,8 +301,7 @@ namespace PettingZoo.UI.Main
|
||||
progressWindow.Close();
|
||||
progressWindow = null;
|
||||
|
||||
AddTab(tabFactory.CreateSubscriberTab(connection,
|
||||
new ImportSubscriber(filename, messages)));
|
||||
tabFactory.CreateSubscriberTab(connection, new ImportSubscriber(filename, messages));
|
||||
});
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@ -377,6 +377,15 @@ namespace PettingZoo.UI.Main
|
||||
}
|
||||
|
||||
|
||||
public void ActivateTab(ITab tab)
|
||||
{
|
||||
if (undockedTabs.TryGetValue(tab, out var window))
|
||||
window.Activate();
|
||||
else if (Tabs.Contains(tab))
|
||||
ActiveTab = tab;
|
||||
}
|
||||
|
||||
|
||||
public void DockTab(ITab tab)
|
||||
{
|
||||
if (undockedTabs.Remove(tab, out var tabHostWindow))
|
||||
|
@ -2,13 +2,10 @@
|
||||
|
||||
namespace PettingZoo.UI.Tab
|
||||
{
|
||||
// Passing the closeTabCommand is necessary because I haven't figured out how to bind the main window's
|
||||
// context menu items for the tab to the main window's datacontext yet. RelativeSource doesn't seem to work
|
||||
// because the popup is it's own window. Refactor if a better solution is found.
|
||||
|
||||
public interface ITabFactory
|
||||
{
|
||||
ITab CreateSubscriberTab(IConnection? connection, ISubscriber subscriber);
|
||||
ITab CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null);
|
||||
void CreateSubscriberTab(IConnection? connection, ISubscriber subscriber);
|
||||
string CreateReplySubscriberTab(IConnection connection);
|
||||
void CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
public interface ITabHost
|
||||
{
|
||||
void AddTab(ITab tab);
|
||||
void ActivateTab(ITab tab);
|
||||
|
||||
void DockTab(ITab tab);
|
||||
void UndockedTabClosed(ITab tab);
|
||||
|
@ -5,6 +5,7 @@
|
||||
string Exchange { get; }
|
||||
string RoutingKey { get; }
|
||||
|
||||
string? GetReplyTo();
|
||||
string? GetReplyTo(ref string? correlationId);
|
||||
void SetExchangeDestination(string exchange, string routingKey);
|
||||
}
|
||||
}
|
||||
|
@ -21,18 +21,36 @@
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" Visibility="{Binding ValidationVisibility}" Margin="0,8,0,0">
|
||||
<Image Source="{svgc:SvgImage Source=/Images/Ok.svg, AppName=PettingZoo}" Width="16" Height="16" Margin="4" Visibility="{Binding ValidationOk}" />
|
||||
<Image Source="{svgc:SvgImage Source=/Images/Error.svg, AppName=PettingZoo}" Width="16" Height="16" Margin="4" Visibility="{Binding ValidationError}" />
|
||||
<Image Source="{svgc:SvgImage Source=/Images/Busy.svg, AppName=PettingZoo}" Width="16" Height="16" Margin="4" Visibility="{Binding ValidationValidating}" />
|
||||
<Image Source="{svgc:SvgImage Source=/Images/Ok.svg, AppName=PettingZoo}" Width="16" Height="16" Margin="1,4,0,0" Visibility="{Binding ValidationOk}" />
|
||||
<Image Source="{svgc:SvgImage Source=/Images/Error.svg, AppName=PettingZoo}" Width="16" Height="16" Margin="1,4,0,0" Visibility="{Binding ValidationError}" />
|
||||
<Image Source="{svgc:SvgImage Source=/Images/Busy.svg, AppName=PettingZoo}" Width="16" Height="16" Margin="1,4,0,0" Visibility="{Binding ValidationValidating}" />
|
||||
<TextBlock Text="{Binding ValidationMessage}" Margin="4" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" Margin="0,8,0,0">
|
||||
<CheckBox Content="{x:Static publisher:PayloadEditorStrings.CheckEnableMacros}" VerticalAlignment="Center" IsChecked="{Binding EnableMacros}" />
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<Border Style="{StaticResource ControlBorder}" Name="EditorBorder">
|
||||
<avalonedit:TextEditor
|
||||
xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit"
|
||||
Name="Editor"
|
||||
SyntaxHighlighting="{Binding SyntaxHighlighting}"
|
||||
Style="{StaticResource Payload}" />
|
||||
Style="{StaticResource Payload}">
|
||||
<avalonedit:TextEditor.ContextMenu>
|
||||
<ContextMenu Opened="ContextMenu_OnOpened">
|
||||
<MenuItem Header="{x:Static publisher:PayloadEditorStrings.ContextMenuUndo}" Name="ContextMenuUndo" Click="Undo_Click" InputGestureText="Ctrl+Z" />
|
||||
<MenuItem Header="{x:Static publisher:PayloadEditorStrings.ContextMenuRedo}" Name="ContextMenuRedo" Click="Redo_Click" InputGestureText="Ctrl+Y "/>
|
||||
<Separator/>
|
||||
<MenuItem Header="{x:Static publisher:PayloadEditorStrings.ContextMenuCut}" Name="ContextMenuCut" Click="Cut_Click" InputGestureText="Ctrl+X "/>
|
||||
<MenuItem Header="{x:Static publisher:PayloadEditorStrings.ContextMenuCopy}" Name="ContextMenuCopy" Click="Copy_Click" InputGestureText="Ctrl+C "/>
|
||||
<MenuItem Header="{x:Static publisher:PayloadEditorStrings.ContextMenuPaste}" Name="ContextMenuPaste" Click="Paste_Click" InputGestureText="Ctrl+V "/>
|
||||
<Separator/>
|
||||
<MenuItem Header="{x:Static publisher:PayloadEditorStrings.ContextMenuInsertMacro}" Name="ContextMenuInsertMacro" />
|
||||
</ContextMenu>
|
||||
</avalonedit:TextEditor.ContextMenu>
|
||||
</avalonedit:TextEditor>
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</UserControl>
|
||||
|
@ -2,7 +2,9 @@
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using PettingZoo.Core.Macros;
|
||||
using PettingZoo.Core.Validation;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Publisher
|
||||
@ -88,6 +90,32 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
}
|
||||
|
||||
|
||||
public static readonly DependencyProperty EnableMacrosProperty
|
||||
= DependencyProperty.Register(
|
||||
"EnableMacros",
|
||||
typeof(bool),
|
||||
typeof(PayloadEditorControl),
|
||||
new FrameworkPropertyMetadata(false)
|
||||
{
|
||||
BindsTwoWayByDefault = true,
|
||||
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
public bool EnableMacros
|
||||
{
|
||||
get => viewModel.EnableMacros;
|
||||
set
|
||||
{
|
||||
if (value == viewModel.EnableMacros)
|
||||
return;
|
||||
|
||||
SetValue(EnableMacrosProperty, value);
|
||||
viewModel.EnableMacros = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IPayloadValidator? Validator
|
||||
{
|
||||
get => viewModel.Validator;
|
||||
@ -95,6 +123,21 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
}
|
||||
|
||||
|
||||
private IPayloadMacroProcessor? macroProcessor;
|
||||
public IPayloadMacroProcessor? MacroProcessor
|
||||
{
|
||||
get => macroProcessor;
|
||||
set
|
||||
{
|
||||
if (value == macroProcessor)
|
||||
return;
|
||||
|
||||
macroProcessor = value;
|
||||
UpdateMacroContextMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private readonly ErrorHighlightingTransformer errorHighlightingTransformer = new();
|
||||
|
||||
public PayloadEditorControl()
|
||||
@ -123,6 +166,12 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
viewModel.Payload = value;
|
||||
});
|
||||
|
||||
this.OnPropertyChanges<bool>(EnableMacrosProperty)
|
||||
.ObserveOn(SynchronizationContext.Current!)
|
||||
.Subscribe(value =>
|
||||
{
|
||||
viewModel.EnableMacros = value;
|
||||
});
|
||||
|
||||
viewModel.PropertyChanged += (_, args) =>
|
||||
{
|
||||
@ -139,6 +188,10 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
case nameof(viewModel.Payload):
|
||||
SetValue(PayloadProperty, viewModel.Payload);
|
||||
break;
|
||||
|
||||
case nameof(viewModel.EnableMacros):
|
||||
SetValue(EnableMacrosProperty, viewModel.EnableMacros);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
@ -207,5 +260,70 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
// so I've moved the ViewModel one level down to get the best of both worlds...
|
||||
DataContextContainer.DataContext = viewModel;
|
||||
}
|
||||
|
||||
|
||||
private void UpdateMacroContextMenu()
|
||||
{
|
||||
ContextMenuInsertMacro.Items.Clear();
|
||||
|
||||
if (macroProcessor == null)
|
||||
return;
|
||||
|
||||
foreach (var macro in macroProcessor.Macros)
|
||||
{
|
||||
var macroMenuItem = new MenuItem
|
||||
{
|
||||
Header = macro.DisplayName
|
||||
};
|
||||
|
||||
macroMenuItem.Click += (_, _) =>
|
||||
{
|
||||
Editor.SelectedText = macro.MacroText;
|
||||
|
||||
var length = Editor.SelectionLength;
|
||||
Editor.SelectionLength = 0;
|
||||
Editor.SelectionStart += length;
|
||||
|
||||
viewModel.EnableMacros = true;
|
||||
};
|
||||
|
||||
ContextMenuInsertMacro.Items.Add(macroMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void Undo_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Editor.Undo();
|
||||
}
|
||||
|
||||
private void Redo_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Editor.Redo();
|
||||
}
|
||||
|
||||
private void Cut_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Editor.Cut();
|
||||
}
|
||||
|
||||
private void Copy_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Editor.Copy();
|
||||
}
|
||||
|
||||
private void Paste_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Editor.Paste();
|
||||
}
|
||||
|
||||
private void ContextMenu_OnOpened(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ContextMenuUndo.IsEnabled = Editor.CanUndo;
|
||||
ContextMenuRedo.IsEnabled = Editor.CanRedo;
|
||||
ContextMenuCut.IsEnabled = Editor.SelectionLength > 0;
|
||||
ContextMenuCopy.IsEnabled = Editor.SelectionLength > 0;
|
||||
ContextMenuPaste.IsEnabled = Clipboard.ContainsText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class PayloadEditorStrings {
|
||||
public class PayloadEditorStrings {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
@ -36,7 +36,7 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
/// 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 {
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PettingZoo.UI.Tab.Publisher.PayloadEditorStrings", typeof(PayloadEditorStrings).Assembly);
|
||||
@ -51,7 +51,7 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
/// 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 {
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
@ -60,10 +60,19 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Enable macros (right-click editor to insert).
|
||||
/// </summary>
|
||||
public static string CheckEnableMacros {
|
||||
get {
|
||||
return ResourceManager.GetString("CheckEnableMacros", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to JSON.
|
||||
/// </summary>
|
||||
internal static string ContentTypeJson {
|
||||
public static string ContentTypeJson {
|
||||
get {
|
||||
return ResourceManager.GetString("ContentTypeJson", resourceCulture);
|
||||
}
|
||||
@ -72,7 +81,7 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Other.
|
||||
/// </summary>
|
||||
internal static string ContentTypeOther {
|
||||
public static string ContentTypeOther {
|
||||
get {
|
||||
return ResourceManager.GetString("ContentTypeOther", resourceCulture);
|
||||
}
|
||||
@ -81,16 +90,79 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Plain text.
|
||||
/// </summary>
|
||||
internal static string ContentTypePlain {
|
||||
public static string ContentTypePlain {
|
||||
get {
|
||||
return ResourceManager.GetString("ContentTypePlain", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copy.
|
||||
/// </summary>
|
||||
public static string ContextMenuCopy {
|
||||
get {
|
||||
return ResourceManager.GetString("ContextMenuCopy", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Cut.
|
||||
/// </summary>
|
||||
public static string ContextMenuCut {
|
||||
get {
|
||||
return ResourceManager.GetString("ContextMenuCut", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Insert macro.
|
||||
/// </summary>
|
||||
public static string ContextMenuInsertMacro {
|
||||
get {
|
||||
return ResourceManager.GetString("ContextMenuInsertMacro", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Paste.
|
||||
/// </summary>
|
||||
public static string ContextMenuPaste {
|
||||
get {
|
||||
return ResourceManager.GetString("ContextMenuPaste", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Redo.
|
||||
/// </summary>
|
||||
public static string ContextMenuRedo {
|
||||
get {
|
||||
return ResourceManager.GetString("ContextMenuRedo", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Undo.
|
||||
/// </summary>
|
||||
public static string ContextMenuUndo {
|
||||
get {
|
||||
return ResourceManager.GetString("ContextMenuUndo", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Show available macros.
|
||||
/// </summary>
|
||||
public static string ShowMacrosHint {
|
||||
get {
|
||||
return ResourceManager.GetString("ShowMacrosHint", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid: {0}.
|
||||
/// </summary>
|
||||
internal static string ValidationError {
|
||||
public static string ValidationError {
|
||||
get {
|
||||
return ResourceManager.GetString("ValidationError", resourceCulture);
|
||||
}
|
||||
@ -99,7 +171,7 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Valid.
|
||||
/// </summary>
|
||||
internal static string ValidationOk {
|
||||
public static string ValidationOk {
|
||||
get {
|
||||
return ResourceManager.GetString("ValidationOk", resourceCulture);
|
||||
}
|
||||
@ -108,7 +180,7 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Valid syntax.
|
||||
/// </summary>
|
||||
internal static string ValidationOkSyntax {
|
||||
public static string ValidationOkSyntax {
|
||||
get {
|
||||
return ResourceManager.GetString("ValidationOkSyntax", resourceCulture);
|
||||
}
|
||||
@ -117,7 +189,7 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Validating....
|
||||
/// </summary>
|
||||
internal static string ValidationValidating {
|
||||
public static string ValidationValidating {
|
||||
get {
|
||||
return ResourceManager.GetString("ValidationValidating", resourceCulture);
|
||||
}
|
||||
|
@ -117,6 +117,9 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="CheckEnableMacros" xml:space="preserve">
|
||||
<value>Enable macros (right-click editor to insert)</value>
|
||||
</data>
|
||||
<data name="ContentTypeJson" xml:space="preserve">
|
||||
<value>JSON</value>
|
||||
</data>
|
||||
@ -126,6 +129,27 @@
|
||||
<data name="ContentTypePlain" xml:space="preserve">
|
||||
<value>Plain text</value>
|
||||
</data>
|
||||
<data name="ContextMenuCopy" xml:space="preserve">
|
||||
<value>Copy</value>
|
||||
</data>
|
||||
<data name="ContextMenuCut" xml:space="preserve">
|
||||
<value>Cut</value>
|
||||
</data>
|
||||
<data name="ContextMenuInsertMacro" xml:space="preserve">
|
||||
<value>Insert macro</value>
|
||||
</data>
|
||||
<data name="ContextMenuPaste" xml:space="preserve">
|
||||
<value>Paste</value>
|
||||
</data>
|
||||
<data name="ContextMenuRedo" xml:space="preserve">
|
||||
<value>Redo</value>
|
||||
</data>
|
||||
<data name="ContextMenuUndo" xml:space="preserve">
|
||||
<value>Undo</value>
|
||||
</data>
|
||||
<data name="ShowMacrosHint" xml:space="preserve">
|
||||
<value>Show available macros</value>
|
||||
</data>
|
||||
<data name="ValidationError" xml:space="preserve">
|
||||
<value>Invalid: {0}</value>
|
||||
</data>
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.ComponentModel;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using ICSharpCode.AvalonEdit.Highlighting;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@ -60,10 +61,11 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
private string contentType = ContentTypeJson;
|
||||
private PayloadEditorContentType contentTypeSelection = PayloadEditorContentType.Json;
|
||||
private bool fixedJson;
|
||||
|
||||
|
||||
private ValidationInfo validationInfo = new(ValidationStatus.OkSyntax);
|
||||
|
||||
private string payload = "";
|
||||
private bool enableMacros;
|
||||
|
||||
|
||||
public string ContentType
|
||||
@ -136,6 +138,7 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
public Visibility ContentTypeVisibility => FixedJson ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
|
||||
|
||||
public string Payload
|
||||
{
|
||||
get => payload;
|
||||
@ -143,6 +146,13 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
}
|
||||
|
||||
|
||||
public bool EnableMacros
|
||||
{
|
||||
get => enableMacros;
|
||||
set => SetField(ref enableMacros, value);
|
||||
}
|
||||
|
||||
|
||||
public IHighlightingDefinition? SyntaxHighlighting => ContentTypeSelection == PayloadEditorContentType.Json
|
||||
? HighlightingManager.Instance.GetDefinition(@"Json")
|
||||
: null;
|
||||
|
@ -5,6 +5,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:res="clr-namespace:PettingZoo.UI.Tab.Publisher"
|
||||
xmlns:controls="clr-namespace:PettingZoo.WPF.Controls;assembly=PettingZoo.WPF"
|
||||
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
@ -13,6 +14,8 @@
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<controls:GridLayout Style="{StaticResource Form}" Margin="4" Grid.IsSharedSizeScope="True">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="8"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
@ -20,8 +23,7 @@
|
||||
<RowDefinition Height="16"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="16"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="16" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
@ -30,37 +32,47 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="1">
|
||||
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="1">
|
||||
<ToggleButton Style="{StaticResource TypeSelection}" IsChecked="{Binding MessageTypeRaw}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Source="{svgc:SvgImage Source=/Images/RabbitMQ.svg, AppName=PettingZoo}" Style="{StaticResource ButtonIcon}" />
|
||||
<TextBlock Text="{x:Static res:PublisherViewStrings.OptionMessageTypeRaw}" />
|
||||
</StackPanel>
|
||||
</ToggleButton>
|
||||
<ToggleButton Style="{StaticResource TypeSelection}" IsChecked="{Binding MessageTypeTapeti}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Source="/Images/Tapeti.png" Style="{StaticResource ButtonIcon}" />
|
||||
<TextBlock Text="{x:Static res:PublisherViewStrings.OptionMessageTypeTapeti}" />
|
||||
</StackPanel>
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="1">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<RadioButton Content="{x:Static res:PublisherViewStrings.LabelSendToExchange}" IsChecked="{Binding SendToExchange}" Style="{StaticResource TypeSelection}" />
|
||||
<RadioButton Content="{x:Static res:PublisherViewStrings.LabelSendToQueue}" IsChecked="{Binding SendToQueue}" Style="{StaticResource TypeSelection}" />
|
||||
</StackPanel>
|
||||
</Label>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{x:Static res:PublisherViewStrings.LabelExchange}" Visibility="{Binding ExchangeVisibility}" />
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Exchange, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding ExchangeVisibility}" />
|
||||
<Label Grid.Row="3" Grid.Column="0" Content="{x:Static res:PublisherViewStrings.LabelExchange}" Visibility="{Binding ExchangeVisibility}" />
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Exchange, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding ExchangeVisibility}" />
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="{x:Static res:PublisherViewStrings.LabelRoutingKey}" Visibility="{Binding ExchangeVisibility}" />
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding RoutingKey, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding ExchangeVisibility}" />
|
||||
<Label Grid.Row="4" Grid.Column="0" Content="{x:Static res:PublisherViewStrings.LabelRoutingKey}" Visibility="{Binding ExchangeVisibility}" />
|
||||
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding RoutingKey, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding ExchangeVisibility}" />
|
||||
|
||||
<Label Grid.Row="3" Grid.Column="0" Content="{x:Static res:PublisherViewStrings.LabelQueue}" Visibility="{Binding QueueVisibility}" />
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Queue, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding QueueVisibility}" />
|
||||
<Label Grid.Row="5" Grid.Column="0" Content="{x:Static res:PublisherViewStrings.LabelQueue}" Visibility="{Binding QueueVisibility}" />
|
||||
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding Queue, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding QueueVisibility}" />
|
||||
|
||||
<Label Grid.Row="5" Grid.Column="0" Content="{x:Static res:PublisherViewStrings.LabelReplyTo}" />
|
||||
<StackPanel Orientation="Horizontal" Grid.Row="5" Grid.Column="1">
|
||||
<Label Grid.Row="7" Grid.Column="0" Content="{x:Static res:PublisherViewStrings.LabelReplyTo}" />
|
||||
<StackPanel Orientation="Horizontal" Grid.Row="7" Grid.Column="1">
|
||||
<RadioButton Content="{x:Static res:PublisherViewStrings.LabelReplyToSpecified}" IsChecked="{Binding ReplyToSpecified}" Style="{StaticResource TypeSelection}" />
|
||||
<RadioButton Content="{x:Static res:PublisherViewStrings.LabelReplyToNewSubscriber}" IsChecked="{Binding ReplyToNewSubscriber}" Style="{StaticResource TypeSelection}" />
|
||||
</StackPanel>
|
||||
<TextBox Grid.Row="6" Grid.Column="1" Text="{Binding ReplyTo}" IsEnabled="{Binding ReplyToSpecified}" />
|
||||
<TextBox Grid.Row="8" Grid.Column="1" Text="{Binding ReplyTo}" IsEnabled="{Binding ReplyToSpecified}" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center">
|
||||
<ToggleButton Content="{x:Static res:PublisherViewStrings.OptionMessageTypeRaw}" Style="{StaticResource TypeSelection}" IsChecked="{Binding MessageTypeRaw}" />
|
||||
<ToggleButton Content="{x:Static res:PublisherViewStrings.OptionMessageTypeTapeti}" Style="{StaticResource TypeSelection}" IsChecked="{Binding MessageTypeTapeti}" />
|
||||
</StackPanel>
|
||||
<ContentControl Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="2" Margin="0 8 0 0" Content="{Binding MessageTypeControl}" />
|
||||
|
||||
<ContentControl Grid.Row="9" Grid.Column="0" Grid.ColumnSpan="2" Margin="0 8 0 0" Content="{Binding MessageTypeControl}" />
|
||||
|
||||
<Button Grid.Row="10" Grid.Column="1" Command="{Binding PublishCommand}" Content="{x:Static res:PublisherViewStrings.CommandPublish}" HorizontalAlignment="Left" />
|
||||
<Button Grid.Row="11" Grid.Column="1" Command="{Binding PublishCommand}" Content="{x:Static res:PublisherViewStrings.CommandPublish}" HorizontalAlignment="Left" />
|
||||
</controls:GridLayout>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
|
@ -5,6 +5,7 @@ using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using PettingZoo.Core.Connection;
|
||||
using PettingZoo.Core.Generator;
|
||||
using PettingZoo.Core.Macros;
|
||||
using PettingZoo.WPF.ViewModel;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Publisher
|
||||
@ -20,8 +21,8 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
{
|
||||
private readonly IConnection connection;
|
||||
private readonly IExampleGenerator exampleGenerator;
|
||||
private readonly IPayloadMacroProcessor payloadMacroProcessor;
|
||||
private readonly ITabFactory tabFactory;
|
||||
private readonly ITabHostProvider tabHostProvider;
|
||||
|
||||
private bool sendToExchange = true;
|
||||
private string exchange = "";
|
||||
@ -156,12 +157,12 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
string IPublishDestination.RoutingKey => SendToExchange ? RoutingKey : Queue;
|
||||
|
||||
|
||||
public PublisherViewModel(ITabHostProvider tabHostProvider, ITabFactory tabFactory, IConnection connection, IExampleGenerator exampleGenerator, ReceivedMessageInfo? fromReceivedMessage = null)
|
||||
public PublisherViewModel(ITabFactory tabFactory, IConnection connection, IExampleGenerator exampleGenerator, IPayloadMacroProcessor payloadMacroProcessor, ReceivedMessageInfo? fromReceivedMessage = null)
|
||||
{
|
||||
this.connection = connection;
|
||||
this.exampleGenerator = exampleGenerator;
|
||||
this.payloadMacroProcessor = payloadMacroProcessor;
|
||||
this.tabFactory = tabFactory;
|
||||
this.tabHostProvider = tabHostProvider;
|
||||
|
||||
publishCommand = new DelegateCommand(PublishExecute, PublishCanExecute);
|
||||
|
||||
@ -209,7 +210,7 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
|
||||
if (rawPublisherView == null)
|
||||
{
|
||||
rawPublisherViewModel = new RawPublisherViewModel(connection, this);
|
||||
rawPublisherViewModel = new RawPublisherViewModel(connection, this, payloadMacroProcessor);
|
||||
rawPublisherViewModel.PublishCommand.CanExecuteChanged += (_, _) =>
|
||||
{
|
||||
publishCommand.RaiseCanExecuteChanged();
|
||||
@ -230,7 +231,7 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
|
||||
if (tapetiPublisherView == null)
|
||||
{
|
||||
tapetiPublisherViewModel = new TapetiPublisherViewModel(connection, this, exampleGenerator);
|
||||
tapetiPublisherViewModel = new TapetiPublisherViewModel(connection, this, exampleGenerator, payloadMacroProcessor);
|
||||
tapetiPublisherViewModel.PublishCommand.CanExecuteChanged += (_, _) =>
|
||||
{
|
||||
publishCommand.RaiseCanExecuteChanged();
|
||||
@ -265,14 +266,14 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
|
||||
if (TapetiPublisherViewModel.IsTapetiMessage(fromReceivedMessage))
|
||||
{
|
||||
var tapetiPublisherViewModel = new TapetiPublisherViewModel(connection, this, exampleGenerator, fromReceivedMessage);
|
||||
var tapetiPublisherViewModel = new TapetiPublisherViewModel(connection, this, exampleGenerator, payloadMacroProcessor, fromReceivedMessage);
|
||||
tapetiPublisherView = new TapetiPublisherView(tapetiPublisherViewModel);
|
||||
|
||||
MessageType = MessageType.Tapeti;
|
||||
}
|
||||
else
|
||||
{
|
||||
var rawPublisherViewModel = new RawPublisherViewModel(connection, this, fromReceivedMessage);
|
||||
var rawPublisherViewModel = new RawPublisherViewModel(connection, this, payloadMacroProcessor, fromReceivedMessage);
|
||||
rawPublisherView = new RawPublisherView(rawPublisherViewModel);
|
||||
|
||||
MessageType = MessageType.Raw;
|
||||
@ -280,17 +281,20 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
}
|
||||
|
||||
|
||||
public string? GetReplyTo()
|
||||
public string? GetReplyTo(ref string? correlationId)
|
||||
{
|
||||
if (ReplyToSpecified)
|
||||
return string.IsNullOrEmpty(ReplyTo) ? null : ReplyTo;
|
||||
|
||||
var subscriber = connection.Subscribe();
|
||||
var tab = tabFactory.CreateSubscriberTab(connection, subscriber);
|
||||
tabHostProvider.Instance.AddTab(tab);
|
||||
correlationId = PublisherViewStrings.ReplyToCorrelationIdPrefix + (SendToExchange ? RoutingKey : Queue);
|
||||
return tabFactory.CreateReplySubscriberTab(connection);
|
||||
}
|
||||
|
||||
subscriber.Start();
|
||||
return subscriber.QueueName;
|
||||
|
||||
public void SetExchangeDestination(string newExchange, string newRoutingKey)
|
||||
{
|
||||
Exchange = newExchange;
|
||||
RoutingKey = newRoutingKey;
|
||||
}
|
||||
|
||||
|
||||
|
@ -168,6 +168,15 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Re: .
|
||||
/// </summary>
|
||||
public static string ReplyToCorrelationIdPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("ReplyToCorrelationIdPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Publish: {0}.
|
||||
/// </summary>
|
||||
|
@ -112,10 +112,10 @@
|
||||
<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>
|
||||
<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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="CommandPublish" xml:space="preserve">
|
||||
<value>Publish</value>
|
||||
@ -153,6 +153,9 @@
|
||||
<data name="OptionMessageTypeTapeti" xml:space="preserve">
|
||||
<value>Tapeti message</value>
|
||||
</data>
|
||||
<data name="ReplyToCorrelationIdPrefix" xml:space="preserve">
|
||||
<value>Re: </value>
|
||||
</data>
|
||||
<data name="TabTitle" xml:space="preserve">
|
||||
<value>Publish: {0}</value>
|
||||
</data>
|
||||
|
@ -131,6 +131,7 @@
|
||||
</Button>
|
||||
|
||||
<Label Grid.Row="14" Grid.Column="0" Content="{x:Static publisher:RawPublisherViewStrings.LabelPayload}" />
|
||||
<publisher:PayloadEditorControl Grid.Row="14" Grid.Column="1" Payload="{Binding Payload}" ContentType="{Binding ContentType}" Height="350"/>
|
||||
<publisher:PayloadEditorControl Grid.Row="14" Grid.Column="1" Payload="{Binding Payload}" ContentType="{Binding ContentType}" Height="350" x:Name="PayloadEditor"
|
||||
EnableMacros="{Binding EnableMacros}" />
|
||||
</controls:GridLayout>
|
||||
</UserControl>
|
||||
|
@ -3,6 +3,7 @@ using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using PettingZoo.Core.Macros;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Publisher
|
||||
{
|
||||
@ -22,6 +23,8 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
DataContext = viewModel;
|
||||
InitializeComponent();
|
||||
|
||||
PayloadEditor.MacroProcessor = viewModel.PayloadMacroProcessor;
|
||||
|
||||
checkEmptyHeaderTimer = new DispatcherTimer();
|
||||
checkEmptyHeaderTimer.Tick += CheckEmptyHeaderTimerOnTick;
|
||||
checkEmptyHeaderTimer.Interval = TimeSpan.FromMilliseconds(50);
|
||||
|
@ -7,6 +7,7 @@ using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using PettingZoo.Core.Connection;
|
||||
using PettingZoo.Core.Macros;
|
||||
using PettingZoo.WPF.ViewModel;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Publisher
|
||||
@ -32,6 +33,7 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
private string typeProperty = "";
|
||||
private string userId = "";
|
||||
private string payload = "";
|
||||
private bool enableMacros;
|
||||
|
||||
|
||||
|
||||
@ -118,6 +120,12 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
set => SetField(ref payload, value, delegateCommandsChanged: new [] { publishCommand });
|
||||
}
|
||||
|
||||
public bool EnableMacros
|
||||
{
|
||||
get => enableMacros;
|
||||
set => SetField(ref enableMacros, value);
|
||||
}
|
||||
|
||||
|
||||
public ObservableCollection<Header> Headers { get; } = new();
|
||||
|
||||
@ -125,6 +133,8 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
public ICommand PublishCommand => publishCommand;
|
||||
public ICommand PropertiesExpandCollapseCommand => propertiesExpandCollapseCommand;
|
||||
|
||||
public IPayloadMacroProcessor PayloadMacroProcessor { get; }
|
||||
|
||||
|
||||
public bool PropertiesExpanded
|
||||
{
|
||||
@ -145,8 +155,10 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
protected Header LastHeader;
|
||||
|
||||
|
||||
public RawPublisherViewModel(IConnection connection, IPublishDestination publishDestination, BaseMessageInfo? receivedMessage = null)
|
||||
public RawPublisherViewModel(IConnection connection, IPublishDestination publishDestination, IPayloadMacroProcessor payloadMacroProcessor, BaseMessageInfo? receivedMessage = null)
|
||||
{
|
||||
PayloadMacroProcessor = payloadMacroProcessor;
|
||||
|
||||
this.connection = connection;
|
||||
this.publishDestination = publishDestination;
|
||||
|
||||
@ -242,24 +254,31 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
}
|
||||
}
|
||||
|
||||
var encodedPayload = Encoding.UTF8.GetBytes(
|
||||
EnableMacros
|
||||
? PayloadMacroProcessor.Apply(Payload)
|
||||
: Payload
|
||||
);
|
||||
|
||||
var headers = Headers.Where(h => h.IsValid()).ToDictionary(h => h.Key, h => h.Value);
|
||||
var publishCorrelationId = NullIfEmpty(CorrelationId);
|
||||
var replyTo = publishDestination.GetReplyTo(ref publishCorrelationId);
|
||||
|
||||
connection.Publish(new PublishMessageInfo(
|
||||
publishDestination.Exchange,
|
||||
publishDestination.RoutingKey,
|
||||
Encoding.UTF8.GetBytes(Payload),
|
||||
encodedPayload,
|
||||
new MessageProperties(headers)
|
||||
{
|
||||
AppId = NullIfEmpty(AppId),
|
||||
ContentEncoding = NullIfEmpty(ContentEncoding),
|
||||
ContentType = NullIfEmpty(ContentType),
|
||||
CorrelationId = NullIfEmpty(CorrelationId),
|
||||
CorrelationId = publishCorrelationId,
|
||||
DeliveryMode = deliveryMode,
|
||||
Expiration = NullIfEmpty(Expiration),
|
||||
MessageId = NullIfEmpty(MessageId),
|
||||
Priority = priorityValue,
|
||||
ReplyTo = publishDestination.GetReplyTo(),
|
||||
ReplyTo = replyTo,
|
||||
Timestamp = timestampValue,
|
||||
Type = NullIfEmpty(TypeProperty),
|
||||
UserId = NullIfEmpty(UserId)
|
||||
@ -309,7 +328,7 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
|
||||
public class DesignTimeRawPublisherViewModel : RawPublisherViewModel
|
||||
{
|
||||
public DesignTimeRawPublisherViewModel() : base(null!, null!)
|
||||
public DesignTimeRawPublisherViewModel() : base(null!, null!, null!)
|
||||
{
|
||||
PropertiesExpanded = true;
|
||||
|
||||
|
@ -46,6 +46,7 @@
|
||||
</Grid>
|
||||
|
||||
<Label Grid.Row="6" Grid.Column="0" Content="{x:Static publisher:TapetiPublisherViewStrings.LabelPayload}" />
|
||||
<publisher:PayloadEditorControl Grid.Row="6" Grid.Column="1" Payload="{Binding Payload}" FixedJson="True" Height="350" x:Name="PayloadEditor"/>
|
||||
<publisher:PayloadEditorControl Grid.Row="6" Grid.Column="1" Payload="{Binding Payload}" FixedJson="True" Height="350" x:Name="PayloadEditor"
|
||||
EnableMacros="{Binding EnableMacros}" />
|
||||
</controls:GridLayout>
|
||||
</UserControl>
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using PettingZoo.Core.Macros;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Publisher
|
||||
{
|
||||
@ -15,6 +16,7 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
InitializeComponent();
|
||||
|
||||
PayloadEditor.Validator = viewModel;
|
||||
PayloadEditor.MacroProcessor = viewModel.PayloadMacroProcessor;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,9 +2,9 @@
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using PettingZoo.Core.Connection;
|
||||
using PettingZoo.Core.Generator;
|
||||
using PettingZoo.Core.Macros;
|
||||
using PettingZoo.Core.Validation;
|
||||
using PettingZoo.WPF.ViewModel;
|
||||
using IConnection = PettingZoo.Core.Connection.IConnection;
|
||||
@ -21,6 +21,7 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
|
||||
private string correlationId = "";
|
||||
private string payload = "";
|
||||
private bool enableMacros;
|
||||
private string className = "";
|
||||
private string assemblyName = "";
|
||||
private Window? tabHostWindow;
|
||||
@ -68,9 +69,17 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
}
|
||||
|
||||
|
||||
public bool EnableMacros
|
||||
{
|
||||
get => enableMacros;
|
||||
set => SetField(ref enableMacros, value);
|
||||
}
|
||||
|
||||
|
||||
public ICommand PublishCommand => publishCommand;
|
||||
public ICommand BrowseClassCommand => browseClassCommand;
|
||||
|
||||
public IPayloadMacroProcessor PayloadMacroProcessor { get; }
|
||||
|
||||
|
||||
public static bool IsTapetiMessage(ReceivedMessageInfo receivedMessage)
|
||||
@ -100,8 +109,11 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
}
|
||||
|
||||
|
||||
public TapetiPublisherViewModel(IConnection connection, IPublishDestination publishDestination, IExampleGenerator exampleGenerator, ReceivedMessageInfo? receivedMessage = null)
|
||||
public TapetiPublisherViewModel(IConnection connection, IPublishDestination publishDestination, IExampleGenerator exampleGenerator,
|
||||
IPayloadMacroProcessor payloadMacroProcessor, ReceivedMessageInfo? receivedMessage = null)
|
||||
{
|
||||
PayloadMacroProcessor = payloadMacroProcessor;
|
||||
|
||||
this.connection = connection;
|
||||
this.publishDestination = publishDestination;
|
||||
this.exampleGenerator = exampleGenerator;
|
||||
@ -135,6 +147,9 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
AssemblyName = classTypeExample.AssemblyName;
|
||||
ClassName = classTypeExample.FullClassName;
|
||||
|
||||
if (classTypeExample.TryGetPublishDestination(out var exchange, out var routingKey))
|
||||
publishDestination.SetExchangeDestination(exchange, routingKey);
|
||||
|
||||
validatingExample = classTypeExample as IValidatingExample;
|
||||
break;
|
||||
}
|
||||
@ -151,20 +166,30 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
{
|
||||
return string.IsNullOrEmpty(value) ? null : value;
|
||||
}
|
||||
|
||||
|
||||
var encodedPayload = Encoding.UTF8.GetBytes(
|
||||
EnableMacros
|
||||
? PayloadMacroProcessor.Apply(Payload)
|
||||
: Payload
|
||||
);
|
||||
|
||||
|
||||
var publishCorrelationId = NullIfEmpty(CorrelationId);
|
||||
var replyTo = publishDestination.GetReplyTo(ref publishCorrelationId);
|
||||
|
||||
connection.Publish(new PublishMessageInfo(
|
||||
publishDestination.Exchange,
|
||||
publishDestination.RoutingKey,
|
||||
Encoding.UTF8.GetBytes(Payload),
|
||||
encodedPayload,
|
||||
new MessageProperties(new Dictionary<string, string>
|
||||
{
|
||||
{ @"classType", $"{ClassName}:{AssemblyName}" }
|
||||
})
|
||||
{
|
||||
ContentType = @"application/json",
|
||||
CorrelationId = NullIfEmpty(CorrelationId),
|
||||
CorrelationId = publishCorrelationId,
|
||||
DeliveryMode = MessageDeliveryMode.Persistent,
|
||||
ReplyTo = publishDestination.GetReplyTo()
|
||||
ReplyTo = replyTo
|
||||
}));
|
||||
}
|
||||
|
||||
@ -199,7 +224,7 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
|
||||
public class DesignTimeTapetiPublisherViewModel : TapetiPublisherViewModel
|
||||
{
|
||||
public DesignTimeTapetiPublisherViewModel() : base(null!, null!, null!)
|
||||
public DesignTimeTapetiPublisherViewModel() : base(null!, null!, null!, null!)
|
||||
{
|
||||
AssemblyName = "Messaging.Example";
|
||||
ClassName = "Messaging.Example.ExampleMessage";
|
||||
|
@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Subscriber
|
||||
{
|
||||
public class SameMessageVisibilityConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return ReferenceEquals(values[0], values[1])
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
}
|
||||
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -13,9 +13,6 @@
|
||||
d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance res:DesignTimeSubscriberViewModel, IsDesignTimeCreatable=True}"
|
||||
Background="White">
|
||||
<UserControl.Resources>
|
||||
<res:SameMessageVisibilityConverter x:Key="SameMessageVisibilityConverter" />
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
@ -64,7 +61,8 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" Text="{Binding ReceivedTimestamp, StringFormat=g}" Style="{StaticResource Timestamp}" />
|
||||
<TextBlock Grid.Column="1" Text="{Binding RoutingKey}" Style="{StaticResource RoutingKey}" />
|
||||
<TextBlock Grid.Column="1" Text="{Binding RoutingKey}" Style="{StaticResource RoutingKey}" Visibility="{Binding DataContext.StandardTabVisibility, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" />
|
||||
<TextBlock Grid.Column="1" Text="{Binding Properties.CorrelationId}" Style="{StaticResource RoutingKey}" Visibility="{Binding DataContext.ReplyTabVisibility, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" />
|
||||
|
||||
<Grid.ContextMenu>
|
||||
<ContextMenu>
|
||||
|
@ -21,10 +21,9 @@ using Timer = System.Threading.Timer;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Subscriber
|
||||
{
|
||||
public class SubscriberViewModel : BaseViewModel, ITabToolbarCommands, ITabActivate
|
||||
public class SubscriberViewModel : BaseViewModel, IDisposable, ITabToolbarCommands, ITabActivate
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly ITabHostProvider tabHostProvider;
|
||||
private readonly ITabFactory tabFactory;
|
||||
private readonly IConnection? connection;
|
||||
private readonly ISubscriber subscriber;
|
||||
@ -76,16 +75,43 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
set => SetField(ref selectedMessageProperties, value);
|
||||
}
|
||||
|
||||
public string Title =>
|
||||
(subscriber.Exchange != null ? $"{subscriber.Exchange} - {subscriber.RoutingKey}" : $"{subscriber.QueueName}") +
|
||||
(tabActive || unreadCount == 0 ? "" : $" ({unreadCount})");
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
var title = new StringBuilder();
|
||||
|
||||
if (IsReplyTab)
|
||||
title.Append(SubscriberViewStrings.ReplyTabTitle);
|
||||
else if (subscriber.Exchange != null)
|
||||
title.Append(subscriber.Exchange).Append(" - ").Append(subscriber.RoutingKey);
|
||||
else
|
||||
title.Append(subscriber.QueueName);
|
||||
|
||||
if (!tabActive && unreadCount > 0)
|
||||
title.Append(" (").Append(unreadCount).Append(')');
|
||||
|
||||
return title.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<TabToolbarCommand> ToolbarCommands => toolbarCommands;
|
||||
|
||||
|
||||
public SubscriberViewModel(ILogger logger, ITabHostProvider tabHostProvider, ITabFactory tabFactory, IConnection? connection, ISubscriber subscriber, IExportImportFormatProvider exportImportFormatProvider)
|
||||
public bool IsReplyTab { get; }
|
||||
|
||||
// ReSharper disable UnusedMember.Global - used via BindingProxy
|
||||
public Visibility StandardTabVisibility => !IsReplyTab ? Visibility.Visible : Visibility.Collapsed;
|
||||
public Visibility ReplyTabVisibility => IsReplyTab ? Visibility.Visible : Visibility.Collapsed;
|
||||
// ReSharper restore UnusedMember.Global
|
||||
|
||||
|
||||
public SubscriberViewModel(ILogger logger, ITabFactory tabFactory, IConnection? connection, ISubscriber subscriber, IExportImportFormatProvider exportImportFormatProvider, bool isReplyTab)
|
||||
{
|
||||
IsReplyTab = isReplyTab;
|
||||
|
||||
this.logger = logger;
|
||||
this.tabHostProvider = tabHostProvider;
|
||||
this.tabFactory = tabFactory;
|
||||
this.connection = connection;
|
||||
this.subscriber = subscriber;
|
||||
@ -111,6 +137,15 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
subscriber.Start();
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
newMessageTimer?.Dispose();
|
||||
subscriber.Dispose();
|
||||
}
|
||||
|
||||
|
||||
private void ClearExecute()
|
||||
{
|
||||
Messages.Clear();
|
||||
@ -222,8 +257,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
if (connection == null)
|
||||
return;
|
||||
|
||||
var publisherTab = tabFactory.CreatePublisherTab(connection, SelectedMessage);
|
||||
tabHostProvider.Instance.AddTab(publisherTab);
|
||||
tabFactory.CreatePublisherTab(connection, SelectedMessage);
|
||||
}
|
||||
|
||||
|
||||
@ -320,7 +354,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
|
||||
public class DesignTimeSubscriberViewModel : SubscriberViewModel
|
||||
{
|
||||
public DesignTimeSubscriberViewModel() : base(null!, null!, null!, null!, new DesignTimeSubscriber(), null!)
|
||||
public DesignTimeSubscriberViewModel() : base(null!, null!, null!, new DesignTimeSubscriber(), null!, false)
|
||||
{
|
||||
for (var i = 1; i <= 5; i++)
|
||||
(i > 2 ? UnreadMessages : Messages).Add(new ReceivedMessageInfo(
|
||||
@ -340,9 +374,9 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
|
||||
private class DesignTimeSubscriber : ISubscriber
|
||||
{
|
||||
public ValueTask DisposeAsync()
|
||||
public void Dispose()
|
||||
{
|
||||
return default;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -185,5 +185,14 @@ namespace PettingZoo.UI.Tab.Subscriber {
|
||||
return ResourceManager.GetString("PropertyValue", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Replies.
|
||||
/// </summary>
|
||||
public static string ReplyTabTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("ReplyTabTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,4 +159,7 @@
|
||||
<data name="PropertyValue" xml:space="preserve">
|
||||
<value>Value</value>
|
||||
</data>
|
||||
<data name="ReplyTabTitle" xml:space="preserve">
|
||||
<value>Replies</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
@ -13,6 +14,7 @@ namespace PettingZoo.UI.Tab.Undocked
|
||||
private readonly ITabHostProvider tabHostProvider;
|
||||
private readonly ITab tab;
|
||||
private readonly DelegateCommand dockCommand;
|
||||
private bool docked;
|
||||
|
||||
|
||||
public string Title => tab.Title;
|
||||
@ -43,13 +45,18 @@ namespace PettingZoo.UI.Tab.Undocked
|
||||
|
||||
private void DockCommandExecute()
|
||||
{
|
||||
docked = true;
|
||||
tabHostProvider.Instance.DockTab(tab);
|
||||
}
|
||||
|
||||
|
||||
public void WindowClosed()
|
||||
{
|
||||
if (docked)
|
||||
return;
|
||||
|
||||
tabHostProvider.Instance.UndockedTabClosed(tab);
|
||||
(tab as IDisposable)?.Dispose();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Undocked
|
||||
{
|
||||
|
@ -8,7 +8,7 @@ using System.Windows.Controls;
|
||||
|
||||
namespace PettingZoo.UI.Tab
|
||||
{
|
||||
public class ViewTab<TView, TViewModel> : ITab, ITabToolbarCommands, ITabActivate, ITabHostWindowNotify where TView : ContentControl where TViewModel : INotifyPropertyChanged
|
||||
public class ViewTab<TView, TViewModel> : IDisposable, ITab, ITabToolbarCommands, ITabActivate, ITabHostWindowNotify where TView : ContentControl where TViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public string Title => getTitle(viewModel);
|
||||
public ContentControl Content { get; }
|
||||
@ -63,5 +63,12 @@ namespace PettingZoo.UI.Tab
|
||||
{
|
||||
(viewModel as ITabHostWindowNotify)?.HostWindowChanged(hostWindow);
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
(viewModel as IDisposable)?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
using PettingZoo.Core.Connection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using PettingZoo.Core.Connection;
|
||||
using PettingZoo.Core.ExportImport;
|
||||
using PettingZoo.Core.Generator;
|
||||
using PettingZoo.Core.Macros;
|
||||
using PettingZoo.UI.Tab.Publisher;
|
||||
using PettingZoo.UI.Tab.Subscriber;
|
||||
using Serilog;
|
||||
@ -13,34 +16,119 @@ namespace PettingZoo.UI.Tab
|
||||
private readonly ITabHostProvider tabHostProvider;
|
||||
private readonly IExampleGenerator exampleGenerator;
|
||||
private readonly IExportImportFormatProvider exportImportFormatProvider;
|
||||
private readonly IPayloadMacroProcessor payloadMacroProcessor;
|
||||
|
||||
// Not the cleanest way, but this factory itself can't be singleton without (justifyable) upsetting SimpleInjector
|
||||
private static ISubscriber? replySubscriber;
|
||||
private static ITab? replySubscriberTab;
|
||||
|
||||
|
||||
public ViewTabFactory(ILogger logger, ITabHostProvider tabHostProvider, IExampleGenerator exampleGenerator, IExportImportFormatProvider exportImportFormatProvider)
|
||||
public ViewTabFactory(ILogger logger, ITabHostProvider tabHostProvider, IExampleGenerator exampleGenerator, IExportImportFormatProvider exportImportFormatProvider,
|
||||
IPayloadMacroProcessor payloadMacroProcessor)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.tabHostProvider = tabHostProvider;
|
||||
this.exampleGenerator = exampleGenerator;
|
||||
this.exportImportFormatProvider = exportImportFormatProvider;
|
||||
this.payloadMacroProcessor = payloadMacroProcessor;
|
||||
}
|
||||
|
||||
|
||||
public ITab CreateSubscriberTab(IConnection? connection, ISubscriber subscriber)
|
||||
public void CreateSubscriberTab(IConnection? connection, ISubscriber subscriber)
|
||||
{
|
||||
var viewModel = new SubscriberViewModel(logger, tabHostProvider, this, connection, subscriber, exportImportFormatProvider);
|
||||
return new ViewTab<SubscriberView, SubscriberViewModel>(
|
||||
new SubscriberView(viewModel),
|
||||
viewModel,
|
||||
vm => vm.Title);
|
||||
InternalCreateSubscriberTab(connection, subscriber, false);
|
||||
}
|
||||
|
||||
|
||||
public ITab CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null)
|
||||
|
||||
public string CreateReplySubscriberTab(IConnection connection)
|
||||
{
|
||||
var viewModel = new PublisherViewModel(tabHostProvider, this, connection, exampleGenerator, fromReceivedMessage);
|
||||
return new ViewTab<PublisherView, PublisherViewModel>(
|
||||
if (replySubscriber?.QueueName != null && replySubscriberTab != null)
|
||||
{
|
||||
tabHostProvider.Instance.ActivateTab(replySubscriberTab);
|
||||
return replySubscriber.QueueName;
|
||||
}
|
||||
|
||||
replySubscriber = new SubscriberDecorator(connection.Subscribe(), () =>
|
||||
{
|
||||
replySubscriber = null;
|
||||
replySubscriberTab = null;
|
||||
});
|
||||
|
||||
replySubscriber.Start();
|
||||
|
||||
replySubscriberTab = InternalCreateSubscriberTab(connection, replySubscriber, true);
|
||||
return replySubscriber.QueueName!;
|
||||
}
|
||||
|
||||
|
||||
public void CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null)
|
||||
{
|
||||
var viewModel = new PublisherViewModel(this, connection, exampleGenerator, payloadMacroProcessor, fromReceivedMessage);
|
||||
var tab = new ViewTab<PublisherView, PublisherViewModel>(
|
||||
new PublisherView(viewModel),
|
||||
viewModel,
|
||||
vm => vm.Title);
|
||||
|
||||
tabHostProvider.Instance.AddTab(tab);
|
||||
}
|
||||
|
||||
|
||||
private ITab InternalCreateSubscriberTab(IConnection? connection, ISubscriber subscriber, bool isReplyTab)
|
||||
{
|
||||
var viewModel = new SubscriberViewModel(logger, this, connection, subscriber, exportImportFormatProvider, isReplyTab);
|
||||
var tab = new ViewTab<SubscriberView, SubscriberViewModel>(
|
||||
new SubscriberView(viewModel),
|
||||
viewModel,
|
||||
vm => vm.Title);
|
||||
|
||||
tabHostProvider.Instance.AddTab(tab);
|
||||
return tab;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class SubscriberDecorator : ISubscriber
|
||||
{
|
||||
private readonly ISubscriber decoratedSubscriber;
|
||||
private readonly Action onDispose;
|
||||
|
||||
|
||||
public string? QueueName => decoratedSubscriber.QueueName;
|
||||
public string? Exchange => decoratedSubscriber.Exchange;
|
||||
public string? RoutingKey => decoratedSubscriber.RoutingKey;
|
||||
|
||||
public event EventHandler<MessageReceivedEventArgs>? MessageReceived;
|
||||
|
||||
|
||||
public SubscriberDecorator(ISubscriber decoratedSubscriber, Action onDispose)
|
||||
{
|
||||
this.decoratedSubscriber = decoratedSubscriber;
|
||||
this.onDispose = onDispose;
|
||||
|
||||
decoratedSubscriber.MessageReceived += (sender, args) =>
|
||||
{
|
||||
MessageReceived?.Invoke(sender, args);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
decoratedSubscriber.Dispose();
|
||||
onDispose();
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<ReceivedMessageInfo> GetInitialMessages()
|
||||
{
|
||||
return decoratedSubscriber.GetInitialMessages();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
decoratedSubscriber.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user