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]
public string? TestReaderWriter()
public string TestReaderWriter()
{
using var stringReader = new StringReader(testJson);
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;
namespace PettingZoo.Core.ExportImport
namespace PettingZoo.Core.ExportImport.Subscriber
{
public abstract class BaseProgressDecorator
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
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 Newtonsoft.Json.Linq;
using PettingZoo.Core.ExportImport;
using PettingZoo.Core.ExportImport.Subscriber;
namespace PettingZoo.Tapeti.Export
{

View File

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

View File

@ -7,7 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport;
using PettingZoo.Core.ExportImport.Subscriber;
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"?>
<!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.707 58.707" style="enable-background:new 0 0 58.707 58.707;" xml:space="preserve">
<g>
<g>
<polygon style="fill:#EFEBDE;" points="46.072,14 32.072,0 1.072,0 1.072,58 46.072,58 "/>
<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"/>
<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"/>
<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"/>
<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"/>
<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"/>
</g>
<polygon style="fill:#D5D0BB;" points="32.072,0 32.072,14 46.072,14 "/>
</g>
<g>
<polygon style="fill:#EDDCC7;" points="36.201,49.214 36.194,49.222 34.205,56.511 38.852,51.865 "/>
<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
L55.451,35.266z"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
viewBox="0 0 25.2705 25.269251"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<g
id="g18"
transform="translate(-32.36475,-33.43775)">
<g
id="g16">
<polygon
style="fill:#eddcc7"
points="34.205,56.511 38.852,51.865 36.201,49.214 36.194,49.222 "
id="polygon2" />
<path
style="fill:#d75a4a"
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"
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"/>
<polygon style="fill:#D6C4B1;" points="41.85,54.879 41.858,54.871 38.852,51.865 34.205,56.511 34.072,57 "/>
<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
L53.472,43.257z"/>
<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.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"/>
<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
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"/>
<rect
x="44.035999"
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>
</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"?>
<!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.195 58.195" style="enable-background:new 0 0 58.195 58.195;" xml:space="preserve">
<g>
<g>
<polygon style="fill:#EFEBDE;" points="45,14.097 31,0.097 0,0.097 0,58.097 45,58.097 "/>
<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
"/>
<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
"/>
<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:#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
"/>
<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
"/>
</g>
<polygon style="fill:#D5D0BB;" points="31,0.097 31,14.097 45,14.097 "/>
</g>
<g>
<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
C38.227,37.412,49.879,37.412,57,48.289L57,48.289z"/>
<circle style="fill:#556080;" cx="43.764" cy="46.007" r="5.909"/>
<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
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"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
viewBox="0 0 28.39 18.476"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<g
id="g10"
transform="translate(-29.806,-39.133)">
<g
id="g8">
<path
style="fill:#ffffff"
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" />
<circle
style="fill:#556080"
cx="43.764"
cy="46.007"
r="5.9089999"
id="circle4" />
<path
style="fill:#8697cb"
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"
id="path6" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

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

View File

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

View File

@ -8,5 +8,4 @@ Should-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

View File

@ -262,7 +262,7 @@ namespace PettingZoo.UI.Connection
// TODO create and enforce unique name?
var displayName = SelectedStoredConnection != null && SelectedStoredConnection.Id != Guid.Empty ? SelectedStoredConnection.DisplayName : "";
if (!ConnectionDisplayNameDialog.Execute(ref displayName))
if (!InputDialog.Execute(ref displayName, ConnectionWindowStrings.ProfileNameDialogTitle))
return;
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>
/// Looks up a localized string similar to Connection parameters.
/// </summary>

View File

@ -112,10 +112,10 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ButtonCancel" xml:space="preserve">
<value>Cancel</value>
@ -168,6 +168,9 @@
<data name="LastUsedDisplayName" xml:space="preserve">
<value>&lt;New connection&gt;</value>
</data>
<data name="ProfileNameDialogTitle" xml:space="preserve">
<value>Profile name</value>
</data>
<data name="WindowTitle" xml:space="preserve">
<value>Connection parameters</value>
</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:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
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"
Width="400"
SizeToContent="Height"
@ -11,15 +11,15 @@
WindowStyle="ToolWindow"
WindowStartupLocation="CenterOwner"
Style="{StaticResource WindowStyle}"
Title="{x:Static local:ConnectionDisplayNameStrings.WindowTitle}"
Title="{Binding Title}"
FocusManager.FocusedElement="{Binding ElementName=DisplayNameTextBox}"
d:DataContext="{d:DesignInstance local:ConnectionDisplayNameViewModel}">
d:DataContext="{d:DesignInstance local:InputDialogViewModel}">
<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}">
<Button IsDefault="True" Content="{x:Static local:ConnectionDisplayNameStrings.ButtonOK}" Style="{StaticResource FooterButton}" Command="{Binding OkCommand}"/>
<Button IsCancel="True" Content="{x:Static local:ConnectionDisplayNameStrings.ButtonCancel}" Style="{StaticResource FooterButton}"/>
<Button IsDefault="True" Content="{x:Static local:InputDialogStrings.ButtonOK}" Style="{StaticResource FooterButton}" Command="{Binding OkCommand}"/>
<Button IsCancel="True" Content="{x:Static local:InputDialogStrings.ButtonCancel}" Style="{StaticResource FooterButton}"/>
</UniformGrid>
</StackPanel>
</Window>

View File

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

View File

@ -8,7 +8,7 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace PettingZoo.UI.Connection {
namespace PettingZoo.UI {
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.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class ConnectionDisplayNameStrings {
public class InputDialogStrings {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal ConnectionDisplayNameStrings() {
internal InputDialogStrings() {
}
/// <summary>
@ -39,7 +39,7 @@ namespace PettingZoo.UI.Connection {
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PettingZoo.UI.Connection.ConnectionDisplayNameStrings", typeof(ConnectionDisplayNameStrings).Assembly);
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PettingZoo.UI.InputDialogStrings", typeof(InputDialogStrings).Assembly);
resourceMan = temp;
}
return resourceMan;
@ -77,14 +77,5 @@ namespace PettingZoo.UI.Connection {
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>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ButtonCancel" xml:space="preserve">
<value>Cancel</value>
@ -123,7 +123,4 @@
<data name="ButtonOK" xml:space="preserve">
<value>OK</value>
</data>
<data name="WindowTitle" xml:space="preserve">
<value>Profile name</value>
</data>
</root>

View File

@ -2,27 +2,36 @@
using System.Windows.Input;
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;
public string DisplayName
public string Title
{
get => displayName;
set => SetField(ref displayName, value, delegateCommandsChanged: new [] { okCommand });
get => title;
set => SetField(ref title, value);
}
public string Value
{
get => value;
set => SetField(ref this.value, value, delegateCommandsChanged: new [] { okCommand });
}
public ICommand OkCommand => okCommand;
public event EventHandler? OkClick;
public ConnectionDisplayNameViewModel()
public InputDialogViewModel()
{
okCommand = new DelegateCommand(OkExecute, OkCanExecute);
}
@ -36,7 +45,7 @@ namespace PettingZoo.UI.Connection
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:svgc="http://sharpvectors.codeplex.com/svgc/"
xmlns:ui="clr-namespace:PettingZoo.UI"
xmlns:controls="clr-namespace:PettingZoo.WPF.Controls;assembly=PettingZoo.WPF"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance main:DesignTimeMainWindowViewModel, IsDesignTimeCreatable=True}"
Width="800"
@ -24,7 +25,7 @@
<ui:BindingProxy x:Key="ContextMenuProxy" Data="{Binding}" />
</Window.Resources>
<DockPanel>
<ToolBar DockPanel.Dock="Top" ToolBarTray.IsLocked="True" Loaded="Toolbar_Loaded">
<controls:NoOverflowToolbar DockPanel.Dock="Top" ToolBarTray.IsLocked="True">
<Button Command="{Binding ConnectCommand}">
<StackPanel Orientation="Horizontal">
<Image Source="{svgc:SvgImage Source=/Images/Connect.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
@ -82,7 +83,7 @@
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ToolBar>
</controls:NoOverflowToolbar>
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem>
<StackPanel Orientation="Horizontal">

View File

@ -5,7 +5,7 @@ using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport;
using PettingZoo.Core.ExportImport.Subscriber;
using PettingZoo.UI.Connection;
using PettingZoo.UI.Subscribe;
using PettingZoo.UI.Tab;
@ -139,18 +139,6 @@ namespace PettingZoo.UI.Main
public double TabWidth => SubscriberTabs.ActualWidth;
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
}

View File

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

View File

@ -6,12 +6,20 @@
xmlns:res="clr-namespace:PettingZoo.UI.Tab.Publisher"
xmlns:controls="clr-namespace:PettingZoo.WPF.Controls;assembly=PettingZoo.WPF"
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
xmlns:valueConverters="clr-namespace:PettingZoo.WPF.ValueConverters;assembly=PettingZoo.WPF"
mc:Ignorable="d"
d:DesignHeight="450"
d:DesignWidth="800"
d:DataContext="{d:DesignInstance res:DesignTimePublisherViewModel, IsDesignTimeCreatable=True}"
Background="White">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<Grid>
<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"/>
@ -75,4 +83,76 @@
<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>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Style="{StaticResource HeaderLabel}" Content="{x:Static res:PublisherViewStrings.PanelTitleMessages}"/>
<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">
<Image Source="{svgc:SvgImage Source=/Images/Save.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
<TextBlock Margin="3,0,0,0" Text="{x:Static res:PublisherViewStrings.ToolbarSave}" />
</StackPanel>
</Button>
<Button Command="{Binding SaveAsCommand}">
<StackPanel Orientation="Horizontal">
<Image Source="{svgc:SvgImage Source=/Images/SaveAs.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
<TextBlock Margin="3,0,0,0" Text="{x:Static res:PublisherViewStrings.ToolbarSaveAs}" />
</StackPanel>
</Button>
<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>
<ListBox Grid.Row="2" ItemsSource="{Binding StoredMessages}" SelectedValue="{Binding SelectedStoredMessage}">
<ListBox.Resources>
<valueConverters:SameReferenceConverter x:Key="SameReferenceConverter" />
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource SameReferenceConverter}">
<Binding RelativeSource="{RelativeSource AncestorType={x:Type ListBoxItem}}" Path="DataContext" />
<Binding RelativeSource="{RelativeSource AncestorType={x:Type ListBox}}" Path="DataContext.ActiveStoredMessage" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
<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>

View File

@ -1,27 +1,25 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport.Publisher;
using PettingZoo.Core.Generator;
using PettingZoo.Core.Macros;
using PettingZoo.Core.Settings;
using PettingZoo.WPF.ViewModel;
namespace PettingZoo.UI.Tab.Publisher
{
public enum MessageType
{
Raw,
Tapeti
}
public class PublisherViewModel : BaseViewModel, ITabToolbarCommands, ITabHostWindowNotify, IPublishDestination
{
private readonly IConnection connection;
private readonly IExampleGenerator exampleGenerator;
private readonly IPayloadMacroProcessor payloadMacroProcessor;
private readonly StoredPublisherMessagesViewModel storedPublisherMessagesViewModel;
private readonly ITabFactory tabFactory;
private bool sendToExchange = true;
@ -29,16 +27,27 @@ namespace PettingZoo.UI.Tab.Publisher
private string routingKey = "";
private string queue = "";
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 ICommand? messageTypePublishCommand;
private RawPublisherViewModel? rawPublisherViewModel;
private UserControl? rawPublisherView;
private TapetiPublisherViewModel? tapetiPublisherViewModel;
private UserControl? tapetiPublisherView;
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 Window? tabHostWindow;
@ -47,8 +56,9 @@ namespace PettingZoo.UI.Tab.Publisher
{
get => sendToExchange;
set => SetField(ref sendToExchange, value,
delegateCommandsChanged: new [] { publishCommand },
otherPropertiesChanged: new[] { nameof(SendToQueue), nameof(ExchangeVisibility), nameof(QueueVisibility), nameof(Title) });
delegateCommandsChanged: new[] { publishCommand },
otherPropertiesChanged: new[]
{ nameof(SendToQueue), nameof(ExchangeVisibility), nameof(QueueVisibility), nameof(Title) });
}
@ -69,14 +79,16 @@ namespace PettingZoo.UI.Tab.Publisher
public string 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
{
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
{
get => replyToSpecified;
set => SetField(ref replyToSpecified, value, otherPropertiesChanged: new[] { nameof(ReplyToNewSubscriber) });
get => !ReplyToNewSubscriber;
set => ReplyToNewSubscriber = !value;
}
public bool ReplyToNewSubscriber
{
get => !ReplyToSpecified;
set => ReplyToSpecified = !value;
get => replyToNewSubscriber;
set => SetField(ref replyToNewSubscriber, value,
otherPropertiesChanged: new[] { nameof(ReplyToSpecified) });
}
@ -105,7 +118,7 @@ namespace PettingZoo.UI.Tab.Publisher
public virtual Visibility QueueVisibility => SendToQueue ? Visibility.Visible : Visibility.Collapsed;
public MessageType MessageType
public PublisherMessageType MessageType
{
get => messageType;
set
@ -124,14 +137,20 @@ namespace PettingZoo.UI.Tab.Publisher
public bool MessageTypeRaw
{
get => MessageType == MessageType.Raw;
set { if (value) MessageType = MessageType.Raw; }
get => MessageType == PublisherMessageType.Raw;
set
{
if (value) MessageType = PublisherMessageType.Raw;
}
}
public bool MessageTypeTapeti
{
get => MessageType == MessageType.Tapeti;
set { if (value) MessageType = MessageType.Tapeti; }
get => MessageType == PublisherMessageType.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 SaveCommand => saveCommand;
public ICommand SaveAsCommand => saveAsCommand;
public ICommand DeleteCommand => deleteCommand;
public ICommand LoadStoredMessage => loadStoredMessage;
public string Title => SendToQueue
? string.IsNullOrWhiteSpace(Queue) ? PublisherViewStrings.TabTitleEmpty : string.Format(PublisherViewStrings.TabTitle, Queue)
: string.IsNullOrWhiteSpace(RoutingKey) ? PublisherViewStrings.TabTitleEmpty : string.Format(PublisherViewStrings.TabTitle, RoutingKey);
? string.IsNullOrWhiteSpace(Queue) ? PublisherViewStrings.TabTitleEmpty :
string.Format(PublisherViewStrings.TabTitle, Queue)
: string.IsNullOrWhiteSpace(RoutingKey)
? PublisherViewStrings.TabTitleEmpty
: string.Format(PublisherViewStrings.TabTitle, RoutingKey);
public IEnumerable<TabToolbarCommand> ToolbarCommands => toolbarCommands;
@ -157,24 +202,33 @@ namespace PettingZoo.UI.Tab.Publisher
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.exampleGenerator = exampleGenerator;
this.payloadMacroProcessor = payloadMacroProcessor;
this.storedPublisherMessagesViewModel = storedPublisherMessagesViewModel;
this.tabFactory = tabFactory;
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[]
{
new TabToolbarCommand(PublishCommand, PublisherViewStrings.CommandPublish, SvgIconHelper.LoadFromResource("/Images/PublishSend.svg"))
new TabToolbarCommand(PublishCommand, PublisherViewStrings.CommandPublish,
SvgIconHelper.LoadFromResource("/Images/PublishSend.svg"))
};
if (fromReceivedMessage != null)
SetMessageTypeControl(fromReceivedMessage);
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)
{
case MessageType.Raw:
RawPublisherViewModel rawPublisherViewModel;
case PublisherMessageType.Raw:
if (rawPublisherView == null)
{
rawPublisherViewModel = new RawPublisherViewModel(connection, this, payloadMacroProcessor);
@ -216,19 +268,17 @@ namespace PettingZoo.UI.Tab.Publisher
publishCommand.RaiseCanExecuteChanged();
};
rawPublisherView ??= new RawPublisherView(rawPublisherViewModel);
rawPublisherView = new RawPublisherView(rawPublisherViewModel);
}
else
rawPublisherViewModel = (RawPublisherViewModel)rawPublisherView.DataContext;
Debug.Assert(rawPublisherViewModel != null);
MessageTypeControl = rawPublisherView;
messageTypePublishCommand = rawPublisherViewModel.PublishCommand;
break;
case MessageType.Tapeti:
TapetiPublisherViewModel tapetiPublisherViewModel;
case PublisherMessageType.Tapeti:
if (tapetiPublisherView == null)
{
tapetiPublisherViewModel = new TapetiPublisherViewModel(connection, this, exampleGenerator, payloadMacroProcessor);
@ -237,13 +287,13 @@ namespace PettingZoo.UI.Tab.Publisher
publishCommand.RaiseCanExecuteChanged();
};
tapetiPublisherView ??= new TapetiPublisherView(tapetiPublisherViewModel);
tapetiPublisherView = new TapetiPublisherView(tapetiPublisherViewModel);
if (tabHostWindow != null)
tapetiPublisherViewModel.HostWindowChanged(tabHostWindow);
}
else
tapetiPublisherViewModel = (TapetiPublisherViewModel)tapetiPublisherView.DataContext;
Debug.Assert(tapetiPublisherViewModel != null);
MessageTypeControl = tapetiPublisherView;
@ -266,17 +316,17 @@ namespace PettingZoo.UI.Tab.Publisher
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);
MessageType = MessageType.Tapeti;
MessageType = PublisherMessageType.Tapeti;
}
else
{
var rawPublisherViewModel = new RawPublisherViewModel(connection, this, payloadMacroProcessor, fromReceivedMessage);
rawPublisherViewModel = new RawPublisherViewModel(connection, this, payloadMacroProcessor, fromReceivedMessage);
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);
}
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 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 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>
/// Looks up a localized string similar to Re: .
/// </summary>
@ -194,5 +203,32 @@ namespace PettingZoo.UI.Tab.Publisher {
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">
<value>Tapeti message</value>
</data>
<data name="PanelTitleMessages" xml:space="preserve">
<value>Saved messages</value>
</data>
<data name="ReplyToCorrelationIdPrefix" xml:space="preserve">
<value>Re: </value>
</data>
@ -162,4 +165,13 @@
<data name="TabTitleEmpty" xml:space="preserve">
<value>Publish</value>
</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>

View File

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

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
@ -7,6 +6,7 @@ using System.Text;
using System.Windows;
using System.Windows.Input;
using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport.Publisher;
using PettingZoo.Core.Macros;
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
{
get => deliveryMode == MessageDeliveryMode.Persistent ? 1 : 0;
set => SetField(ref deliveryMode, value == 1 ? MessageDeliveryMode.Persistent : MessageDeliveryMode.NonPersistent);
get => DeliveryMode == MessageDeliveryMode.Persistent ? 1 : 0;
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;
@ -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)
{
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.Controls;
using PettingZoo.Core.Macros;
namespace PettingZoo.UI.Tab.Publisher
{

View File

@ -3,6 +3,7 @@ using System.Text;
using System.Windows;
using System.Windows.Input;
using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport.Publisher;
using PettingZoo.Core.Generator;
using PettingZoo.Core.Macros;
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()
{
exampleGenerator.Select(tabHostWindow, example =>

View File

@ -8,6 +8,7 @@
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit"
xmlns:connection="clr-namespace:PettingZoo.Core.Connection;assembly=PettingZoo.Core"
xmlns:controls="clr-namespace:PettingZoo.WPF.Controls;assembly=PettingZoo.WPF"
mc:Ignorable="d"
d:DesignHeight="450"
d:DesignWidth="800"
@ -82,14 +83,14 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="200"/>
</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}">
<StackPanel Orientation="Horizontal">
<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}" />
</StackPanel>
</Button>
</ToolBar>
</controls:NoOverflowToolbar>
<Border Grid.Column="0" Grid.Row="1" Style="{StaticResource SidePanel}">
<DockPanel>

View File

@ -1,6 +1,4 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Highlighting;
namespace PettingZoo.UI.Tab.Subscriber
@ -35,17 +33,5 @@ namespace PettingZoo.UI.Tab.Subscriber
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
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.Input;
using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport;
using PettingZoo.Core.ExportImport.Subscriber;
using PettingZoo.Core.Rendering;
using PettingZoo.WPF.ProgressWindow;
using PettingZoo.WPF.ViewModel;

View File

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

View File

@ -1,7 +1,4 @@
using System.Windows;
using System.Windows.Controls;
namespace PettingZoo.UI.Tab.Undocked
namespace PettingZoo.UI.Tab.Undocked
{
/// <summary>
/// Interaction logic for UndockedTabHostWindow.xaml
@ -41,17 +38,5 @@ namespace PettingZoo.UI.Tab.Undocked
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.Collections.Generic;
using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport;
using PettingZoo.Core.ExportImport.Subscriber;
using PettingZoo.Core.Generator;
using PettingZoo.Core.Macros;
using PettingZoo.UI.Tab.Publisher;
@ -17,6 +17,7 @@ namespace PettingZoo.UI.Tab
private readonly IExampleGenerator exampleGenerator;
private readonly IExportImportFormatProvider exportImportFormatProvider;
private readonly IPayloadMacroProcessor payloadMacroProcessor;
private readonly StoredPublisherMessagesViewModel storedPublisherMessagesViewModel;
// Not the cleanest way, but this factory itself can't be singleton without (justifyable) upsetting SimpleInjector
private static ISubscriber? replySubscriber;
@ -24,13 +25,14 @@ namespace PettingZoo.UI.Tab
public ViewTabFactory(ILogger logger, ITabHostProvider tabHostProvider, IExampleGenerator exampleGenerator, IExportImportFormatProvider exportImportFormatProvider,
IPayloadMacroProcessor payloadMacroProcessor)
IPayloadMacroProcessor payloadMacroProcessor, StoredPublisherMessagesViewModel storedPublisherMessagesViewModel)
{
this.logger = logger;
this.tabHostProvider = tabHostProvider;
this.exampleGenerator = exampleGenerator;
this.exportImportFormatProvider = exportImportFormatProvider;
this.payloadMacroProcessor = payloadMacroProcessor;
this.storedPublisherMessagesViewModel = storedPublisherMessagesViewModel;
}
@ -63,7 +65,7 @@ namespace PettingZoo.UI.Tab
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>(
new PublisherView(viewModel),
viewModel,