Compare commits

...

3 Commits

9 changed files with 380 additions and 19 deletions

View File

@ -1,10 +1,13 @@
using System.ComponentModel; using System.ComponentModel;
using MBS.Core.Extensibility; using MBS.Core.Extensibility;
using System.ComponentModel.Design;
namespace MBS.Core; namespace MBS.Core;
public class Application public class Application
{ {
public Command.CommandCollection Commands { get; } = new Command.CommandCollection();
public static Application? Instance { get; private set; } public static Application? Instance { get; private set; }
public CommandLine CommandLine { get; } = new CommandLine(); public CommandLine CommandLine { get; } = new CommandLine();
@ -501,4 +504,31 @@ public class Application
{ {
return new Plugin[0]; return new Plugin[0];
} }
private Dictionary<Union<Guid, string>, List<EventHandler<CommandEventArgs>>> _commandEventHandlers = new Dictionary<Union<Guid, string>, List<EventHandler<CommandEventArgs>>>();
public void AttachCommandEventHandler(Union<Guid, string> commandId, EventHandler<CommandEventArgs> handler)
{
if (!_commandEventHandlers.ContainsKey(commandId))
{
_commandEventHandlers[commandId] = new List<EventHandler<CommandEventArgs>>();
}
if (!_commandEventHandlers[commandId].Contains(handler))
{
_commandEventHandlers[commandId].Add(handler);
}
}
public void ExecuteCommand(Union<Guid, string> commandId)
{
if (_commandEventHandlers.ContainsKey(commandId))
{
foreach (EventHandler<CommandEventArgs> handler in _commandEventHandlers[commandId])
{
handler(this, new CommandEventArgs(commandId));
}
}
else
{
Console.WriteLine("command event handler not registered for command '{0}'", commandId);
}
}
} }

View File

@ -19,7 +19,7 @@ namespace MBS.Core;
public class CommandEventArgs : EventArgs public class CommandEventArgs : EventArgs
{ {
public Command Command { get; private set; } public Command? Command { get; private set; }
private Dictionary<string, object> _NamedParameters = new Dictionary<string, object>(); private Dictionary<string, object> _NamedParameters = new Dictionary<string, object>();
public T GetNamedParameter<T>(string key, T defaultValue = default(T)) public T GetNamedParameter<T>(string key, T defaultValue = default(T))
@ -35,6 +35,12 @@ public class CommandEventArgs : EventArgs
return defaultValue; return defaultValue;
} }
public Union<Guid, string> CommandID { get; }
public CommandEventArgs(Union<Guid, string> commandId)
{
CommandID = commandId;
}
public CommandEventArgs(Command command, KeyValuePair<string, object>[] namedParameters = null) public CommandEventArgs(Command command, KeyValuePair<string, object>[] namedParameters = null)
{ {

View File

@ -29,9 +29,9 @@ public abstract class CommandItem
{ {
for (int i = 0; i < Count; i++) for (int i = 0; i < Count; i++)
{ {
if (this[i] is CommandReferenceCommandItem) if (this[i] is CommandReferenceCommandItem crci)
{ {
if ((this[i] as CommandReferenceCommandItem).CommandID.Equals(value)) if (crci.CommandID.Equals(value))
return i; return i;
} }
} }
@ -61,19 +61,7 @@ public class ActionCommandItem : CommandItem
} }
} }
} }
public class CommandReferenceCommandItem : CommandItem
{
private string mvarCommandID = String.Empty;
public string CommandID { get { return mvarCommandID; } set { mvarCommandID = value; } }
public CommandReferenceCommandItem()
{
}
public CommandReferenceCommandItem(string commandID)
{
mvarCommandID = commandID;
}
}
public class CommandPlaceholderCommandItem : CommandItem public class CommandPlaceholderCommandItem : CommandItem
{ {
private string mvarPlaceholderID = String.Empty; private string mvarPlaceholderID = String.Empty;
@ -84,9 +72,7 @@ public class CommandPlaceholderCommandItem : CommandItem
mvarPlaceholderID = placeholderID; mvarPlaceholderID = placeholderID;
} }
} }
public class SeparatorCommandItem : CommandItem
{
}
public class GroupCommandItem : CommandItem public class GroupCommandItem : CommandItem
{ {
public CommandItemCollection Items { get; } = new CommandItemCollection(); public CommandItemCollection Items { get; } = new CommandItemCollection();

View File

@ -0,0 +1,27 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of editor-dotnet.
//
// editor-dotnet is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// editor-dotnet is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
namespace MBS.Core;
public class CommandReferenceCommandItem : CommandItem
{
public Union<Guid, string> CommandID { get; }
public CommandReferenceCommandItem(Union<Guid, string> commandId)
{
CommandID = commandId;
}
}

View File

@ -0,0 +1,26 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of editor-dotnet.
//
// editor-dotnet is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// editor-dotnet is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
namespace MBS.Core;
/// <summary>
/// Defines a command item which separates groups of related command items.
/// </summary>
public class SeparatorCommandItem : CommandItem
{
}

View File

@ -0,0 +1,189 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of editor-dotnet.
//
// editor-dotnet is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// editor-dotnet is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
using System.Diagnostics.CodeAnalysis;
public struct Union<T1, T2>
{
private T1 _value1;
private T2 _value2;
private int _which;
private bool _notEmpty;
public bool IsEmpty { get { return !_notEmpty; } }
public override string ToString()
{
if (_which == 1)
{
return _value1?.ToString() ?? "";
}
else if (_which == 2)
{
return _value2?.ToString() ?? "";
}
throw new InvalidOperationException("internal error: _which state inconsistent!");
}
private Union(T1 value1, T2 value2, int which)
{
_value1 = value1;
_value2 = value2;
_which = which;
_notEmpty = true;
}
public static implicit operator Union<T1, T2>(T1 value1)
{
return new Union<T1, T2>(value1, default(T2), 1);
}
public static implicit operator Union<T1, T2>(T2 value2)
{
return new Union<T1, T2>(default(T1), value2, 2);
}
public static implicit operator T1(Union<T1, T2> union)
{
if (union._which == 1)
{
return union._value1;
}
throw new InvalidOperationException();
}
public static implicit operator T2(Union<T1, T2> union)
{
if (union._which == 2)
{
return union._value2;
}
throw new InvalidOperationException();
}
public static implicit operator Union<T1, T2>(Union<T2, T1> other)
{
return new Union<T1, T2>(other._value2, other._value1, other._which == 2 ? 1 : 2);
}
public override bool Equals([NotNullWhen(true)] object? obj)
{
if (obj is Union<T1, T2>)
{
return (this.GetValue()?.Equals(((Union<T1, T2>)obj).GetValue())).GetValueOrDefault(false);
}
else if (obj is T1)
{
return (_value1?.Equals((T1)obj)).GetValueOrDefault(false);
}
else if (obj is T2)
{
return (_value2?.Equals((T2)obj)).GetValueOrDefault(false);
}
return false;
}
private object? GetValue()
{
if (_which == 1)
return _value1;
else if (_which == 2)
return _value2;
throw new InvalidOperationException();
}
}
public struct Union<T1, T2, T3>
{
private object _value;
private bool _notEmpty;
public bool IsEmpty { get { return !_notEmpty; } }
public override string ToString()
{
return _value?.ToString();
}
private Union(object value)
{
_value = value;
_notEmpty = true;
}
public static implicit operator Union<T1, T2, T3>(T1 value)
{
return new Union<T1, T2, T3>(value);
}
public static implicit operator Union<T1, T2, T3>(T2 value)
{
return new Union<T1, T2, T3>(value);
}
public static implicit operator Union<T1, T2, T3>(T3 value)
{
return new Union<T1, T2, T3>(value);
}
public static implicit operator T1(Union<T1, T2, T3> union)
{
if (union._value is T1)
{
return (T1)union._value;
}
throw new InvalidOperationException();
}
public static implicit operator T2(Union<T1, T2, T3> union)
{
if (union._value is T2)
{
return (T2)union._value;
}
throw new InvalidOperationException();
}
public static implicit operator T3(Union<T1, T2, T3> union)
{
if (union._value is T3)
{
return (T3)union._value;
}
throw new InvalidOperationException();
}
public override bool Equals([NotNullWhen(true)] object? obj)
{
if (obj is Union<T1, T2, T3>)
{
return (this.GetValue()?.Equals(((Union<T1, T2, T3>)obj).GetValue())).GetValueOrDefault(false);
}
else if (obj is T1)
{
return (_value?.Equals((T1)obj)).GetValueOrDefault(false);
}
else if (obj is T2)
{
return (_value?.Equals((T2)obj)).GetValueOrDefault(false);
}
else if (obj is T3)
{
return (_value?.Equals((T3)obj)).GetValueOrDefault(false);
}
return false;
}
private object? GetValue()
{
return _value;
}
}

View File

@ -0,0 +1 @@
global using NUnit.Framework;

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit.Analyzers" Version="3.6.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\lib\MBS.Core\MBS.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,72 @@
using System.Diagnostics.CodeAnalysis;
namespace MBS.Core.Tests;
public class UnionTests
{
public class Union2
{
[SetUp]
public void Setup()
{
}
public const string TEST_VALUE_STR = "Test value";
public const int TEST_VALUE_INT = 314159;
[Test]
public void OperatorEqualsToStringLiteral()
{
Union<string, int> value = TEST_VALUE_STR;
Assert.That(value == TEST_VALUE_STR);
}
[Test]
public void MethodEqualsToStringLiteral()
{
Union<string, int> value = TEST_VALUE_STR;
Assert.That(value.Equals(TEST_VALUE_STR));
}
}
public class Union3
{
[SetUp]
public void Setup()
{
}
public const string TEST_VALUE_STR = "Test value";
public const int TEST_VALUE_INT = 314159;
[Test]
public void OperatorEqualsToInt32Literal()
{
Union<string, int, double> value = TEST_VALUE_INT;
Assert.That(value == TEST_VALUE_INT);
}
[Test]
public void MethodEqualsToStringLiteral()
{
Union<string, int, double> value = TEST_VALUE_STR;
Assert.That(value.Equals(TEST_VALUE_STR));
}
[Test]
public void OperatorEqualsToDoubleLiteral()
{
Union<string, int, double> value = 0.53;
Assert.That(value == 0.53);
}
[Test]
public void MethodCallWithUnion()
{
Union<string, int, double> value = 25.75;
PrintDoubleValue(value);
}
private void PrintDoubleValue(double value)
{
Assert.That(value, Is.EqualTo(25.75));
}
}
}