1
0
mirror of synced 2024-11-25 04:03:08 +01:00

Basic implementation for saving and loading publisher messages

This commit is contained in:
Mark van Renswoude 2022-01-23 11:41:57 +01:00
parent 317eebe789
commit b3c432d629
53 changed files with 1298 additions and 285 deletions

View File

@ -73,7 +73,7 @@ namespace PettingZoo.Benchmark
[Benchmark] [Benchmark]
public string? TestReaderWriter() public string TestReaderWriter()
{ {
using var stringReader = new StringReader(testJson); using var stringReader = new StringReader(testJson);
using var jsonTextReader = new JsonTextReader(stringReader); using var jsonTextReader = new JsonTextReader(stringReader);

View File

@ -0,0 +1,58 @@
using System.Collections.Generic;
using PettingZoo.Core.Connection;
namespace PettingZoo.Core.ExportImport.Publisher
{
public enum PublisherMessageType
{
Raw,
Tapeti
}
public class PublisherMessage
{
public PublisherMessageType MessageType { get; set; }
public bool SendToExchange { get; set; }
public string? Exchange { get; set; }
public string? RoutingKey { get; set; }
public string? Queue { get; set; }
public bool ReplyToNewSubscriber { get; set; }
public string? ReplyTo { get; set; }
public RawPublisherMessage? RawPublisherMessage { get; set; }
public TapetiPublisherMessage? TapetiPublisherMessage { get; set; }
}
public class RawPublisherMessage
{
public MessageDeliveryMode DeliveryMode { get; set; }
public string? ContentType { get; set; }
public string? CorrelationId { get; set; }
public string? AppId { get; set; }
public string? ContentEncoding { get; set; }
public string? Expiration { get; set; }
public string? MessageId { get; set; }
public string? Priority { get; set; }
public string? Timestamp { get; set; }
public string? TypeProperty { get; set; }
public string? UserId { get; set; }
public string? Payload { get; set; }
public bool EnableMacros { get; set; }
public Dictionary<string, string>? Headers { get; set; }
}
public class TapetiPublisherMessage
{
public string? CorrelationId { get; set; }
public string? Payload { get; set; }
public bool EnableMacros { get; set; }
public string? ClassName { get; set; }
public string? AssemblyName { get; set; }
}
}

View File

@ -1,6 +1,6 @@
using System; using System;
namespace PettingZoo.Core.ExportImport namespace PettingZoo.Core.ExportImport.Subscriber
{ {
public abstract class BaseProgressDecorator public abstract class BaseProgressDecorator
{ {

View File

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace PettingZoo.Core.ExportImport namespace PettingZoo.Core.ExportImport.Subscriber
{ {
public class ExportImportFormatProvider : IExportImportFormatProvider public class ExportImportFormatProvider : IExportImportFormatProvider
{ {

View File

@ -4,7 +4,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using PettingZoo.Core.Connection; using PettingZoo.Core.Connection;
namespace PettingZoo.Core.ExportImport namespace PettingZoo.Core.ExportImport.Subscriber
{ {
public interface IExportImportFormat public interface IExportImportFormat
{ {

View File

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace PettingZoo.Core.ExportImport namespace PettingZoo.Core.ExportImport.Subscriber
{ {
public interface IExportImportFormatProvider public interface IExportImportFormatProvider
{ {

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using PettingZoo.Core.Connection; using PettingZoo.Core.Connection;
namespace PettingZoo.Core.ExportImport namespace PettingZoo.Core.ExportImport.Subscriber
{ {
public class ImportSubscriber : ISubscriber public class ImportSubscriber : ISubscriber
{ {

View File

@ -2,7 +2,7 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
namespace PettingZoo.Core.ExportImport namespace PettingZoo.Core.ExportImport.Subscriber
{ {
public class ListEnumerableProgressDecorator<T> : BaseProgressDecorator, IEnumerable<T> public class ListEnumerableProgressDecorator<T> : BaseProgressDecorator, IEnumerable<T>
{ {

View File

@ -3,7 +3,7 @@ using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace PettingZoo.Core.ExportImport namespace PettingZoo.Core.ExportImport.Subscriber
{ {
public class StreamProgressDecorator : BaseProgressDecorator public class StreamProgressDecorator : BaseProgressDecorator
{ {

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace PettingZoo.Core.Rendering namespace PettingZoo.Core.Rendering
{ {

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using PettingZoo.Core.ExportImport.Publisher;
namespace PettingZoo.Core.Settings
{
public interface IPublisherMessagesRepository
{
// For now read everything into memory, you need quite a few and/or huge messsages before that becomes an issue
Task<IEnumerable<StoredPublisherMessage>> GetStored();
Task<StoredPublisherMessage> Add(string displayName, PublisherMessage message);
Task<StoredPublisherMessage> Update(Guid id, string displayName, PublisherMessage message);
Task Delete(Guid id);
}
public class StoredPublisherMessage
{
public Guid Id { get; }
public string DisplayName { get; }
public PublisherMessage Message { get; }
public StoredPublisherMessage(Guid id, string displayName, PublisherMessage message)
{
Id = id;
DisplayName = displayName;
Message = message;
}
}
}

View File

@ -0,0 +1,80 @@
using PettingZoo.Core.ExportImport.Publisher;
using PettingZoo.Core.Settings;
namespace PettingZoo.Settings.LiteDB
{
public class LiteDBPublisherMessagesRepository : BaseLiteDBRepository, IPublisherMessagesRepository
{
private const string CollectionMessages = "messages";
public LiteDBPublisherMessagesRepository() : base(@"publisherMessages")
{
}
public async Task<IEnumerable<StoredPublisherMessage>> GetStored()
{
using var database = GetDatabase();
var collection = database.GetCollection<PublisherMessageRecord>(CollectionMessages);
return (await collection.FindAllAsync())
.Select(r => new StoredPublisherMessage(r.Id, r.DisplayName, r.Message))
.ToArray();
}
public async Task<StoredPublisherMessage> Add(string displayName, PublisherMessage message)
{
using var database = GetDatabase();
var collection = database.GetCollection<PublisherMessageRecord>(CollectionMessages);
var id = Guid.NewGuid();
await collection.InsertAsync(PublisherMessageRecord.FromPublisherMessage(id, displayName, message));
return new StoredPublisherMessage(id, displayName, message);
}
public async Task<StoredPublisherMessage> Update(Guid id, string displayName, PublisherMessage message)
{
using var database = GetDatabase();
var collection = database.GetCollection<PublisherMessageRecord>(CollectionMessages);
await collection.UpdateAsync(PublisherMessageRecord.FromPublisherMessage(id, displayName, message));
return new StoredPublisherMessage(id, displayName, message);
}
public async Task Delete(Guid id)
{
using var database = GetDatabase();
var collection = database.GetCollection<PublisherMessageRecord>(CollectionMessages);
await collection.DeleteAsync(id);
}
// ReSharper disable MemberCanBePrivate.Local - for LiteDB
// ReSharper disable PropertyCanBeMadeInitOnly.Local
private class PublisherMessageRecord
{
public Guid Id { get; set; }
public string DisplayName { get; set; } = null!;
public PublisherMessage Message { get; set; } = null!;
public static PublisherMessageRecord FromPublisherMessage(Guid id, string displayName, PublisherMessage message)
{
return new PublisherMessageRecord
{
Id = id,
DisplayName = displayName,
Message = message
};
}
}
// ReSharper restore PropertyCanBeMadeInitOnly.Local
// ReSharper restore MemberCanBePrivate.Local
}
}

View File

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using PettingZoo.Core.ExportImport; using PettingZoo.Core.ExportImport.Subscriber;
namespace PettingZoo.Tapeti.Export namespace PettingZoo.Tapeti.Export
{ {

View File

@ -8,7 +8,7 @@ using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using PettingZoo.Core.Connection; using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport; using PettingZoo.Core.ExportImport.Subscriber;
namespace PettingZoo.Tapeti.Export namespace PettingZoo.Tapeti.Export

View File

@ -7,7 +7,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
using PettingZoo.Core.Connection; using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport; using PettingZoo.Core.ExportImport.Subscriber;
namespace PettingZoo.Tapeti.Export namespace PettingZoo.Tapeti.Export
{ {

View File

@ -0,0 +1,21 @@
using System.Windows;
using System.Windows.Controls;
namespace PettingZoo.WPF.Controls
{
public class NoOverflowToolbar : ToolBar
{
public NoOverflowToolbar()
{
Loaded += (_, _) =>
{
// Hide arrow on the right side of the toolbar
if (Template.FindName("OverflowGrid", this) is FrameworkElement overflowGrid)
overflowGrid.Visibility = Visibility.Collapsed;
if (Template.FindName("MainPanelBorder", this) is FrameworkElement mainPanelBorder)
mainPanelBorder.Margin = new Thickness(0);
};
}
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace PettingZoo.WPF.ValueConverters
{
public class SameReferenceConverter : IMultiValueConverter
{
public object Convert(object?[] values, Type targetType, object parameter, CultureInfo culture)
{
return ReferenceEquals(values[0], values[1]);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

View File

@ -0,0 +1,22 @@
<?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>
<circle style="fill:#F29C21;" cx="44.5" cy="46" r="12"/>
<path style="fill:#FFFFFF;" d="M50.5,47h-12c-0.552,0-1-0.448-1-1s0.448-1,1-1h12c0.552,0,1,0.448,1,1S51.052,47,50.5,47z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,32 +1,53 @@
<?xml version="1.0" encoding="iso-8859-1"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg
<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" version="1.1"
viewBox="0 0 58.707 58.707" style="enable-background:new 0 0 58.707 58.707;" xml:space="preserve"> viewBox="0 0 25.2705 25.269251"
<g> xml:space="preserve"
<g> xmlns="http://www.w3.org/2000/svg"
<polygon style="fill:#EFEBDE;" points="46.072,14 32.072,0 1.072,0 1.072,58 46.072,58 "/> xmlns:svg="http://www.w3.org/2000/svg">
<g> <g
<path style="fill:#D5D0BB;" d="M11.072,23h25c0.552,0,1-0.447,1-1s-0.448-1-1-1h-25c-0.552,0-1,0.447-1,1S10.52,23,11.072,23z"/> id="g18"
<path style="fill:#D5D0BB;" d="M11.072,15h10c0.552,0,1-0.447,1-1s-0.448-1-1-1h-10c-0.552,0-1,0.447-1,1S10.52,15,11.072,15z"/> transform="translate(-32.36475,-33.43775)">
<path style="fill:#D5D0BB;" d="M36.072,29h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S36.624,29,36.072,29z"/> <g
<path style="fill:#D5D0BB;" d="M36.072,37h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S36.624,37,36.072,37z"/> id="g16">
<path style="fill:#D5D0BB;" d="M36.072,45h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S36.624,45,36.072,45z"/> <polygon
</g> style="fill:#eddcc7"
<polygon style="fill:#D5D0BB;" points="32.072,0 32.072,14 46.072,14 "/> points="34.205,56.511 38.852,51.865 36.201,49.214 36.194,49.222 "
</g> id="polygon2" />
<g> <path
<polygon style="fill:#EDDCC7;" points="36.201,49.214 36.194,49.222 34.205,56.511 38.852,51.865 "/> style="fill:#d75a4a"
<path style="fill:#D75A4A;" d="M55.451,35.266l-1.247-1.247c-0.775-0.775-2.032-0.775-2.807,0L47.815,37.6l2.651,2.651 d="m 55.451,35.266 -1.247,-1.247 c -0.775,-0.775 -2.032,-0.775 -2.807,0 l -3.582,3.581 2.651,2.651 z"
L55.451,35.266z"/> id="path4" />
<rect x="41.459" y="36.521" transform="matrix(0.7071 0.7071 -0.7071 0.7071 44.3228 -17.5395)" style="fill:#F29C21;" width="3.749" height="16.424"/> <rect
<polygon style="fill:#D6C4B1;" points="41.85,54.879 41.858,54.871 38.852,51.865 34.205,56.511 34.072,57 "/> x="41.459"
<path style="fill:#A34740;" d="M53.472,43.257l3.582-3.582c0.775-0.775,0.775-2.032,0-2.807l-1.602-1.602l-4.985,4.985 y="36.521"
L53.472,43.257z"/> transform="matrix(0.7071,0.7071,-0.7071,0.7071,44.3228,-17.5395)"
style="fill:#f29c21"
width="3.7490001"
height="16.424"
id="rect6" />
<polygon
style="fill:#d6c4b1"
points="38.852,51.865 34.205,56.511 34.072,57 41.85,54.879 41.858,54.871 "
id="polygon8" />
<path
style="fill:#a34740"
d="m 53.472,43.257 3.582,-3.582 c 0.775,-0.775 0.775,-2.032 0,-2.807 l -1.602,-1.602 -4.985,4.985 z"
id="path10" />
<rect x="44.036" y="39.349" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 45.1717 113.8333)" style="fill:#E18C25;" width="4.251" height="16.424"/> <rect
<path style="fill:#5E5E5E;" d="M33.365,58.707c-0.256,0-0.512-0.098-0.707-0.293c-0.391-0.391-0.391-1.023,0-1.414l2.207-2.207 x="44.035999"
c0.391-0.391,1.023-0.391,1.414,0s0.391,1.023,0,1.414l-2.207,2.207C33.877,58.609,33.621,58.707,33.365,58.707z"/> y="39.348999"
transform="matrix(-0.7071,-0.7071,0.7071,-0.7071,45.1717,113.8333)"
style="fill:#e18c25"
width="4.2509999"
height="16.424"
id="rect12" />
<path
style="fill:#5e5e5e"
d="m 33.365,58.707 c -0.256,0 -0.512,-0.098 -0.707,-0.293 -0.391,-0.391 -0.391,-1.023 0,-1.414 l 2.207,-2.207 c 0.391,-0.391 1.023,-0.391 1.414,0 0.391,0.391 0.391,1.023 0,1.414 l -2.207,2.207 c -0.195,0.195 -0.451,0.293 -0.707,0.293 z"
id="path14" />
</g> </g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,24 @@
<?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>
<circle style="fill:#26B999;" cx="44.5" cy="46" r="12"/>
<path style="fill:#FFFFFF;" d="M51.071,40.179c-0.455-0.316-1.077-0.204-1.392,0.25l-5.596,8.04l-3.949-3.242
c-0.426-0.351-1.057-0.288-1.407,0.139c-0.351,0.427-0.289,1.057,0.139,1.407l4.786,3.929c0.18,0.147,0.404,0.227,0.634,0.227
c0.045,0,0.091-0.003,0.137-0.009c0.276-0.039,0.524-0.19,0.684-0.419l6.214-8.929C51.636,41.118,51.524,40.495,51.071,40.179z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,24 @@
<?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="47.222,14 33.222,0 2.222,0 2.222,58 47.222,58 "/>
<g>
<path style="fill:#D5D0BB;" d="M12.222,23h25c0.552,0,1-0.447,1-1s-0.448-1-1-1h-25c-0.552,0-1,0.447-1,1S11.669,23,12.222,23z"
/>
<path style="fill:#D5D0BB;" d="M12.222,15h10c0.552,0,1-0.447,1-1s-0.448-1-1-1h-10c-0.552,0-1,0.447-1,1S11.669,15,12.222,15z"
/>
<path style="fill:#D5D0BB;" d="M37.222,29h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S37.774,29,37.222,29z"/>
<path style="fill:#D5D0BB;" d="M37.222,37h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S37.774,37,37.222,37z"/>
<path style="fill:#D5D0BB;" d="M37.222,45h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S37.774,45,37.222,45z"/>
</g>
<polygon style="fill:#D5D0BB;" points="33.222,0 33.222,14 47.222,14 "/>
</g>
<g>
<path style="fill:#3D324C;" d="M55.485,55.293l-6.797-6.797l6.483-3.241l-17.637-6.498l6.499,17.637l3.241-6.484l6.797,6.797
C54.267,56.902,54.522,57,54.778,57s0.512-0.098,0.707-0.293C55.876,56.316,55.876,55.684,55.485,55.293z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,32 +1,29 @@
<?xml version="1.0" encoding="iso-8859-1"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg
<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" version="1.1"
viewBox="0 0 58.195 58.195" style="enable-background:new 0 0 58.195 58.195;" xml:space="preserve"> viewBox="0 0 28.39 18.476"
<g> xml:space="preserve"
<g> xmlns="http://www.w3.org/2000/svg"
<polygon style="fill:#EFEBDE;" points="45,14.097 31,0.097 0,0.097 0,58.097 45,58.097 "/> xmlns:svg="http://www.w3.org/2000/svg">
<g> <g
<path style="fill:#D5D0BB;" d="M10,23.097h25c0.552,0,1-0.447,1-1s-0.448-1-1-1H10c-0.552,0-1,0.447-1,1S9.448,23.097,10,23.097z id="g10"
"/> transform="translate(-29.806,-39.133)">
<path style="fill:#D5D0BB;" d="M10,15.097h10c0.552,0,1-0.447,1-1s-0.448-1-1-1H10c-0.552,0-1,0.447-1,1S9.448,15.097,10,15.097z <g
"/> id="g8">
<path style="fill:#D5D0BB;" d="M35,29.097H10c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S35.552,29.097,35,29.097z <path
"/> style="fill:#ffffff"
<path style="fill:#D5D0BB;" d="M35,37.097H10c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S35.552,37.097,35,37.097z d="m 57,48.289 -0.107,0.163 c -7.121,10.876 -18.773,10.876 -25.893,0 v 0 l 0.107,-0.163 c 7.12,-10.877 18.772,-10.877 25.893,0 z"
"/> id="path2" />
<path style="fill:#D5D0BB;" d="M35,45.097H10c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S35.552,45.097,35,45.097z <circle
"/> style="fill:#556080"
</g> cx="43.764"
<polygon style="fill:#D5D0BB;" points="31,0.097 31,14.097 45,14.097 "/> cy="46.007"
</g> r="5.9089999"
<g> id="circle4" />
<path style="fill:#FFFFFF;" d="M57,48.289l-0.107,0.163c-7.121,10.876-18.773,10.876-25.893,0l0,0l0.107-0.163 <path
C38.227,37.412,49.879,37.412,57,48.289L57,48.289z"/> style="fill:#8697cb"
<circle style="fill:#556080;" cx="43.764" cy="46.007" r="5.909"/> d="m 43.947,57.609 c -5.254,0 -10.148,-3.058 -13.783,-8.609 l -0.358,-0.547 0.465,-0.711 c 3.635,-5.552 8.53,-8.609 13.784,-8.609 5.253,0 10.148,3.057 13.783,8.609 l 0.358,0.547 -0.465,0.711 c -3.636,5.552 -8.531,8.609 -13.784,8.609 z m -11.744,-9.161 c 3.206,4.624 7.356,7.161 11.744,7.161 4.436,0 8.63,-2.594 11.85,-7.317 -3.206,-4.624 -7.356,-7.161 -11.743,-7.161 -4.437,10e-4 -8.631,2.594 -11.851,7.317 z"
<path style="fill:#8697CB;" d="M43.947,57.609c-5.254,0-10.148-3.058-13.783-8.609l-0.358-0.547l0.465-0.711 id="path6" />
c3.635-5.552,8.53-8.609,13.784-8.609c5.253,0,10.148,3.057,13.783,8.609l0.358,0.547l-0.465,0.711
C54.095,54.552,49.2,57.609,43.947,57.609z M32.203,48.448c3.206,4.624,7.356,7.161,11.744,7.161c4.436,0,8.63-2.594,11.85-7.317
c-3.206-4.624-7.356-7.161-11.743-7.161C39.617,41.132,35.423,43.725,32.203,48.448z"/>
</g> </g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -20,6 +20,7 @@
<ItemGroup> <ItemGroup>
<None Remove="Images\Busy.svg" /> <None Remove="Images\Busy.svg" />
<None Remove="Images\Delete.svg" />
<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" />
@ -29,6 +30,8 @@
<None Remove="Images\Ok.svg" /> <None Remove="Images\Ok.svg" />
<None Remove="Images\PublishSend.svg" /> <None Remove="Images\PublishSend.svg" />
<None Remove="Images\RabbitMQ.svg" /> <None Remove="Images\RabbitMQ.svg" />
<None Remove="Images\Save.svg" />
<None Remove="Images\SaveAs.svg" />
<None Remove="Images\Tapeti.png" /> <None Remove="Images\Tapeti.png" />
<None Remove="Images\Undock.svg" /> <None Remove="Images\Undock.svg" />
</ItemGroup> </ItemGroup>
@ -36,6 +39,7 @@
<ItemGroup> <ItemGroup>
<Resource Include="Images\Clear.svg" /> <Resource Include="Images\Clear.svg" />
<Resource Include="Images\Connect.svg" /> <Resource Include="Images\Connect.svg" />
<Resource Include="Images\Delete.svg" />
<Resource Include="Images\Disconnect.svg" /> <Resource Include="Images\Disconnect.svg" />
<Resource Include="Images\Dock.svg" /> <Resource Include="Images\Dock.svg" />
<Resource Include="Images\Error.svg" /> <Resource Include="Images\Error.svg" />
@ -47,6 +51,8 @@
<Resource Include="Images\Publish.svg" /> <Resource Include="Images\Publish.svg" />
<Resource Include="Images\PublishSend.svg" /> <Resource Include="Images\PublishSend.svg" />
<Resource Include="Images\RabbitMQ.svg" /> <Resource Include="Images\RabbitMQ.svg" />
<Resource Include="Images\Save.svg" />
<Resource Include="Images\SaveAs.svg" />
<Resource Include="Images\Subscribe.svg" /> <Resource Include="Images\Subscribe.svg" />
</ItemGroup> </ItemGroup>
@ -75,10 +81,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="UI\Connection\ConnectionDisplayNameStrings.Designer.cs"> <Compile Update="UI\InputDialogStrings.Designer.cs">
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>ConnectionDisplayNameStrings.resx</DependentUpon> <DependentUpon>InputDialogStrings.resx</DependentUpon>
</Compile> </Compile>
<Compile Update="UI\Connection\ConnectionWindowStrings.Designer.cs"> <Compile Update="UI\Connection\ConnectionWindowStrings.Designer.cs">
<DependentUpon>ConnectionWindowStrings.resx</DependentUpon> <DependentUpon>ConnectionWindowStrings.resx</DependentUpon>
@ -100,6 +106,11 @@
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>PayloadEditorStrings.resx</DependentUpon> <DependentUpon>PayloadEditorStrings.resx</DependentUpon>
</Compile> </Compile>
<Compile Update="UI\Tab\Publisher\StoredPublisherMessagesStrings.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>StoredPublisherMessagesStrings.resx</DependentUpon>
</Compile>
<Compile Update="UI\Tab\Publisher\TapetiPublisherViewStrings.Designer.cs"> <Compile Update="UI\Tab\Publisher\TapetiPublisherViewStrings.Designer.cs">
<DependentUpon>TapetiPublisherViewStrings.resx</DependentUpon> <DependentUpon>TapetiPublisherViewStrings.resx</DependentUpon>
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
@ -131,9 +142,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Update="UI\Connection\ConnectionDisplayNameStrings.resx"> <EmbeddedResource Update="UI\InputDialogStrings.resx">
<Generator>PublicResXFileCodeGenerator</Generator> <Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>ConnectionDisplayNameStrings.Designer.cs</LastGenOutput> <LastGenOutput>InputDialogStrings.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Update="UI\Connection\ConnectionWindowStrings.resx"> <EmbeddedResource Update="UI\Connection\ConnectionWindowStrings.resx">
<LastGenOutput>ConnectionWindowStrings.Designer.cs</LastGenOutput> <LastGenOutput>ConnectionWindowStrings.Designer.cs</LastGenOutput>
@ -151,6 +162,10 @@
<Generator>PublicResXFileCodeGenerator</Generator> <Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>PayloadEditorStrings.Designer.cs</LastGenOutput> <LastGenOutput>PayloadEditorStrings.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Update="UI\Tab\Publisher\StoredPublisherMessagesStrings.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>StoredPublisherMessagesStrings.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Update="UI\Tab\Publisher\TapetiPublisherViewStrings.resx"> <EmbeddedResource Update="UI\Tab\Publisher\TapetiPublisherViewStrings.resx">
<LastGenOutput>TapetiPublisherViewStrings.Designer.cs</LastGenOutput> <LastGenOutput>TapetiPublisherViewStrings.Designer.cs</LastGenOutput>
<Generator>PublicResXFileCodeGenerator</Generator> <Generator>PublicResXFileCodeGenerator</Generator>

View File

@ -4,7 +4,7 @@ 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.ExportImport; using PettingZoo.Core.ExportImport.Subscriber;
using PettingZoo.Core.Generator; using PettingZoo.Core.Generator;
using PettingZoo.Core.Macros; using PettingZoo.Core.Macros;
using PettingZoo.Core.Settings; using PettingZoo.Core.Settings;
@ -16,6 +16,7 @@ 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 PettingZoo.UI.Tab;
using PettingZoo.UI.Tab.Publisher;
using Serilog; using Serilog;
using SimpleInjector; using SimpleInjector;
@ -82,10 +83,12 @@ namespace PettingZoo
container.Register<ISubscribeDialog, WindowSubscribeDialog>(); container.Register<ISubscribeDialog, WindowSubscribeDialog>();
container.Register<IConnectionSettingsRepository, LiteDBConnectionSettingsRepository>(); container.Register<IConnectionSettingsRepository, LiteDBConnectionSettingsRepository>();
container.Register<IUISettingsRepository, LiteDBUISettingsRepository>(); container.Register<IUISettingsRepository, LiteDBUISettingsRepository>();
container.RegisterSingleton<IPublisherMessagesRepository, LiteDBPublisherMessagesRepository>();
container.Register<IExampleGenerator, TapetiClassLibraryExampleGenerator>(); container.Register<IExampleGenerator, TapetiClassLibraryExampleGenerator>();
container.RegisterSingleton<ITabHostProvider, TabHostProvider>(); container.RegisterSingleton<ITabHostProvider, TabHostProvider>();
container.Register<ITabFactory, ViewTabFactory>(); container.Register<ITabFactory, ViewTabFactory>();
container.RegisterSingleton<IPayloadMacroProcessor, PayloadMacroProcessor>(); container.RegisterSingleton<IPayloadMacroProcessor, PayloadMacroProcessor>();
container.RegisterSingleton<StoredPublisherMessagesViewModel>();
container.RegisterInstance<IExportImportFormatProvider>(new ExportImportFormatProvider( container.RegisterInstance<IExportImportFormatProvider>(new ExportImportFormatProvider(
new TapetiCmdExportFormat(), new TapetiCmdExportFormat(),

View File

@ -8,5 +8,4 @@ Should-have
Nice-to-have Nice-to-have
------------ ------------
- Save / load publisher messages (either as templates or to disk)
- 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

View File

@ -262,7 +262,7 @@ namespace PettingZoo.UI.Connection
// TODO create and enforce unique name? // TODO create and enforce unique name?
var displayName = SelectedStoredConnection != null && SelectedStoredConnection.Id != Guid.Empty ? SelectedStoredConnection.DisplayName : ""; var displayName = SelectedStoredConnection != null && SelectedStoredConnection.Id != Guid.Empty ? SelectedStoredConnection.DisplayName : "";
if (!ConnectionDisplayNameDialog.Execute(ref displayName)) if (!InputDialog.Execute(ref displayName, ConnectionWindowStrings.ProfileNameDialogTitle))
return; return;
var storedConnectionSettings = await connectionSettingsRepository.Add(displayName, StorePassword, ToModel()); var storedConnectionSettings = await connectionSettingsRepository.Add(displayName, StorePassword, ToModel());

View File

@ -213,6 +213,15 @@ namespace PettingZoo.UI.Connection {
} }
} }
/// <summary>
/// Looks up a localized string similar to Profile name.
/// </summary>
public static string ProfileNameDialogTitle {
get {
return ResourceManager.GetString("ProfileNameDialogTitle", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Connection parameters. /// Looks up a localized string similar to Connection parameters.
/// </summary> /// </summary>

View File

@ -112,10 +112,10 @@
<value>2.0</value> <value>2.0</value>
</resheader> </resheader>
<resheader name="reader"> <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>
<resheader name="writer"> <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> </resheader>
<data name="ButtonCancel" xml:space="preserve"> <data name="ButtonCancel" xml:space="preserve">
<value>Cancel</value> <value>Cancel</value>
@ -168,6 +168,9 @@
<data name="LastUsedDisplayName" xml:space="preserve"> <data name="LastUsedDisplayName" xml:space="preserve">
<value>&lt;New connection&gt;</value> <value>&lt;New connection&gt;</value>
</data> </data>
<data name="ProfileNameDialogTitle" xml:space="preserve">
<value>Profile name</value>
</data>
<data name="WindowTitle" xml:space="preserve"> <data name="WindowTitle" xml:space="preserve">
<value>Connection parameters</value> <value>Connection parameters</value>
</data> </data>

View File

@ -1,9 +1,9 @@
<Window x:Class="PettingZoo.UI.Connection.ConnectionDisplayNameDialog" <Window x:Class="PettingZoo.UI.InputDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PettingZoo.UI.Connection" xmlns:local="clr-namespace:PettingZoo.UI"
mc:Ignorable="d" mc:Ignorable="d"
Width="400" Width="400"
SizeToContent="Height" SizeToContent="Height"
@ -11,15 +11,15 @@
WindowStyle="ToolWindow" WindowStyle="ToolWindow"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
Style="{StaticResource WindowStyle}" Style="{StaticResource WindowStyle}"
Title="{x:Static local:ConnectionDisplayNameStrings.WindowTitle}" Title="{Binding Title}"
FocusManager.FocusedElement="{Binding ElementName=DisplayNameTextBox}" FocusManager.FocusedElement="{Binding ElementName=DisplayNameTextBox}"
d:DataContext="{d:DesignInstance local:ConnectionDisplayNameViewModel}"> d:DataContext="{d:DesignInstance local:InputDialogViewModel}">
<StackPanel Margin="8"> <StackPanel Margin="8">
<TextBox Name="DisplayNameTextBox" Text="{Binding DisplayName, UpdateSourceTrigger=PropertyChanged}" /> <TextBox Name="ValueTextBox" Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}" />
<UniformGrid HorizontalAlignment="Right" Rows="1" Columns="2" Style="{StaticResource FooterPanel}"> <UniformGrid HorizontalAlignment="Right" Rows="1" Columns="2" Style="{StaticResource FooterPanel}">
<Button IsDefault="True" Content="{x:Static local:ConnectionDisplayNameStrings.ButtonOK}" Style="{StaticResource FooterButton}" Command="{Binding OkCommand}"/> <Button IsDefault="True" Content="{x:Static local:InputDialogStrings.ButtonOK}" Style="{StaticResource FooterButton}" Command="{Binding OkCommand}"/>
<Button IsCancel="True" Content="{x:Static local:ConnectionDisplayNameStrings.ButtonCancel}" Style="{StaticResource FooterButton}"/> <Button IsCancel="True" Content="{x:Static local:InputDialogStrings.ButtonCancel}" Style="{StaticResource FooterButton}"/>
</UniformGrid> </UniformGrid>
</StackPanel> </StackPanel>
</Window> </Window>

View File

@ -1,18 +1,19 @@
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
namespace PettingZoo.UI.Connection namespace PettingZoo.UI
{ {
/// <summary> /// <summary>
/// Interaction logic for ConnectionDisplayNameDialog.xaml /// Interaction logic for InputDialog.xaml
/// </summary> /// </summary>
public partial class ConnectionDisplayNameDialog public partial class InputDialog
{ {
public static bool Execute(ref string displayName) public static bool Execute(ref string value, string title)
{ {
var viewModel = new ConnectionDisplayNameViewModel var viewModel = new InputDialogViewModel
{ {
DisplayName = displayName Value = value,
Title = title
}; };
@ -20,7 +21,7 @@ namespace PettingZoo.UI.Connection
.Cast<Window>() .Cast<Window>()
.FirstOrDefault(applicationWindow => applicationWindow.IsActive); .FirstOrDefault(applicationWindow => applicationWindow.IsActive);
var window = new ConnectionDisplayNameDialog(viewModel) var window = new InputDialog(viewModel)
{ {
Owner = activeWindow ?? Application.Current.MainWindow Owner = activeWindow ?? Application.Current.MainWindow
}; };
@ -28,12 +29,12 @@ namespace PettingZoo.UI.Connection
if (!window.ShowDialog().GetValueOrDefault()) if (!window.ShowDialog().GetValueOrDefault())
return false; return false;
displayName = viewModel.DisplayName; value = viewModel.Value;
return true; return true;
} }
public ConnectionDisplayNameDialog(ConnectionDisplayNameViewModel viewModel) public InputDialog(InputDialogViewModel viewModel)
{ {
viewModel.OkClick += (_, _) => viewModel.OkClick += (_, _) =>
{ {
@ -43,7 +44,7 @@ namespace PettingZoo.UI.Connection
DataContext = viewModel; DataContext = viewModel;
InitializeComponent(); InitializeComponent();
DisplayNameTextBox.CaretIndex = DisplayNameTextBox.Text.Length; ValueTextBox.CaretIndex = ValueTextBox.Text.Length;
} }
} }
} }

View File

@ -8,7 +8,7 @@
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace PettingZoo.UI.Connection { namespace PettingZoo.UI {
using System; using System;
@ -22,14 +22,14 @@ namespace PettingZoo.UI.Connection {
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class ConnectionDisplayNameStrings { public class InputDialogStrings {
private static global::System.Resources.ResourceManager resourceMan; private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture; private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal ConnectionDisplayNameStrings() { internal InputDialogStrings() {
} }
/// <summary> /// <summary>
@ -39,7 +39,7 @@ namespace PettingZoo.UI.Connection {
public static global::System.Resources.ResourceManager ResourceManager { public static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PettingZoo.UI.Connection.ConnectionDisplayNameStrings", typeof(ConnectionDisplayNameStrings).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PettingZoo.UI.InputDialogStrings", typeof(InputDialogStrings).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;
@ -77,14 +77,5 @@ namespace PettingZoo.UI.Connection {
return ResourceManager.GetString("ButtonOK", resourceCulture); return ResourceManager.GetString("ButtonOK", resourceCulture);
} }
} }
/// <summary>
/// Looks up a localized string similar to Profile name.
/// </summary>
public static string WindowTitle {
get {
return ResourceManager.GetString("WindowTitle", resourceCulture);
}
}
} }
} }

View File

@ -112,10 +112,10 @@
<value>2.0</value> <value>2.0</value>
</resheader> </resheader>
<resheader name="reader"> <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>
<resheader name="writer"> <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> </resheader>
<data name="ButtonCancel" xml:space="preserve"> <data name="ButtonCancel" xml:space="preserve">
<value>Cancel</value> <value>Cancel</value>
@ -123,7 +123,4 @@
<data name="ButtonOK" xml:space="preserve"> <data name="ButtonOK" xml:space="preserve">
<value>OK</value> <value>OK</value>
</data> </data>
<data name="WindowTitle" xml:space="preserve">
<value>Profile name</value>
</data>
</root> </root>

View File

@ -2,27 +2,36 @@
using System.Windows.Input; using System.Windows.Input;
using PettingZoo.WPF.ViewModel; using PettingZoo.WPF.ViewModel;
namespace PettingZoo.UI.Connection namespace PettingZoo.UI
{ {
public class ConnectionDisplayNameViewModel : BaseViewModel public class InputDialogViewModel : BaseViewModel
{ {
private string displayName = ""; private string title = "";
private string value = "";
private readonly DelegateCommand okCommand; private readonly DelegateCommand okCommand;
public string DisplayName public string Title
{ {
get => displayName; get => title;
set => SetField(ref displayName, value, delegateCommandsChanged: new [] { okCommand }); set => SetField(ref title, value);
} }
public string Value
{
get => value;
set => SetField(ref this.value, value, delegateCommandsChanged: new [] { okCommand });
}
public ICommand OkCommand => okCommand; public ICommand OkCommand => okCommand;
public event EventHandler? OkClick; public event EventHandler? OkClick;
public ConnectionDisplayNameViewModel() public InputDialogViewModel()
{ {
okCommand = new DelegateCommand(OkExecute, OkCanExecute); okCommand = new DelegateCommand(OkExecute, OkCanExecute);
} }
@ -36,7 +45,7 @@ namespace PettingZoo.UI.Connection
private bool OkCanExecute() private bool OkCanExecute()
{ {
return !string.IsNullOrWhiteSpace(DisplayName); return !string.IsNullOrWhiteSpace(Value);
} }
} }
} }

View File

@ -7,6 +7,7 @@
xmlns:tab="clr-namespace:PettingZoo.UI.Tab" xmlns:tab="clr-namespace:PettingZoo.UI.Tab"
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/" xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
xmlns:ui="clr-namespace:PettingZoo.UI" xmlns:ui="clr-namespace:PettingZoo.UI"
xmlns:controls="clr-namespace:PettingZoo.WPF.Controls;assembly=PettingZoo.WPF"
mc:Ignorable="d" mc:Ignorable="d"
d:DataContext="{d:DesignInstance main:DesignTimeMainWindowViewModel, IsDesignTimeCreatable=True}" d:DataContext="{d:DesignInstance main:DesignTimeMainWindowViewModel, IsDesignTimeCreatable=True}"
Width="800" Width="800"
@ -24,7 +25,7 @@
<ui:BindingProxy x:Key="ContextMenuProxy" Data="{Binding}" /> <ui:BindingProxy x:Key="ContextMenuProxy" Data="{Binding}" />
</Window.Resources> </Window.Resources>
<DockPanel> <DockPanel>
<ToolBar DockPanel.Dock="Top" ToolBarTray.IsLocked="True" Loaded="Toolbar_Loaded"> <controls:NoOverflowToolbar DockPanel.Dock="Top" ToolBarTray.IsLocked="True">
<Button Command="{Binding ConnectCommand}"> <Button Command="{Binding ConnectCommand}">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<Image Source="{svgc:SvgImage Source=/Images/Connect.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/> <Image Source="{svgc:SvgImage Source=/Images/Connect.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
@ -82,7 +83,7 @@
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
</ItemsControl> </ItemsControl>
</ToolBar> </controls:NoOverflowToolbar>
<StatusBar DockPanel.Dock="Bottom"> <StatusBar DockPanel.Dock="Bottom">
<StatusBarItem> <StatusBarItem>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">

View File

@ -5,7 +5,7 @@ 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.ExportImport; using PettingZoo.Core.ExportImport.Subscriber;
using PettingZoo.UI.Connection; using PettingZoo.UI.Connection;
using PettingZoo.UI.Subscribe; using PettingZoo.UI.Subscribe;
using PettingZoo.UI.Tab; using PettingZoo.UI.Tab;
@ -139,18 +139,6 @@ namespace PettingZoo.UI.Main
public double TabWidth => SubscriberTabs.ActualWidth; public double TabWidth => SubscriberTabs.ActualWidth;
public double TabHeight => SubscriberTabs.ActualHeight; public double TabHeight => SubscriberTabs.ActualHeight;
private void Toolbar_Loaded(object sender, RoutedEventArgs e)
{
// Hide arrow on the right side of the toolbar
var toolBar = sender as ToolBar;
if (toolBar?.Template.FindName("OverflowGrid", toolBar) is FrameworkElement overflowGrid)
overflowGrid.Visibility = Visibility.Collapsed;
if (toolBar?.Template.FindName("MainPanelBorder", toolBar) is FrameworkElement mainPanelBorder)
mainPanelBorder.Margin = new Thickness(0);
}
} }
#pragma warning restore CA1001 #pragma warning restore CA1001
} }

View File

@ -9,7 +9,7 @@ using System.Windows;
using System.Windows.Forms; using System.Windows.Forms;
using System.Windows.Input; using System.Windows.Input;
using PettingZoo.Core.Connection; using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport; using PettingZoo.Core.ExportImport.Subscriber;
using PettingZoo.UI.Connection; using PettingZoo.UI.Connection;
using PettingZoo.UI.Subscribe; using PettingZoo.UI.Subscribe;
using PettingZoo.UI.Tab; using PettingZoo.UI.Tab;

View File

@ -6,73 +6,153 @@
xmlns:res="clr-namespace:PettingZoo.UI.Tab.Publisher" xmlns:res="clr-namespace:PettingZoo.UI.Tab.Publisher"
xmlns:controls="clr-namespace:PettingZoo.WPF.Controls;assembly=PettingZoo.WPF" xmlns:controls="clr-namespace:PettingZoo.WPF.Controls;assembly=PettingZoo.WPF"
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/" xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
xmlns:valueConverters="clr-namespace:PettingZoo.WPF.ValueConverters;assembly=PettingZoo.WPF"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
d:DataContext="{d:DesignInstance res:DesignTimePublisherViewModel, IsDesignTimeCreatable=True}" d:DataContext="{d:DesignInstance res:DesignTimePublisherViewModel, IsDesignTimeCreatable=True}"
Background="White"> Background="White">
<ScrollViewer VerticalScrollBarVisibility="Auto"> <Grid>
<controls:GridLayout Style="{StaticResource Form}" Margin="4" Grid.IsSharedSizeScope="True"> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Column="0" 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"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="16"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="16" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Label" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<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="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="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="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="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="8" Grid.Column="1" Text="{Binding ReplyTo}" IsEnabled="{Binding ReplyToSpecified}" />
<ContentControl Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="2" Margin="0 8 0 0" Content="{Binding MessageTypeControl}" />
<Button Grid.Row="11" Grid.Column="1" Command="{Binding PublishCommand}" Content="{x:Static res:PublisherViewStrings.CommandPublish}" HorizontalAlignment="Left" />
</controls:GridLayout>
</ScrollViewer>
<GridSplitter Width="5" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch"/>
<Grid Grid.Column="2" Grid.Row="0">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="8"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="16"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="16" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Label" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="1"> <Label Grid.Row="0" Style="{StaticResource HeaderLabel}" Content="{x:Static res:PublisherViewStrings.PanelTitleMessages}"/>
<ToggleButton Style="{StaticResource TypeSelection}" IsChecked="{Binding MessageTypeRaw}">
<controls:NoOverflowToolbar Grid.Row="1" ToolBarTray.IsLocked="True" Margin="0,0,0,4">
<!-- TODO load button in addition to double-click. I don't like hidden-only functionality -->
<Button Command="{Binding SaveCommand}">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<Image Source="{svgc:SvgImage Source=/Images/RabbitMQ.svg, AppName=PettingZoo}" Style="{StaticResource ButtonIcon}" /> <Image Source="{svgc:SvgImage Source=/Images/Save.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
<TextBlock Text="{x:Static res:PublisherViewStrings.OptionMessageTypeRaw}" /> <TextBlock Margin="3,0,0,0" Text="{x:Static res:PublisherViewStrings.ToolbarSave}" />
</StackPanel> </StackPanel>
</ToggleButton> </Button>
<ToggleButton Style="{StaticResource TypeSelection}" IsChecked="{Binding MessageTypeTapeti}"> <Button Command="{Binding SaveAsCommand}">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<Image Source="/Images/Tapeti.png" Style="{StaticResource ButtonIcon}" /> <Image Source="{svgc:SvgImage Source=/Images/SaveAs.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
<TextBlock Text="{x:Static res:PublisherViewStrings.OptionMessageTypeTapeti}" /> <TextBlock Margin="3,0,0,0" Text="{x:Static res:PublisherViewStrings.ToolbarSaveAs}" />
</StackPanel> </StackPanel>
</ToggleButton> </Button>
</StackPanel> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Button Command="{Binding DeleteCommand}">
<StackPanel Orientation="Horizontal">
<Image Source="{svgc:SvgImage Source=/Images/Delete.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
<TextBlock Margin="3,0,0,0" Text="{x:Static res:PublisherViewStrings.ToolbarDelete}" />
</StackPanel>
</Button>
<!-- TODO export / import -->
</controls:NoOverflowToolbar>
<Label Grid.Row="2" Grid.Column="1"> <ListBox Grid.Row="2" ItemsSource="{Binding StoredMessages}" SelectedValue="{Binding SelectedStoredMessage}">
<StackPanel Orientation="Horizontal"> <ListBox.Resources>
<RadioButton Content="{x:Static res:PublisherViewStrings.LabelSendToExchange}" IsChecked="{Binding SendToExchange}" Style="{StaticResource TypeSelection}" /> <valueConverters:SameReferenceConverter x:Key="SameReferenceConverter" />
<RadioButton Content="{x:Static res:PublisherViewStrings.LabelSendToQueue}" IsChecked="{Binding SendToQueue}" Style="{StaticResource TypeSelection}" /> </ListBox.Resources>
</StackPanel> <ListBox.ItemContainerStyle>
</Label> <Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Label Grid.Row="3" Grid.Column="0" Content="{x:Static res:PublisherViewStrings.LabelExchange}" Visibility="{Binding ExchangeVisibility}" /> </Style>
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Exchange, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding ExchangeVisibility}" /> </ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<Label Grid.Row="4" Grid.Column="0" Content="{x:Static res:PublisherViewStrings.LabelRoutingKey}" Visibility="{Binding ExchangeVisibility}" /> <DataTemplate>
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding RoutingKey, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding ExchangeVisibility}" /> <TextBlock Text="{Binding DisplayName}">
<TextBlock.Style>
<Label Grid.Row="5" Grid.Column="0" Content="{x:Static res:PublisherViewStrings.LabelQueue}" Visibility="{Binding QueueVisibility}" /> <Style TargetType="{x:Type TextBlock}">
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding Queue, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding QueueVisibility}" /> <Style.Triggers>
<DataTrigger Value="True">
<Label Grid.Row="7" Grid.Column="0" Content="{x:Static res:PublisherViewStrings.LabelReplyTo}" /> <DataTrigger.Binding>
<StackPanel Orientation="Horizontal" Grid.Row="7" Grid.Column="1"> <MultiBinding Converter="{StaticResource SameReferenceConverter}">
<RadioButton Content="{x:Static res:PublisherViewStrings.LabelReplyToSpecified}" IsChecked="{Binding ReplyToSpecified}" Style="{StaticResource TypeSelection}" /> <Binding RelativeSource="{RelativeSource AncestorType={x:Type ListBoxItem}}" Path="DataContext" />
<RadioButton Content="{x:Static res:PublisherViewStrings.LabelReplyToNewSubscriber}" IsChecked="{Binding ReplyToNewSubscriber}" Style="{StaticResource TypeSelection}" /> <Binding RelativeSource="{RelativeSource AncestorType={x:Type ListBox}}" Path="DataContext.ActiveStoredMessage" />
</StackPanel> </MultiBinding>
<TextBox Grid.Row="8" Grid.Column="1" Text="{Binding ReplyTo}" IsEnabled="{Binding ReplyToSpecified}" /> </DataTrigger.Binding>
<Setter Property="FontWeight" Value="Bold" />
<ContentControl Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="2" Margin="0 8 0 0" Content="{Binding MessageTypeControl}" /> </DataTrigger>
</Style.Triggers>
<Button Grid.Row="11" Grid.Column="1" Command="{Binding PublishCommand}" Content="{x:Static res:PublisherViewStrings.CommandPublish}" HorizontalAlignment="Left" /> </Style>
</controls:GridLayout> </TextBlock.Style>
</ScrollViewer> <TextBlock.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding DataContext.LoadStoredMessage, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" />
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
</UserControl> </UserControl>

View File

@ -1,27 +1,25 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using PettingZoo.Core.Connection; using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport.Publisher;
using PettingZoo.Core.Generator; using PettingZoo.Core.Generator;
using PettingZoo.Core.Macros; using PettingZoo.Core.Macros;
using PettingZoo.Core.Settings;
using PettingZoo.WPF.ViewModel; using PettingZoo.WPF.ViewModel;
namespace PettingZoo.UI.Tab.Publisher namespace PettingZoo.UI.Tab.Publisher
{ {
public enum MessageType
{
Raw,
Tapeti
}
public class PublisherViewModel : BaseViewModel, ITabToolbarCommands, ITabHostWindowNotify, IPublishDestination public class PublisherViewModel : BaseViewModel, ITabToolbarCommands, ITabHostWindowNotify, IPublishDestination
{ {
private readonly IConnection connection; private readonly IConnection connection;
private readonly IExampleGenerator exampleGenerator; private readonly IExampleGenerator exampleGenerator;
private readonly IPayloadMacroProcessor payloadMacroProcessor; private readonly IPayloadMacroProcessor payloadMacroProcessor;
private readonly StoredPublisherMessagesViewModel storedPublisherMessagesViewModel;
private readonly ITabFactory tabFactory; private readonly ITabFactory tabFactory;
private bool sendToExchange = true; private bool sendToExchange = true;
@ -29,16 +27,27 @@ namespace PettingZoo.UI.Tab.Publisher
private string routingKey = ""; private string routingKey = "";
private string queue = ""; private string queue = "";
private string replyTo = ""; private string replyTo = "";
private bool replyToSpecified = true; private bool replyToNewSubscriber;
private MessageType messageType; private StoredPublisherMessage? selectedStoredMessage;
private StoredPublisherMessage? activeStoredMessage;
private PublisherMessageType messageType;
private UserControl? messageTypeControl; private UserControl? messageTypeControl;
private ICommand? messageTypePublishCommand; private ICommand? messageTypePublishCommand;
private RawPublisherViewModel? rawPublisherViewModel;
private UserControl? rawPublisherView; private UserControl? rawPublisherView;
private TapetiPublisherViewModel? tapetiPublisherViewModel;
private UserControl? tapetiPublisherView; private UserControl? tapetiPublisherView;
private readonly DelegateCommand publishCommand; private readonly DelegateCommand publishCommand;
private readonly DelegateCommand saveCommand;
private readonly DelegateCommand saveAsCommand;
private readonly DelegateCommand deleteCommand;
private readonly DelegateCommand loadStoredMessage;
private readonly TabToolbarCommand[] toolbarCommands; private readonly TabToolbarCommand[] toolbarCommands;
private Window? tabHostWindow; private Window? tabHostWindow;
@ -46,9 +55,10 @@ namespace PettingZoo.UI.Tab.Publisher
public bool SendToExchange public bool SendToExchange
{ {
get => sendToExchange; get => sendToExchange;
set => SetField(ref sendToExchange, value, set => SetField(ref sendToExchange, value,
delegateCommandsChanged: new [] { publishCommand }, delegateCommandsChanged: new[] { publishCommand },
otherPropertiesChanged: new[] { nameof(SendToQueue), nameof(ExchangeVisibility), nameof(QueueVisibility), nameof(Title) }); otherPropertiesChanged: new[]
{ nameof(SendToQueue), nameof(ExchangeVisibility), nameof(QueueVisibility), nameof(Title) });
} }
@ -69,14 +79,16 @@ namespace PettingZoo.UI.Tab.Publisher
public string RoutingKey public string RoutingKey
{ {
get => routingKey; get => routingKey;
set => SetField(ref routingKey, value, delegateCommandsChanged: new[] { publishCommand }, otherPropertiesChanged: new[] { nameof(Title) }); set => SetField(ref routingKey, value, delegateCommandsChanged: new[] { publishCommand },
otherPropertiesChanged: new[] { nameof(Title) });
} }
public string Queue public string Queue
{ {
get => queue; get => queue;
set => SetField(ref queue, value, delegateCommandsChanged: new[] { publishCommand }, otherPropertiesChanged: new[] { nameof(Title) }); set => SetField(ref queue, value, delegateCommandsChanged: new[] { publishCommand },
otherPropertiesChanged: new[] { nameof(Title) });
} }
@ -89,15 +101,16 @@ namespace PettingZoo.UI.Tab.Publisher
public bool ReplyToSpecified public bool ReplyToSpecified
{ {
get => replyToSpecified; get => !ReplyToNewSubscriber;
set => SetField(ref replyToSpecified, value, otherPropertiesChanged: new[] { nameof(ReplyToNewSubscriber) }); set => ReplyToNewSubscriber = !value;
} }
public bool ReplyToNewSubscriber public bool ReplyToNewSubscriber
{ {
get => !ReplyToSpecified; get => replyToNewSubscriber;
set => ReplyToSpecified = !value; set => SetField(ref replyToNewSubscriber, value,
otherPropertiesChanged: new[] { nameof(ReplyToSpecified) });
} }
@ -105,17 +118,17 @@ namespace PettingZoo.UI.Tab.Publisher
public virtual Visibility QueueVisibility => SendToQueue ? Visibility.Visible : Visibility.Collapsed; public virtual Visibility QueueVisibility => SendToQueue ? Visibility.Visible : Visibility.Collapsed;
public MessageType MessageType public PublisherMessageType MessageType
{ {
get => messageType; get => messageType;
set set
{ {
if (SetField(ref messageType, value, if (SetField(ref messageType, value,
otherPropertiesChanged: new[] otherPropertiesChanged: new[]
{ {
nameof(MessageTypeRaw), nameof(MessageTypeRaw),
nameof(MessageTypeTapeti) nameof(MessageTypeTapeti)
})) }))
{ {
SetMessageTypeControl(value); SetMessageTypeControl(value);
} }
@ -124,14 +137,20 @@ namespace PettingZoo.UI.Tab.Publisher
public bool MessageTypeRaw public bool MessageTypeRaw
{ {
get => MessageType == MessageType.Raw; get => MessageType == PublisherMessageType.Raw;
set { if (value) MessageType = MessageType.Raw; } set
{
if (value) MessageType = PublisherMessageType.Raw;
}
} }
public bool MessageTypeTapeti public bool MessageTypeTapeti
{ {
get => MessageType == MessageType.Tapeti; get => MessageType == PublisherMessageType.Tapeti;
set { if (value) MessageType = MessageType.Tapeti; } set
{
if (value) MessageType = PublisherMessageType.Tapeti;
}
} }
@ -142,12 +161,38 @@ namespace PettingZoo.UI.Tab.Publisher
} }
public ObservableCollectionEx<StoredPublisherMessage> StoredMessages =>
storedPublisherMessagesViewModel.StoredMessages;
public StoredPublisherMessage? SelectedStoredMessage
{
get => selectedStoredMessage;
set => SetField(ref selectedStoredMessage, value, delegateCommandsChanged: new[] { deleteCommand });
}
// TODO detect changes from ActiveStoredMessage and show indication in the UI
public StoredPublisherMessage? ActiveStoredMessage
{
get => activeStoredMessage;
set => SetField(ref activeStoredMessage, value);
}
public ICommand PublishCommand => publishCommand; public ICommand PublishCommand => publishCommand;
public ICommand SaveCommand => saveCommand;
public ICommand SaveAsCommand => saveAsCommand;
public ICommand DeleteCommand => deleteCommand;
public ICommand LoadStoredMessage => loadStoredMessage;
public string Title => SendToQueue public string Title => SendToQueue
? string.IsNullOrWhiteSpace(Queue) ? PublisherViewStrings.TabTitleEmpty : string.Format(PublisherViewStrings.TabTitle, Queue) ? string.IsNullOrWhiteSpace(Queue) ? PublisherViewStrings.TabTitleEmpty :
: string.IsNullOrWhiteSpace(RoutingKey) ? PublisherViewStrings.TabTitleEmpty : string.Format(PublisherViewStrings.TabTitle, RoutingKey); string.Format(PublisherViewStrings.TabTitle, Queue)
: string.IsNullOrWhiteSpace(RoutingKey)
? PublisherViewStrings.TabTitleEmpty
: string.Format(PublisherViewStrings.TabTitle, RoutingKey);
public IEnumerable<TabToolbarCommand> ToolbarCommands => toolbarCommands; public IEnumerable<TabToolbarCommand> ToolbarCommands => toolbarCommands;
@ -157,24 +202,33 @@ namespace PettingZoo.UI.Tab.Publisher
string IPublishDestination.RoutingKey => SendToExchange ? RoutingKey : Queue; string IPublishDestination.RoutingKey => SendToExchange ? RoutingKey : Queue;
public PublisherViewModel(ITabFactory tabFactory, IConnection connection, IExampleGenerator exampleGenerator, IPayloadMacroProcessor payloadMacroProcessor, ReceivedMessageInfo? fromReceivedMessage = null) public PublisherViewModel(ITabFactory tabFactory, IConnection connection, IExampleGenerator exampleGenerator,
IPayloadMacroProcessor payloadMacroProcessor,
StoredPublisherMessagesViewModel storedPublisherMessagesViewModel,
ReceivedMessageInfo? fromReceivedMessage = null)
{ {
this.connection = connection; this.connection = connection;
this.exampleGenerator = exampleGenerator; this.exampleGenerator = exampleGenerator;
this.payloadMacroProcessor = payloadMacroProcessor; this.payloadMacroProcessor = payloadMacroProcessor;
this.storedPublisherMessagesViewModel = storedPublisherMessagesViewModel;
this.tabFactory = tabFactory; this.tabFactory = tabFactory;
publishCommand = new DelegateCommand(PublishExecute, PublishCanExecute); publishCommand = new DelegateCommand(PublishExecute, PublishCanExecute);
saveCommand = new DelegateCommand(SaveExecute);
saveAsCommand = new DelegateCommand(SaveAsExecute);
deleteCommand = new DelegateCommand(DeleteExecute, DeleteCanExecute);
loadStoredMessage = new DelegateCommand(LoadStoredMessageExecute, LoadStoredMessageCanExecute);
toolbarCommands = new[] toolbarCommands = new[]
{ {
new TabToolbarCommand(PublishCommand, PublisherViewStrings.CommandPublish, SvgIconHelper.LoadFromResource("/Images/PublishSend.svg")) new TabToolbarCommand(PublishCommand, PublisherViewStrings.CommandPublish,
SvgIconHelper.LoadFromResource("/Images/PublishSend.svg"))
}; };
if (fromReceivedMessage != null) if (fromReceivedMessage != null)
SetMessageTypeControl(fromReceivedMessage); SetMessageTypeControl(fromReceivedMessage);
else else
SetMessageTypeControl(MessageType.Raw); SetMessageTypeControl(PublisherMessageType.Raw);
} }
@ -201,13 +255,11 @@ namespace PettingZoo.UI.Tab.Publisher
} }
private void SetMessageTypeControl(MessageType value) private void SetMessageTypeControl(PublisherMessageType value)
{ {
switch (value) switch (value)
{ {
case MessageType.Raw: case PublisherMessageType.Raw:
RawPublisherViewModel rawPublisherViewModel;
if (rawPublisherView == null) if (rawPublisherView == null)
{ {
rawPublisherViewModel = new RawPublisherViewModel(connection, this, payloadMacroProcessor); rawPublisherViewModel = new RawPublisherViewModel(connection, this, payloadMacroProcessor);
@ -216,19 +268,17 @@ namespace PettingZoo.UI.Tab.Publisher
publishCommand.RaiseCanExecuteChanged(); publishCommand.RaiseCanExecuteChanged();
}; };
rawPublisherView ??= new RawPublisherView(rawPublisherViewModel); rawPublisherView = new RawPublisherView(rawPublisherViewModel);
} }
else else
rawPublisherViewModel = (RawPublisherViewModel)rawPublisherView.DataContext; Debug.Assert(rawPublisherViewModel != null);
MessageTypeControl = rawPublisherView; MessageTypeControl = rawPublisherView;
messageTypePublishCommand = rawPublisherViewModel.PublishCommand; messageTypePublishCommand = rawPublisherViewModel.PublishCommand;
break; break;
case MessageType.Tapeti:
TapetiPublisherViewModel tapetiPublisherViewModel;
case PublisherMessageType.Tapeti:
if (tapetiPublisherView == null) if (tapetiPublisherView == null)
{ {
tapetiPublisherViewModel = new TapetiPublisherViewModel(connection, this, exampleGenerator, payloadMacroProcessor); tapetiPublisherViewModel = new TapetiPublisherViewModel(connection, this, exampleGenerator, payloadMacroProcessor);
@ -237,19 +287,19 @@ namespace PettingZoo.UI.Tab.Publisher
publishCommand.RaiseCanExecuteChanged(); publishCommand.RaiseCanExecuteChanged();
}; };
tapetiPublisherView ??= new TapetiPublisherView(tapetiPublisherViewModel); tapetiPublisherView = new TapetiPublisherView(tapetiPublisherViewModel);
if (tabHostWindow != null) if (tabHostWindow != null)
tapetiPublisherViewModel.HostWindowChanged(tabHostWindow); tapetiPublisherViewModel.HostWindowChanged(tabHostWindow);
} }
else else
tapetiPublisherViewModel = (TapetiPublisherViewModel)tapetiPublisherView.DataContext; Debug.Assert(tapetiPublisherViewModel != null);
MessageTypeControl = tapetiPublisherView; MessageTypeControl = tapetiPublisherView;
messageTypePublishCommand = tapetiPublisherViewModel.PublishCommand; messageTypePublishCommand = tapetiPublisherViewModel.PublishCommand;
break; break;
default: default:
throw new ArgumentException($@"Unknown message type: {value}", nameof(value)); throw new ArgumentException($@"Unknown message type: {value}", nameof(value));
} }
@ -266,17 +316,17 @@ namespace PettingZoo.UI.Tab.Publisher
if (TapetiPublisherViewModel.IsTapetiMessage(fromReceivedMessage)) if (TapetiPublisherViewModel.IsTapetiMessage(fromReceivedMessage))
{ {
var tapetiPublisherViewModel = new TapetiPublisherViewModel(connection, this, exampleGenerator, payloadMacroProcessor, fromReceivedMessage); tapetiPublisherViewModel = new TapetiPublisherViewModel(connection, this, exampleGenerator, payloadMacroProcessor, fromReceivedMessage);
tapetiPublisherView = new TapetiPublisherView(tapetiPublisherViewModel); tapetiPublisherView = new TapetiPublisherView(tapetiPublisherViewModel);
MessageType = MessageType.Tapeti; MessageType = PublisherMessageType.Tapeti;
} }
else else
{ {
var rawPublisherViewModel = new RawPublisherViewModel(connection, this, payloadMacroProcessor, fromReceivedMessage); rawPublisherViewModel = new RawPublisherViewModel(connection, this, payloadMacroProcessor, fromReceivedMessage);
rawPublisherView = new RawPublisherView(rawPublisherViewModel); rawPublisherView = new RawPublisherView(rawPublisherViewModel);
MessageType = MessageType.Raw; MessageType = PublisherMessageType.Raw;
} }
} }
@ -304,16 +354,160 @@ namespace PettingZoo.UI.Tab.Publisher
(tapetiPublisherView?.DataContext as TapetiPublisherViewModel)?.HostWindowChanged(hostWindow); (tapetiPublisherView?.DataContext as TapetiPublisherViewModel)?.HostWindowChanged(hostWindow);
} }
private void SaveExecute()
{
storedPublisherMessagesViewModel.Save(SelectedStoredMessage, GetPublisherMessage(), message =>
{
ActiveStoredMessage = message;
SelectedStoredMessage = message;
});
}
private void SaveAsExecute()
{
storedPublisherMessagesViewModel.SaveAs(GetPublisherMessage(), SelectedStoredMessage?.DisplayName, message =>
{
ActiveStoredMessage = message;
SelectedStoredMessage = message;
});
}
private void DeleteExecute()
{
if (SelectedStoredMessage == null)
return;
var message = SelectedStoredMessage;
storedPublisherMessagesViewModel.Delete(message, () =>
{
if (SelectedStoredMessage == message)
SelectedStoredMessage = null;
if (ActiveStoredMessage == message)
ActiveStoredMessage = null;
});
}
private bool DeleteCanExecute()
{
return SelectedStoredMessage != null;
}
private void LoadStoredMessageExecute()
{
if (SelectedStoredMessage == null)
return;
var message = SelectedStoredMessage.Message;
MessageType = message.MessageType;
SendToExchange = message.SendToExchange;
Exchange = message.Exchange ?? "";
RoutingKey = message.RoutingKey ?? "";
Queue = message.Queue ?? "";
ReplyToNewSubscriber = message.ReplyToNewSubscriber;
ReplyTo = message.ReplyTo ?? "";
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
switch (message.MessageType)
{
case PublisherMessageType.Raw:
if (message.RawPublisherMessage != null)
rawPublisherViewModel?.LoadPublisherMessage(message.RawPublisherMessage);
break;
case PublisherMessageType.Tapeti:
if (message.TapetiPublisherMessage != null)
tapetiPublisherViewModel?.LoadPublisherMessage(message.TapetiPublisherMessage);
break;
}
ActiveStoredMessage = SelectedStoredMessage;
}
private bool LoadStoredMessageCanExecute()
{
return SelectedStoredMessage != null;
}
private PublisherMessage GetPublisherMessage()
{
return new PublisherMessage
{
MessageType = MessageType,
SendToExchange = SendToExchange,
Exchange = Exchange,
RoutingKey = RoutingKey,
Queue = Queue,
ReplyToNewSubscriber = ReplyToNewSubscriber,
ReplyTo = ReplyTo,
RawPublisherMessage = MessageType == PublisherMessageType.Raw
? rawPublisherViewModel?.GetPublisherMessage()
: null,
TapetiPublisherMessage = MessageType == PublisherMessageType.Tapeti
? tapetiPublisherViewModel?.GetPublisherMessage()
: null
};
}
} }
public class DesignTimePublisherViewModel : PublisherViewModel public class DesignTimePublisherViewModel : PublisherViewModel
{ {
public DesignTimePublisherViewModel() : base(null!, null!, null!, null!) public DesignTimePublisherViewModel() : base(null!, null!, null!, null!, new StoredPublisherMessagesViewModel(new DesignTimePublisherMessagesRepository()))
{ {
StoredMessages.CollectionChanged += (_, _) =>
{
if (StoredMessages.Count < 2)
return;
SelectedStoredMessage = StoredMessages[0];
ActiveStoredMessage = StoredMessages[1];
};
} }
public override Visibility ExchangeVisibility => Visibility.Visible; public override Visibility ExchangeVisibility => Visibility.Visible;
public override Visibility QueueVisibility => Visibility.Visible; public override Visibility QueueVisibility => Visibility.Visible;
private class DesignTimePublisherMessagesRepository : IPublisherMessagesRepository
{
public Task<IEnumerable<StoredPublisherMessage>> GetStored()
{
return Task.FromResult(new StoredPublisherMessage[]
{
new(new Guid("16fdf930-2e4c-48f4-ae21-68dac9ca62e6"), "Design-time message 1", new PublisherMessage()),
new(new Guid("01d2671b-4426-4c1c-bcbc-61689d14796e"), "Design-time message 2", new PublisherMessage())
} as IEnumerable<StoredPublisherMessage>);
}
public Task<StoredPublisherMessage> Add(string displayName, PublisherMessage message)
{
throw new NotSupportedException();
}
public Task<StoredPublisherMessage> Update(Guid id, string displayName, PublisherMessage message)
{
throw new NotSupportedException();
}
public Task Delete(Guid id)
{
throw new NotSupportedException();
}
}
} }
} }

View File

@ -168,6 +168,15 @@ namespace PettingZoo.UI.Tab.Publisher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Saved messages.
/// </summary>
public static string PanelTitleMessages {
get {
return ResourceManager.GetString("PanelTitleMessages", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Re: . /// Looks up a localized string similar to Re: .
/// </summary> /// </summary>
@ -194,5 +203,32 @@ namespace PettingZoo.UI.Tab.Publisher {
return ResourceManager.GetString("TabTitleEmpty", resourceCulture); return ResourceManager.GetString("TabTitleEmpty", resourceCulture);
} }
} }
/// <summary>
/// Looks up a localized string similar to Delete.
/// </summary>
public static string ToolbarDelete {
get {
return ResourceManager.GetString("ToolbarDelete", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Save.
/// </summary>
public static string ToolbarSave {
get {
return ResourceManager.GetString("ToolbarSave", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Save as....
/// </summary>
public static string ToolbarSaveAs {
get {
return ResourceManager.GetString("ToolbarSaveAs", resourceCulture);
}
}
} }
} }

View File

@ -153,6 +153,9 @@
<data name="OptionMessageTypeTapeti" xml:space="preserve"> <data name="OptionMessageTypeTapeti" xml:space="preserve">
<value>Tapeti message</value> <value>Tapeti message</value>
</data> </data>
<data name="PanelTitleMessages" xml:space="preserve">
<value>Saved messages</value>
</data>
<data name="ReplyToCorrelationIdPrefix" xml:space="preserve"> <data name="ReplyToCorrelationIdPrefix" xml:space="preserve">
<value>Re: </value> <value>Re: </value>
</data> </data>
@ -162,4 +165,13 @@
<data name="TabTitleEmpty" xml:space="preserve"> <data name="TabTitleEmpty" xml:space="preserve">
<value>Publish</value> <value>Publish</value>
</data> </data>
<data name="ToolbarDelete" xml:space="preserve">
<value>Delete</value>
</data>
<data name="ToolbarSave" xml:space="preserve">
<value>Save</value>
</data>
<data name="ToolbarSaveAs" xml:space="preserve">
<value>Save as...</value>
</data>
</root> </root>

View File

@ -3,7 +3,6 @@ using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Threading; using System.Windows.Threading;
using PettingZoo.Core.Macros;
namespace PettingZoo.UI.Tab.Publisher namespace PettingZoo.UI.Tab.Publisher
{ {

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
@ -7,6 +6,7 @@ using System.Text;
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.ExportImport.Publisher;
using PettingZoo.Core.Macros; using PettingZoo.Core.Macros;
using PettingZoo.WPF.ViewModel; using PettingZoo.WPF.ViewModel;
@ -37,10 +37,17 @@ namespace PettingZoo.UI.Tab.Publisher
public MessageDeliveryMode DeliveryMode
{
get => deliveryMode;
set => SetField(ref deliveryMode, value, otherPropertiesChanged: new[] { nameof(DeliveryModeIndex) });
}
public int DeliveryModeIndex public int DeliveryModeIndex
{ {
get => deliveryMode == MessageDeliveryMode.Persistent ? 1 : 0; get => DeliveryMode == MessageDeliveryMode.Persistent ? 1 : 0;
set => SetField(ref deliveryMode, value == 1 ? MessageDeliveryMode.Persistent : MessageDeliveryMode.NonPersistent); set => DeliveryMode = value == 1 ? MessageDeliveryMode.Persistent : MessageDeliveryMode.NonPersistent;
} }
@ -127,7 +134,7 @@ namespace PettingZoo.UI.Tab.Publisher
} }
public ObservableCollection<Header> Headers { get; } = new(); public ObservableCollectionEx<Header> Headers { get; } = new();
public ICommand PublishCommand => publishCommand; public ICommand PublishCommand => publishCommand;
@ -194,6 +201,56 @@ namespace PettingZoo.UI.Tab.Publisher
} }
public RawPublisherMessage GetPublisherMessage()
{
return new RawPublisherMessage
{
DeliveryMode = DeliveryMode,
ContentType = ContentType,
CorrelationId = CorrelationId,
AppId = AppId,
ContentEncoding = ContentEncoding,
Expiration = Expiration,
MessageId = MessageId,
Priority = Priority,
Timestamp = Timestamp,
TypeProperty = TypeProperty,
UserId = UserId,
Payload = Payload,
EnableMacros = EnableMacros,
Headers = Headers.Count > 0
? Headers.ToDictionary(h => h.Key, h => h.Value)
: null
};
}
public void LoadPublisherMessage(RawPublisherMessage message)
{
DeliveryMode = message.DeliveryMode;
ContentType = message.ContentType ?? "";
CorrelationId = message.CorrelationId ?? "";
AppId = message.AppId ?? "";
ContentEncoding = message.ContentEncoding ?? "";
Expiration = message.Expiration ?? "";
MessageId = message.MessageId ?? "";
Priority = message.Priority ?? "";
Timestamp = message.Timestamp ?? "";
TypeProperty = message.TypeProperty ?? "";
UserId = message.UserId ?? "";
Payload = message.Payload ?? "";
EnableMacros = message.EnableMacros;
if (message.Headers != null)
Headers.ReplaceAll(message.Headers.Select(p => new Header
{
Key = p.Key,
Value = p.Value
}));
}
private static bool AnyNotEmpty(params string?[] values) private static bool AnyNotEmpty(params string?[] values)
{ {
return values.Any(s => !string.IsNullOrEmpty(s)); return values.Any(s => !string.IsNullOrEmpty(s));

View File

@ -0,0 +1,90 @@
//------------------------------------------------------------------------------
// <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.UI.Tab.Publisher {
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 StoredPublisherMessagesStrings {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal StoredPublisherMessagesStrings() {
}
/// <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.UI.Tab.Publisher.StoredPublisherMessagesStrings", typeof(StoredPublisherMessagesStrings).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 Do you want to delete the saved message &apos;{0}&apos;?.
/// </summary>
internal static string DeleteConfirmation {
get {
return ResourceManager.GetString("DeleteConfirmation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Delete message.
/// </summary>
internal static string DeleteConfirmationTitle {
get {
return ResourceManager.GetString("DeleteConfirmationTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Save as....
/// </summary>
internal static string DisplayNameDialogTitle {
get {
return ResourceManager.GetString("DisplayNameDialogTitle", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,129 @@
<?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="DeleteConfirmation" xml:space="preserve">
<value>Do you want to delete the saved message '{0}'?</value>
</data>
<data name="DeleteConfirmationTitle" xml:space="preserve">
<value>Delete message</value>
</data>
<data name="DisplayNameDialogTitle" xml:space="preserve">
<value>Save as...</value>
</data>
</root>

View File

@ -0,0 +1,103 @@
using System;
using System.Threading.Tasks;
using System.Windows;
using PettingZoo.Core.ExportImport.Publisher;
using PettingZoo.Core.Settings;
using PettingZoo.WPF.ViewModel;
namespace PettingZoo.UI.Tab.Publisher
{
public class StoredPublisherMessagesViewModel
{
private readonly IPublisherMessagesRepository publisherMessagesRepository;
public ObservableCollectionEx<StoredPublisherMessage> StoredMessages { get; } = new();
public StoredPublisherMessagesViewModel(IPublisherMessagesRepository publisherMessagesRepository)
{
this.publisherMessagesRepository = publisherMessagesRepository;
Task.Run(async () =>
{
var messages = await publisherMessagesRepository.GetStored();
await Application.Current.Dispatcher.BeginInvoke(() =>
{
StoredMessages.ReplaceAll(messages);
});
});
}
public void Save(StoredPublisherMessage? selectedMessage, PublisherMessage message, Action<StoredPublisherMessage> onSaved)
{
if (selectedMessage == null)
{
SaveAs(message, null, onSaved);
return;
}
Task.Run(async () =>
{
var updatedMessage = await publisherMessagesRepository.Update(selectedMessage.Id, selectedMessage.DisplayName, message);
await Application.Current.Dispatcher.BeginInvoke(() =>
{
var index = StoredMessages.IndexOf(selectedMessage);
if (index >= 0)
StoredMessages[index] = updatedMessage;
else
// Should not occur, but might as well handle it gracefully
StoredMessages.Add(updatedMessage);
onSaved(updatedMessage);
});
});
}
public void SaveAs(PublisherMessage message, string? originalDisplayName, Action<StoredPublisherMessage> onSaved)
{
var displayName = originalDisplayName ?? "";
if (!InputDialog.Execute(ref displayName, StoredPublisherMessagesStrings.DisplayNameDialogTitle))
return;
Task.Run(async () =>
{
var storedMessage = await publisherMessagesRepository.Add(displayName, message);
await Application.Current.Dispatcher.BeginInvoke(() =>
{
StoredMessages.Add(storedMessage);
onSaved(storedMessage);
});
});
}
public void Delete(StoredPublisherMessage message, Action onDeleted)
{
if (MessageBox.Show(
string.Format(StoredPublisherMessagesStrings.DeleteConfirmation, message.DisplayName),
StoredPublisherMessagesStrings.DeleteConfirmationTitle,
MessageBoxButton.YesNo,
MessageBoxImage.Question) != MessageBoxResult.Yes)
return;
Task.Run(async () =>
{
await publisherMessagesRepository.Delete(message.Id);
await Application.Current.Dispatcher.BeginInvoke(() =>
{
StoredMessages.Remove(message);
onDeleted();
});
});
}
}
}

View File

@ -1,6 +1,5 @@
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using PettingZoo.Core.Macros;
namespace PettingZoo.UI.Tab.Publisher namespace PettingZoo.UI.Tab.Publisher
{ {

View File

@ -3,6 +3,7 @@ using System.Text;
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.ExportImport.Publisher;
using PettingZoo.Core.Generator; using PettingZoo.Core.Generator;
using PettingZoo.Core.Macros; using PettingZoo.Core.Macros;
using PettingZoo.Core.Validation; using PettingZoo.Core.Validation;
@ -132,6 +133,29 @@ namespace PettingZoo.UI.Tab.Publisher
} }
public TapetiPublisherMessage GetPublisherMessage()
{
return new TapetiPublisherMessage
{
CorrelationId = CorrelationId,
Payload = Payload,
EnableMacros = EnableMacros,
ClassName = ClassName,
AssemblyName = AssemblyName
};
}
public void LoadPublisherMessage(TapetiPublisherMessage message)
{
CorrelationId = message.CorrelationId ?? "";
Payload = message.Payload ?? "";
EnableMacros = message.EnableMacros;
ClassName = message.ClassName ?? "";
AssemblyName = message.AssemblyName ?? "";
}
private void BrowseClassExecute() private void BrowseClassExecute()
{ {
exampleGenerator.Select(tabHostWindow, example => exampleGenerator.Select(tabHostWindow, example =>

View File

@ -8,6 +8,7 @@
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/" xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit" xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit"
xmlns:connection="clr-namespace:PettingZoo.Core.Connection;assembly=PettingZoo.Core" xmlns:connection="clr-namespace:PettingZoo.Core.Connection;assembly=PettingZoo.Core"
xmlns:controls="clr-namespace:PettingZoo.WPF.Controls;assembly=PettingZoo.WPF"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
@ -82,14 +83,14 @@
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="200"/> <RowDefinition Height="200"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<ToolBar Grid.Column="0" Grid.Row="0" ToolBarTray.IsLocked="True" Margin="0,0,0,4" Background="Transparent" Loaded="Toolbar_Loaded"> <controls:NoOverflowToolbar Grid.Column="0" Grid.Row="0" ToolBarTray.IsLocked="True" Margin="0,0,0,4" Background="Transparent">
<Button Command="{Binding CreatePublisherCommand}"> <Button Command="{Binding CreatePublisherCommand}">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<Image Source="{svgc:SvgImage Source=/Images/Publish.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/> <Image Source="{svgc:SvgImage Source=/Images/Publish.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
<TextBlock Margin="3,0,0,0" Text="{x:Static res:SubscriberViewStrings.ContextPublish}" /> <TextBlock Margin="3,0,0,0" Text="{x:Static res:SubscriberViewStrings.ContextPublish}" />
</StackPanel> </StackPanel>
</Button> </Button>
</ToolBar> </controls:NoOverflowToolbar>
<Border Grid.Column="0" Grid.Row="1" Style="{StaticResource SidePanel}"> <Border Grid.Column="0" Grid.Row="1" Style="{StaticResource SidePanel}">
<DockPanel> <DockPanel>

View File

@ -1,6 +1,4 @@
using System.Windows; using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
namespace PettingZoo.UI.Tab.Subscriber namespace PettingZoo.UI.Tab.Subscriber
@ -35,17 +33,5 @@ namespace PettingZoo.UI.Tab.Subscriber
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
Background = Brushes.Transparent; Background = Brushes.Transparent;
} }
private void Toolbar_Loaded(object sender, RoutedEventArgs e)
{
// Hide arrow on the right side of the toolbar
var toolBar = sender as ToolBar;
if (toolBar?.Template.FindName("OverflowGrid", toolBar) is FrameworkElement overflowGrid)
overflowGrid.Visibility = Visibility.Collapsed;
if (toolBar?.Template.FindName("MainPanelBorder", toolBar) is FrameworkElement mainPanelBorder)
mainPanelBorder.Margin = new Thickness(0);
}
} }
} }

View File

@ -9,7 +9,7 @@ using System.Windows;
using System.Windows.Forms; using System.Windows.Forms;
using System.Windows.Input; using System.Windows.Input;
using PettingZoo.Core.Connection; using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport; using PettingZoo.Core.ExportImport.Subscriber;
using PettingZoo.Core.Rendering; using PettingZoo.Core.Rendering;
using PettingZoo.WPF.ProgressWindow; using PettingZoo.WPF.ProgressWindow;
using PettingZoo.WPF.ViewModel; using PettingZoo.WPF.ViewModel;

View File

@ -5,6 +5,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:undocked="clr-namespace:PettingZoo.UI.Tab.Undocked" xmlns:undocked="clr-namespace:PettingZoo.UI.Tab.Undocked"
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/" xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
xmlns:controls="clr-namespace:PettingZoo.WPF.Controls;assembly=PettingZoo.WPF"
mc:Ignorable="d" mc:Ignorable="d"
d:DataContext="{d:DesignInstance undocked:DesignTimeUndockedTabHostViewModel, IsDesignTimeCreatable=True}" d:DataContext="{d:DesignInstance undocked:DesignTimeUndockedTabHostViewModel, IsDesignTimeCreatable=True}"
Title="{Binding Title}" Title="{Binding Title}"
@ -12,7 +13,7 @@
Width="800" Width="800"
WindowStyle="ThreeDBorderWindow"> WindowStyle="ThreeDBorderWindow">
<DockPanel> <DockPanel>
<ToolBar DockPanel.Dock="Top" ToolBarTray.IsLocked="True" Loaded="Toolbar_Loaded"> <controls:NoOverflowToolbar DockPanel.Dock="Top" ToolBarTray.IsLocked="True">
<Button Command="{Binding DockCommand}"> <Button Command="{Binding DockCommand}">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<Image Source="{svgc:SvgImage Source=/Images/Dock.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/> <Image Source="{svgc:SvgImage Source=/Images/Dock.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
@ -37,7 +38,7 @@
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
</ItemsControl> </ItemsControl>
</ToolBar> </controls:NoOverflowToolbar>
<ContentControl Content="{Binding Content}" /> <ContentControl Content="{Binding Content}" />
</DockPanel> </DockPanel>

View File

@ -1,7 +1,4 @@
using System.Windows; namespace PettingZoo.UI.Tab.Undocked
using System.Windows.Controls;
namespace PettingZoo.UI.Tab.Undocked
{ {
/// <summary> /// <summary>
/// Interaction logic for UndockedTabHostWindow.xaml /// Interaction logic for UndockedTabHostWindow.xaml
@ -41,17 +38,5 @@ namespace PettingZoo.UI.Tab.Undocked
viewModel.Deactivate(); viewModel.Deactivate();
}; };
} }
private void Toolbar_Loaded(object sender, RoutedEventArgs e)
{
// Hide arrow on the right side of the toolbar
var toolBar = sender as ToolBar;
if (toolBar?.Template.FindName("OverflowGrid", toolBar) is FrameworkElement overflowGrid)
overflowGrid.Visibility = Visibility.Collapsed;
if (toolBar?.Template.FindName("MainPanelBorder", toolBar) is FrameworkElement mainPanelBorder)
mainPanelBorder.Margin = new Thickness(0);
}
} }
} }

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using PettingZoo.Core.Connection; using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport; using PettingZoo.Core.ExportImport.Subscriber;
using PettingZoo.Core.Generator; using PettingZoo.Core.Generator;
using PettingZoo.Core.Macros; using PettingZoo.Core.Macros;
using PettingZoo.UI.Tab.Publisher; using PettingZoo.UI.Tab.Publisher;
@ -17,6 +17,7 @@ namespace PettingZoo.UI.Tab
private readonly IExampleGenerator exampleGenerator; private readonly IExampleGenerator exampleGenerator;
private readonly IExportImportFormatProvider exportImportFormatProvider; private readonly IExportImportFormatProvider exportImportFormatProvider;
private readonly IPayloadMacroProcessor payloadMacroProcessor; private readonly IPayloadMacroProcessor payloadMacroProcessor;
private readonly StoredPublisherMessagesViewModel storedPublisherMessagesViewModel;
// Not the cleanest way, but this factory itself can't be singleton without (justifyable) upsetting SimpleInjector // Not the cleanest way, but this factory itself can't be singleton without (justifyable) upsetting SimpleInjector
private static ISubscriber? replySubscriber; private static ISubscriber? replySubscriber;
@ -24,13 +25,14 @@ namespace PettingZoo.UI.Tab
public ViewTabFactory(ILogger logger, ITabHostProvider tabHostProvider, IExampleGenerator exampleGenerator, IExportImportFormatProvider exportImportFormatProvider, public ViewTabFactory(ILogger logger, ITabHostProvider tabHostProvider, IExampleGenerator exampleGenerator, IExportImportFormatProvider exportImportFormatProvider,
IPayloadMacroProcessor payloadMacroProcessor) IPayloadMacroProcessor payloadMacroProcessor, StoredPublisherMessagesViewModel storedPublisherMessagesViewModel)
{ {
this.logger = logger; this.logger = logger;
this.tabHostProvider = tabHostProvider; this.tabHostProvider = tabHostProvider;
this.exampleGenerator = exampleGenerator; this.exampleGenerator = exampleGenerator;
this.exportImportFormatProvider = exportImportFormatProvider; this.exportImportFormatProvider = exportImportFormatProvider;
this.payloadMacroProcessor = payloadMacroProcessor; this.payloadMacroProcessor = payloadMacroProcessor;
this.storedPublisherMessagesViewModel = storedPublisherMessagesViewModel;
} }
@ -63,7 +65,7 @@ namespace PettingZoo.UI.Tab
public void CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null) public void CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null)
{ {
var viewModel = new PublisherViewModel(this, connection, exampleGenerator, payloadMacroProcessor, fromReceivedMessage); var viewModel = new PublisherViewModel(this, connection, exampleGenerator, payloadMacroProcessor, storedPublisherMessagesViewModel, fromReceivedMessage);
var tab = new ViewTab<PublisherView, PublisherViewModel>( var tab = new ViewTab<PublisherView, PublisherViewModel>(
new PublisherView(viewModel), new PublisherView(viewModel),
viewModel, viewModel,