huh
This commit is contained in:
commit
e5af2f5dec
@ -1,22 +1,228 @@
|
|||||||
using System.ComponentModel.Design;
|
using System.ComponentModel;
|
||||||
|
using MBS.Core.Extensibility;
|
||||||
|
|
||||||
|
using System.ComponentModel.Design;
|
||||||
|
|
||||||
namespace MBS.Core;
|
namespace MBS.Core;
|
||||||
|
|
||||||
public class Application
|
public class Application
|
||||||
{
|
{
|
||||||
public IList<Command> Commands { get; } = new List<Command>();
|
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();
|
||||||
protected virtual void OnStartup(EventArgs e)
|
protected virtual void OnStartup(EventArgs e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
public event ApplicationActivatedEventHandler BeforeActivated;
|
||||||
|
protected virtual void OnBeforeActivated(ApplicationActivatedEventArgs e)
|
||||||
|
{
|
||||||
|
BeforeActivated?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event ApplicationActivatedEventHandler Activated;
|
||||||
protected virtual void OnActivated(ApplicationActivatedEventArgs e)
|
protected virtual void OnActivated(ApplicationActivatedEventArgs e)
|
||||||
{
|
{
|
||||||
|
Activated?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public event ApplicationActivatedEventHandler AfterActivated;
|
||||||
|
protected virtual void OnAfterActivated(ApplicationActivatedEventArgs e)
|
||||||
|
{
|
||||||
|
AfterActivated?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses the option.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><c>true</c>, if option was parsed, <c>false</c> otherwise.</returns>
|
||||||
|
/// <param name="args">Arguments.</param>
|
||||||
|
/// <param name="index">Index.</param>
|
||||||
|
/// <param name="list">The list into which to add the option if it has been specified.</param>
|
||||||
|
/// <param name="optionSet">The set of available options.</param>
|
||||||
|
private bool ParseOption(string[] args, ref int index, IList<CommandLineOption> list, CommandLineOption.CommandLineOptionCollection optionSet)
|
||||||
|
{
|
||||||
|
string longOptionPrefix = "--", shortOptionPrefix = "-";
|
||||||
|
|
||||||
|
bool breakout = false;
|
||||||
|
if (args[index].StartsWith(shortOptionPrefix) && args[index].Length == (shortOptionPrefix.Length + 1))
|
||||||
|
{
|
||||||
|
char shortOptionChar = args[index][args[index].Length - 1];
|
||||||
|
CommandLineOption option = optionSet[shortOptionChar];
|
||||||
|
if (option != null)
|
||||||
|
{
|
||||||
|
if (option.Abbreviation == shortOptionChar)
|
||||||
|
{
|
||||||
|
if (option.Type != CommandLineOptionValueType.None)
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
option.Value = args[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
option.Value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list != null)
|
||||||
|
list.Add(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list.Add(new CommandLineOption() { Abbreviation = shortOptionChar });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args[index].StartsWith(longOptionPrefix))
|
||||||
|
{
|
||||||
|
// long option format is --name[=value]
|
||||||
|
string name = args[index].Substring(longOptionPrefix.Length);
|
||||||
|
string value = null;
|
||||||
|
if (name.Contains("="))
|
||||||
|
{
|
||||||
|
int idx = name.IndexOf('=');
|
||||||
|
value = name.Substring(idx + 1);
|
||||||
|
name = name.Substring(0, idx);
|
||||||
|
}
|
||||||
|
CommandLineOption option = optionSet[name];
|
||||||
|
if (option != null)
|
||||||
|
{
|
||||||
|
if (option.Type != CommandLineOptionValueType.None)
|
||||||
|
{
|
||||||
|
// index++;
|
||||||
|
// option.Value = args[index];
|
||||||
|
if (!name.Contains("="))
|
||||||
|
{
|
||||||
|
// already taken care of the true case above
|
||||||
|
if (index + 1 < args.Length)
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
value = args[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
option.Value = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
option.Value = true;
|
||||||
|
}
|
||||||
|
list.Add(option);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list.Add(new CommandLineOption() { Name = name });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we have reached a non-option
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual int StartInternal()
|
protected virtual int StartInternal()
|
||||||
{
|
{
|
||||||
|
CommandLine cline = new CommandLine();
|
||||||
|
string[] args = CommandLine.Arguments;
|
||||||
|
|
||||||
|
if (args.Length > 0)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0; i < args.Length; i++)
|
||||||
|
{
|
||||||
|
if (ParseOption(args, ref i, cline.Options, CommandLine.Options))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have finished parsing the first set of options ("global" options)
|
||||||
|
// now we see if we have commands
|
||||||
|
if (CommandLine.Commands.Count > 0 && i < args.Length)
|
||||||
|
{
|
||||||
|
// we support commands like git and apt, "appname --app-global-options <command> --command-options"
|
||||||
|
CommandLineCommand cmd = CommandLine.Commands[args[i]];
|
||||||
|
if (cmd != null)
|
||||||
|
{
|
||||||
|
for (i++; i < args.Length; i++)
|
||||||
|
{
|
||||||
|
if (ParseOption(args, ref i, cline.Options, cmd.Options))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cline.Command = cmd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// assume filename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (/* intentionally left blank */; i < args.Length; i++)
|
||||||
|
{
|
||||||
|
cline.FileNames.Add(args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationActivatedEventArgs e = new ApplicationActivatedEventArgs(true, ApplicationActivationType.CommandLineLaunch, cline);
|
||||||
|
|
||||||
|
if (CommandLine.Options["help"]?.Value is bool && ((bool)CommandLine.Options["help"]?.Value) == true)
|
||||||
|
{
|
||||||
|
if (ShowCommandLineHelp(out int resultCode))
|
||||||
|
{
|
||||||
|
return resultCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OnStartup(EventArgs.Empty);
|
||||||
|
if (cline.Command != null && cline.Command.ActivationDelegate != null)
|
||||||
|
{
|
||||||
|
OnBeforeActivated(e);
|
||||||
|
if (!e.Success)
|
||||||
|
{
|
||||||
|
Console.WriteLine(String.Format("Try '{0} --help' for more information.", ShortName));
|
||||||
|
return e.ExitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use the activation delegate instead of calling OnActivated
|
||||||
|
cline.Command.ActivationDelegate(e);
|
||||||
|
if (!e.Success)
|
||||||
|
{
|
||||||
|
Console.WriteLine(String.Format("Try '{0} --help' for more information.", ShortName));
|
||||||
|
return e.ExitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnAfterActivated(e);
|
||||||
|
if (!e.Success)
|
||||||
|
{
|
||||||
|
Console.WriteLine(String.Format("Try '{0} --help' for more information.", ShortName));
|
||||||
|
return e.ExitCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OnBeforeActivated(e);
|
||||||
|
if (!e.Success)
|
||||||
|
{
|
||||||
|
Console.WriteLine(String.Format("Try '{0} --help' for more information.", ShortName));
|
||||||
|
return e.ExitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnActivated(e);
|
||||||
|
if (!e.Success)
|
||||||
|
{
|
||||||
|
Console.WriteLine(String.Format("Try '{0} --help' for more information.", ShortName));
|
||||||
|
return e.ExitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnAfterActivated(e);
|
||||||
|
if (!e.Success)
|
||||||
|
{
|
||||||
|
Console.WriteLine(String.Format("Try '{0} --help' for more information.", ShortName));
|
||||||
|
return e.ExitCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return e.ExitCode;
|
||||||
|
/*
|
||||||
OnStartup(EventArgs.Empty);
|
OnStartup(EventArgs.Empty);
|
||||||
|
|
||||||
CommandLine cline = new CommandLine();
|
CommandLine cline = new CommandLine();
|
||||||
@ -26,11 +232,24 @@ public class Application
|
|||||||
OnActivated(e);
|
OnActivated(e);
|
||||||
|
|
||||||
return e.ExitCode;
|
return e.ExitCode;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<CancelEventArgs> BeforeStartInternal;
|
||||||
|
protected virtual void OnBeforeStartInternal(CancelEventArgs e)
|
||||||
|
{
|
||||||
|
BeforeStartInternal?.Invoke(this, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Start()
|
public int Start()
|
||||||
{
|
{
|
||||||
Instance = this;
|
Instance = this;
|
||||||
|
|
||||||
|
CancelEventArgs e = new CancelEventArgs();
|
||||||
|
OnBeforeStartInternal(e);
|
||||||
|
if (e.Cancel)
|
||||||
|
return 2;
|
||||||
|
|
||||||
int exitCode = StartInternal();
|
int exitCode = StartInternal();
|
||||||
|
|
||||||
Instance = null;
|
Instance = null;
|
||||||
@ -46,12 +265,251 @@ public class Application
|
|||||||
StopInternal(exitCode);
|
StopInternal(exitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<Union<Guid, string>, List<CommandEventHandler>> _commandEventHandlers = new Dictionary<Union<Guid, string>, List<CommandEventHandler>>();
|
private string _UniqueName = null;
|
||||||
public void AttachCommandEventHandler(Union<Guid, string> commandId, CommandEventHandler handler)
|
public string UniqueName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_UniqueName == null)
|
||||||
|
{
|
||||||
|
return ShortName;
|
||||||
|
}
|
||||||
|
return _UniqueName;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_UniqueName = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string mvarBasePath = null;
|
||||||
|
public string BasePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (mvarBasePath == null)
|
||||||
|
{
|
||||||
|
// Set up the base path for the current application. Should this be able to be
|
||||||
|
// overridden with a switch (/basepath:...) ?
|
||||||
|
mvarBasePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
|
||||||
|
}
|
||||||
|
return mvarBasePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual string DataDirectoryName => ShortName;
|
||||||
|
public string[] EnumerateDataPaths() => EnumerateDataPaths(FindFileOptions.All);
|
||||||
|
public string[] EnumerateDataPaths(FindFileOptions options)
|
||||||
|
{
|
||||||
|
List<string> list = new List<string>();
|
||||||
|
|
||||||
|
string[] dataDirectoryNames = null;
|
||||||
|
if (AdditionalShortNames != null)
|
||||||
|
{
|
||||||
|
dataDirectoryNames = new string[AdditionalShortNames.Length + 1];
|
||||||
|
dataDirectoryNames[0] = DataDirectoryName;
|
||||||
|
for (int i = 0; i < AdditionalShortNames.Length; i++)
|
||||||
|
{
|
||||||
|
dataDirectoryNames[i + 1] = AdditionalShortNames[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dataDirectoryNames = new string[] { DataDirectoryName };
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((options & FindFileOptions.All) == FindFileOptions.All)
|
||||||
|
{
|
||||||
|
// first look in the application root directory since this will override everything else
|
||||||
|
list.Add(BasePath);
|
||||||
|
|
||||||
|
foreach (string dataDirName in dataDirectoryNames)
|
||||||
|
{
|
||||||
|
if (Environment.OSVersion.Platform == PlatformID.Unix)
|
||||||
|
{
|
||||||
|
// if we are on Unix or Mac OS X, look in /etc/...
|
||||||
|
list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[]
|
||||||
|
{
|
||||||
|
String.Empty, // *nix root directory
|
||||||
|
"etc",
|
||||||
|
dataDirName
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// then look in /usr/share/universal-editor or C:\ProgramData\Mike Becker's Software\Universal Editor
|
||||||
|
list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[]
|
||||||
|
{
|
||||||
|
System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData),
|
||||||
|
dataDirName
|
||||||
|
}));
|
||||||
|
|
||||||
|
// then look in ~/.local/share/universal-editor or C:\Users\USERNAME\AppData\Local\Mike Becker's Software\Universal Editor
|
||||||
|
list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[]
|
||||||
|
{
|
||||||
|
System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData),
|
||||||
|
dataDirName
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//fixme: addd finddfileoption.userconfig, localdata, etc.
|
||||||
|
// now for the user-writable locations...
|
||||||
|
|
||||||
|
foreach (string dataDirName in dataDirectoryNames)
|
||||||
|
{
|
||||||
|
// then look in ~/.universal-editor or C:\Users\USERNAME\AppData\Roaming\Mike Becker's Software\Universal Editor
|
||||||
|
list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[]
|
||||||
|
{
|
||||||
|
System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData),
|
||||||
|
dataDirName
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return list.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ShortName { get; set; }
|
||||||
|
public virtual string[] AdditionalShortNames => null;
|
||||||
|
|
||||||
|
protected void PrintUsageStatement(CommandLineCommand command = null)
|
||||||
|
{
|
||||||
|
string shortOptionPrefix = CommandLine.ShortOptionPrefix ?? "-";
|
||||||
|
string longOptionPrefix = CommandLine.LongOptionPrefix ?? "--";
|
||||||
|
|
||||||
|
Console.Write("usage: {0} ", ShortName);
|
||||||
|
foreach (CommandLineOption option in CommandLine.Options)
|
||||||
|
{
|
||||||
|
PrintUsageStatementOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CommandLine.HelpTextPrefix != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine(CommandLine.HelpTextPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
bool printDescriptions = true;
|
||||||
|
if (printDescriptions)
|
||||||
|
{
|
||||||
|
foreach (CommandLineOption option in CommandLine.Options)
|
||||||
|
{
|
||||||
|
Console.WriteLine(" {0}{1}", option.Abbreviation != '\0' ? String.Format("{0}{1}, {2}{3}", shortOptionPrefix, option.Abbreviation, longOptionPrefix, option.Name) : String.Format("{0}{1}", longOptionPrefix, option.Name), option.Description == null ? null : String.Format(" - {0}", option.Description));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Console.Write("[<global-options...>]");
|
||||||
|
|
||||||
|
if (command != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine(" {0}{1}", command.Name, command.Description == null ? null : String.Format(" - {0}", command.Description));
|
||||||
|
foreach (CommandLineOption option in command.Options)
|
||||||
|
{
|
||||||
|
PrintUsageStatementOption(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CommandLine.Commands.Count > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine(" <command> [<command-options...>]");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
List<CommandLineCommand> commands = new List<CommandLineCommand>(CommandLine.Commands);
|
||||||
|
commands.Sort((x, y) =>
|
||||||
|
{
|
||||||
|
return x.Name.CompareTo(y.Name);
|
||||||
|
});
|
||||||
|
foreach (CommandLineCommand command1 in commands)
|
||||||
|
{
|
||||||
|
Console.WriteLine(" {0}{1}", command1.Name, command1.Description == null ? null : String.Format(" - {0}", command1.Description));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CommandLine.HelpTextSuffix != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine(CommandLine.HelpTextSuffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintUsageStatementOption(CommandLineOption option)
|
||||||
|
{
|
||||||
|
Console.Write(" ");
|
||||||
|
if (option.Optional)
|
||||||
|
{
|
||||||
|
Console.Write('[');
|
||||||
|
}
|
||||||
|
|
||||||
|
string shortOptionPrefix = CommandLine.ShortOptionPrefix ?? "-";
|
||||||
|
string longOptionPrefix = CommandLine.LongOptionPrefix ?? "--";
|
||||||
|
|
||||||
|
if (option.Abbreviation != '\0')
|
||||||
|
{
|
||||||
|
Console.Write("{0}{1}", shortOptionPrefix, option.Abbreviation);
|
||||||
|
if (option.Type == CommandLineOptionValueType.Single)
|
||||||
|
{
|
||||||
|
Console.Write(" <value>");
|
||||||
|
}
|
||||||
|
else if (option.Type == CommandLineOptionValueType.Multiple)
|
||||||
|
{
|
||||||
|
Console.Write(" <value1>[,<value2>,...]");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.Write(" | {0}{1}", longOptionPrefix, option.Name);
|
||||||
|
if (option.Type == CommandLineOptionValueType.Single)
|
||||||
|
{
|
||||||
|
Console.Write("=<value>");
|
||||||
|
}
|
||||||
|
else if (option.Type == CommandLineOptionValueType.Multiple)
|
||||||
|
{
|
||||||
|
Console.Write("=<value1>[,<value2>,...]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.Write(longOptionPrefix ?? "--");
|
||||||
|
Console.Write("{0}", option.Name);
|
||||||
|
if (option.Type == CommandLineOptionValueType.Single)
|
||||||
|
{
|
||||||
|
Console.Write("=<value>");
|
||||||
|
}
|
||||||
|
else if (option.Type == CommandLineOptionValueType.Multiple)
|
||||||
|
{
|
||||||
|
Console.Write("=<value1>[,<value2>,...]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (option.Optional)
|
||||||
|
{
|
||||||
|
Console.Write(']');
|
||||||
|
}
|
||||||
|
// Console.WriteLine();
|
||||||
|
}
|
||||||
|
protected virtual bool ShowCommandLineHelp(out int resultCode)
|
||||||
|
{
|
||||||
|
// bash: cd returns 2 if --help is specified OR invalid option selected, 1 if file not found
|
||||||
|
PrintUsageStatement();
|
||||||
|
resultCode = 2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void _EnableDisableCommand(Command command, bool enable)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal virtual Plugin[] GetAdditionalPlugins()
|
||||||
|
{
|
||||||
|
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))
|
if (!_commandEventHandlers.ContainsKey(commandId))
|
||||||
{
|
{
|
||||||
_commandEventHandlers[commandId] = new List<CommandEventHandler>();
|
_commandEventHandlers[commandId] = new List<EventHandler<CommandEventArgs>>();
|
||||||
}
|
}
|
||||||
if (!_commandEventHandlers[commandId].Contains(handler))
|
if (!_commandEventHandlers[commandId].Contains(handler))
|
||||||
{
|
{
|
||||||
@ -62,7 +520,7 @@ public class Application
|
|||||||
{
|
{
|
||||||
if (_commandEventHandlers.ContainsKey(commandId))
|
if (_commandEventHandlers.ContainsKey(commandId))
|
||||||
{
|
{
|
||||||
foreach (CommandEventHandler handler in _commandEventHandlers[commandId])
|
foreach (EventHandler<CommandEventArgs> handler in _commandEventHandlers[commandId])
|
||||||
{
|
{
|
||||||
handler(this, new CommandEventArgs(commandId));
|
handler(this, new CommandEventArgs(commandId));
|
||||||
}
|
}
|
||||||
|
|||||||
31
framework-dotnet/src/lib/MBS.Core/CardinalDirection.cs
Executable file
31
framework-dotnet/src/lib/MBS.Core/CardinalDirection.cs
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// CardinalDirection.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Mike Becker's Software
|
||||||
|
//
|
||||||
|
// This program 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.
|
||||||
|
//
|
||||||
|
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
using System;
|
||||||
|
namespace MBS.Core
|
||||||
|
{
|
||||||
|
public enum CardinalDirection
|
||||||
|
{
|
||||||
|
Top,
|
||||||
|
Left,
|
||||||
|
Bottom,
|
||||||
|
Right
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -27,7 +27,7 @@ namespace MBS.Core.Collections
|
|||||||
{
|
{
|
||||||
public static class ExtensionMethods
|
public static class ExtensionMethods
|
||||||
{
|
{
|
||||||
public static bool ContainsAny<T>(this IEnumerable enumerable, T[] item)
|
public static bool ContainsAny<T>(this IEnumerable enumerable, IEnumerable<T> item)
|
||||||
{
|
{
|
||||||
foreach (object item1 in enumerable)
|
foreach (object item1 in enumerable)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -55,13 +55,20 @@ namespace MBS.Core.Collections.Generic
|
|||||||
return ((List<T>)(cacheOfT[obj][typeof(T)])).ToArray();
|
return ((List<T>)(cacheOfT[obj][typeof(T)])).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddRange<T>(this IList<T> list, IEnumerable<T> items)
|
public static void AddRange<T>(this ICollection<T> list, IEnumerable<T> items)
|
||||||
{
|
{
|
||||||
foreach (T item in items)
|
foreach (T item in items)
|
||||||
{
|
{
|
||||||
list.Add(item);
|
list.Add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static void AddRange<TKey, TValue>(this ICollection<KeyValuePair<TKey, TValue>> list, IEnumerable<KeyValuePair<TKey, TValue>> items)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<TKey, TValue> kvp in items)
|
||||||
|
{
|
||||||
|
list.Add(kvp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static T[] ToNullTerminatedArray<T>(this IEnumerable<T> enumerable) where T : class
|
public static T[] ToNullTerminatedArray<T>(this IEnumerable<T> enumerable) where T : class
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,31 +1,149 @@
|
|||||||
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
//
|
//
|
||||||
// This file is part of editor-dotnet.
|
// This file is part of MBS Framework for .NET Core.
|
||||||
//
|
//
|
||||||
// editor-dotnet is free software: you can redistribute it and/or modify
|
// MBS Framework for .NET Core is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// editor-dotnet is distributed in the hope that it will be useful,
|
// MBS Framework for .NET Core is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
|
// along with MBS Framework for .NET Core. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
namespace MBS.Core;
|
namespace MBS.Core;
|
||||||
|
|
||||||
public class Command
|
public class Command
|
||||||
{
|
{
|
||||||
public Command(Union<string, Guid> id, string title)
|
public class CommandCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<Command>
|
||||||
|
{
|
||||||
|
public Command this[string ID]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
foreach (Command command in this)
|
||||||
|
{
|
||||||
|
if (command.ID == ID) return command;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Command()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public Command(string id, string title, CommandItem[] items = null)
|
||||||
{
|
{
|
||||||
ID = id;
|
ID = id;
|
||||||
Title = title;
|
Title = title;
|
||||||
|
if (items != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < items.Length; i++)
|
||||||
|
{
|
||||||
|
Items.Add(items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this command displays as checked.
|
||||||
|
/// </summary>
|
||||||
|
public bool Checked { get; set; } = false;
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the command, used to reference it in <see cref="CommandReferenceCommandItem"/>.
|
||||||
|
/// </summary>
|
||||||
|
public string ID { get; set; } = String.Empty;
|
||||||
|
/// <summary>
|
||||||
|
/// The title of the command (including mnemonic prefix, if applicable).
|
||||||
|
/// </summary>
|
||||||
|
public string Title { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
private string mvarDefaultCommandID = String.Empty;
|
||||||
|
public string DefaultCommandID { get { return mvarDefaultCommandID; } set { mvarDefaultCommandID = value; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="StockType"/> that represents a predefined, platform-themed command.
|
||||||
|
/// </summary>
|
||||||
|
public StockType StockType { get; set; } = StockType.None;
|
||||||
|
|
||||||
|
private string mvarImageFileName = String.Empty;
|
||||||
|
/// <summary>
|
||||||
|
/// The file name of the image to be displayed on the command.
|
||||||
|
/// </summary>
|
||||||
|
public string ImageFileName { get { return mvarImageFileName; } set { mvarImageFileName = value; } }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The child <see cref="CommandItem"/>s that are contained within this <see cref="Command"/>.
|
||||||
|
/// </summary>
|
||||||
|
public CommandItem.CommandItemCollection Items { get; } = new CommandItem.CommandItemCollection();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The event that is fired when the command is executed.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler Executed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this <see cref="Command" /> is enabled in all <see cref="CommandBar" />s and <see cref="MenuBar" />s
|
||||||
|
/// that reference it.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
|
||||||
|
private bool _Enabled = true;
|
||||||
|
public bool Enabled { get { return _Enabled; } set { _Enabled = value; Application.Instance._EnableDisableCommand(this, value); } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this <see cref="Command" /> is visible in all <see cref="CommandBar" />s and <see cref="MenuBar" />s
|
||||||
|
/// that reference it.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
|
||||||
|
public bool Visible { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes this <see cref="Command"/>.
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("Please use Application.ExecuteCommand. Command.Execute does not always work and will be removed in a future release.")]
|
||||||
|
public void Execute()
|
||||||
|
{
|
||||||
|
if (Executed != null) Executed(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return String.Format("{0} [{1}]", ID, Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, object> _extraData = new Dictionary<string, object>();
|
||||||
|
public T GetExtraData<T>(string key, T defaultValue = default(T))
|
||||||
|
{
|
||||||
|
if (_extraData.ContainsKey(key))
|
||||||
|
{
|
||||||
|
if (_extraData[key] is T)
|
||||||
|
{
|
||||||
|
return (T)_extraData[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetExtraData<T>(string key, T value)
|
||||||
|
{
|
||||||
|
_extraData[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetExtraData(string key, object defaultValue = null)
|
||||||
|
{
|
||||||
|
if (_extraData.ContainsKey(key))
|
||||||
|
return _extraData[key];
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetExtraData(string key, object value)
|
||||||
|
{
|
||||||
|
_extraData[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Union<string, Guid> ID { get; }
|
|
||||||
public string Title { get; set; }
|
|
||||||
public IEnumerable<CommandItem> Items { get; set; }
|
|
||||||
}
|
}
|
||||||
@ -1,31 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 delegate void CommandEventHandler(object sender, CommandEventArgs e);
|
|
||||||
public class CommandEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public Union<Guid, string> CommandID { get; }
|
|
||||||
|
|
||||||
public CommandEventArgs(Union<Guid, string> commandId)
|
|
||||||
{
|
|
||||||
CommandID = commandId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
56
framework-dotnet/src/lib/MBS.Core/CommandEventArgs.cs
Normal file
56
framework-dotnet/src/lib/MBS.Core/CommandEventArgs.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of MBS Framework for .NET Core.
|
||||||
|
//
|
||||||
|
// MBS Framework for .NET Core 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.
|
||||||
|
//
|
||||||
|
// MBS Framework for .NET Core 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 MBS Framework for .NET Core. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Core;
|
||||||
|
|
||||||
|
public class CommandEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public Command? Command { get; private set; }
|
||||||
|
|
||||||
|
private Dictionary<string, object> _NamedParameters = new Dictionary<string, object>();
|
||||||
|
public T GetNamedParameter<T>(string key, T defaultValue = default(T))
|
||||||
|
{
|
||||||
|
if (_NamedParameters.ContainsKey(key))
|
||||||
|
return (T)_NamedParameters[key];
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
public object GetNamedParameter(string key, object defaultValue = null)
|
||||||
|
{
|
||||||
|
if (_NamedParameters.ContainsKey(key))
|
||||||
|
return _NamedParameters[key];
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Command = command;
|
||||||
|
if (namedParameters != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < namedParameters.Length; i++)
|
||||||
|
{
|
||||||
|
_NamedParameters[namedParameters[i].Key] = namedParameters[i].Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,25 +1,79 @@
|
|||||||
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
//
|
//
|
||||||
// This file is part of editor-dotnet.
|
// This file is part of Mocha.NET.
|
||||||
//
|
//
|
||||||
// editor-dotnet is free software: you can redistribute it and/or modify
|
// Mocha.NET is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// editor-dotnet is distributed in the hope that it will be useful,
|
// Mocha.NET is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
|
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
namespace MBS.Core;
|
namespace MBS.Core;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The base class from which all command items derive.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class CommandItem
|
public abstract class CommandItem
|
||||||
{
|
{
|
||||||
|
public string InsertAfterID { get; set; } = null;
|
||||||
|
public string InsertBeforeID { get; set; } = null;
|
||||||
|
|
||||||
|
public class CommandItemCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<CommandItem>
|
||||||
|
{
|
||||||
|
public int IndexOf(string value)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
if (this[i] is CommandReferenceCommandItem crci)
|
||||||
|
{
|
||||||
|
if (crci.CommandID.Equals(value))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class ActionCommandItem : CommandItem
|
||||||
|
{
|
||||||
|
public string ID { get; }
|
||||||
|
public string Title { get; }
|
||||||
|
|
||||||
|
public event EventHandler Executed;
|
||||||
|
|
||||||
|
public void Execute()
|
||||||
|
{
|
||||||
|
Executed?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionCommandItem(string id, string title, EventHandler execute = null)
|
||||||
|
{
|
||||||
|
ID = id;
|
||||||
|
Title = title;
|
||||||
|
if (execute != null)
|
||||||
|
{
|
||||||
|
Executed += execute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CommandPlaceholderCommandItem : CommandItem
|
||||||
|
{
|
||||||
|
private string mvarPlaceholderID = String.Empty;
|
||||||
|
public string PlaceholderID { get { return mvarPlaceholderID; } set { mvarPlaceholderID = value; } }
|
||||||
|
|
||||||
|
public CommandPlaceholderCommandItem(string placeholderID)
|
||||||
|
{
|
||||||
|
mvarPlaceholderID = placeholderID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GroupCommandItem : CommandItem
|
||||||
|
{
|
||||||
|
public CommandItemCollection Items { get; } = new CommandItemCollection();
|
||||||
}
|
}
|
||||||
115
framework-dotnet/src/lib/MBS.Core/Context.cs
Normal file
115
framework-dotnet/src/lib/MBS.Core/Context.cs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of Mocha.NET.
|
||||||
|
//
|
||||||
|
// Mocha.NET 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.
|
||||||
|
//
|
||||||
|
// Mocha.NET 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 Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Core;
|
||||||
|
|
||||||
|
public class Context
|
||||||
|
{
|
||||||
|
public class ContextCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<Context>
|
||||||
|
{
|
||||||
|
private Dictionary<Guid, Context> _ItemsByID = new Dictionary<Guid, Context>();
|
||||||
|
|
||||||
|
public bool Contains(Guid contextID)
|
||||||
|
{
|
||||||
|
return _ItemsByID.ContainsKey(contextID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Context this[Guid id]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_ItemsByID.ContainsKey(id))
|
||||||
|
return _ItemsByID[id];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ClearItems()
|
||||||
|
{
|
||||||
|
base.ClearItems();
|
||||||
|
_ItemsByID.Clear();
|
||||||
|
}
|
||||||
|
protected override void InsertItem(int index, Context item)
|
||||||
|
{
|
||||||
|
base.InsertItem(index, item);
|
||||||
|
_ItemsByID[item.ID] = item;
|
||||||
|
}
|
||||||
|
protected override void RemoveItem(int index)
|
||||||
|
{
|
||||||
|
_ItemsByID.Remove(this[index].ID);
|
||||||
|
base.RemoveItem(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid ID { get; private set; } = Guid.Empty;
|
||||||
|
public string Name { get; private set; } = String.Empty;
|
||||||
|
|
||||||
|
// public MenuBar MenuBar { get; } = new MenuBar();
|
||||||
|
public Command.CommandCollection Commands { get; } = new Command.CommandCollection();
|
||||||
|
|
||||||
|
public Context(Guid id, string name)
|
||||||
|
{
|
||||||
|
ID = id;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return String.Format("{0} {1}", Name, ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, List<EventHandler>> _CommandEventHandlers = new Dictionary<string, List<EventHandler>>();
|
||||||
|
/// <summary>
|
||||||
|
/// Attachs an event handler for the command with the ID specified by <paramref name="commandID" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><c>true</c>, if command event handler was attached, <c>false</c> otherwise.</returns>
|
||||||
|
/// <param name="commandID">The ID of the <see cref="Command" /> for which to attach an event handler.</param>
|
||||||
|
/// <param name="handler">The event handler to invoke when the <see cref="Command" /> is executed.</param>
|
||||||
|
public bool AttachCommandEventHandler(string commandID, EventHandler handler)
|
||||||
|
{
|
||||||
|
// handle command event handlers attached without a Command instance
|
||||||
|
if (!_CommandEventHandlers.ContainsKey(commandID))
|
||||||
|
{
|
||||||
|
_CommandEventHandlers.Add(commandID, new List<EventHandler>());
|
||||||
|
}
|
||||||
|
if (!_CommandEventHandlers[commandID].Contains(handler))
|
||||||
|
{
|
||||||
|
_CommandEventHandlers[commandID].Add(handler);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Executes the command (i.e., calls all attached <see cref="EventHandler" />s for the <see cref="Command" />) with
|
||||||
|
/// the given <paramref name="commandID" />, passing in the given parameters in an instance of <see cref="CommandEventArgs" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><c>true</c>, if command was executed, <c>false</c> otherwise.</returns>
|
||||||
|
/// <param name="commandID">Command identifier.</param>
|
||||||
|
/// <param name="namedParameters">Named parameters.</param>
|
||||||
|
public bool ExecuteCommand(string commandID, KeyValuePair<string, object>[] namedParameters = null)
|
||||||
|
{
|
||||||
|
if (_CommandEventHandlers.ContainsKey(commandID))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _CommandEventHandlers[commandID].Count; i++)
|
||||||
|
{
|
||||||
|
_CommandEventHandlers[commandID][i](this, new CommandEventArgs(Commands[commandID], namedParameters));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
61
framework-dotnet/src/lib/MBS.Core/Extensibility/Feature.cs
Normal file
61
framework-dotnet/src/lib/MBS.Core/Extensibility/Feature.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of MBS Framework for .NET Core.
|
||||||
|
//
|
||||||
|
// MBS Framework for .NET Core 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.
|
||||||
|
//
|
||||||
|
// MBS Framework for .NET Core 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 MBS Framework for .NET Core. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Core.Extensibility;
|
||||||
|
|
||||||
|
public class Feature
|
||||||
|
{
|
||||||
|
public class FeatureCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<Feature>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid ID { get; private set; } = Guid.Empty;
|
||||||
|
public string Title { get; private set; } = null;
|
||||||
|
|
||||||
|
public Feature(Guid id, string title)
|
||||||
|
{
|
||||||
|
ID = id;
|
||||||
|
Title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (!(this is null) && (obj is null)) return false;
|
||||||
|
if (this is null && !(obj is null)) return false;
|
||||||
|
|
||||||
|
if (obj is Feature)
|
||||||
|
{
|
||||||
|
Feature feat = (obj as Feature);
|
||||||
|
return feat.ID.Equals(ID);
|
||||||
|
}
|
||||||
|
return base.Equals(obj);
|
||||||
|
}
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return base.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Feature left, Feature right)
|
||||||
|
{
|
||||||
|
return (left.ID == right.ID);
|
||||||
|
}
|
||||||
|
public static bool operator !=(Feature left, Feature right)
|
||||||
|
{
|
||||||
|
return (left.ID != right.ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
181
framework-dotnet/src/lib/MBS.Core/Extensibility/Plugin.cs
Normal file
181
framework-dotnet/src/lib/MBS.Core/Extensibility/Plugin.cs
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of MBS Framework for .NET Core.
|
||||||
|
//
|
||||||
|
// MBS Framework for .NET Core 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.
|
||||||
|
//
|
||||||
|
// MBS Framework for .NET Core 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 MBS Framework for .NET Core. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Core.Extensibility;
|
||||||
|
|
||||||
|
public class Plugin
|
||||||
|
{
|
||||||
|
public Context Context { get; protected set; }
|
||||||
|
public virtual string Title { get; set; } = null;
|
||||||
|
public Feature.FeatureCollection ProvidedFeatures { get; } = new Feature.FeatureCollection();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="PropertyBag" /> containing the plugin-specific
|
||||||
|
/// settings for this <see cref="Plugin" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The settings.</value>
|
||||||
|
public PropertyBag Settings { get; }
|
||||||
|
|
||||||
|
public Plugin()
|
||||||
|
{
|
||||||
|
Settings = new PluginPropertyBag(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Initialized { get; private set; } = false;
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
if (Initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
InitializeInternal();
|
||||||
|
|
||||||
|
Settings.Initialize();
|
||||||
|
Initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid ID { get; set; } = Guid.Empty;
|
||||||
|
|
||||||
|
protected virtual void InitializeInternal()
|
||||||
|
{
|
||||||
|
// this method intentionally left blank
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual bool AutoRegister => true;
|
||||||
|
|
||||||
|
protected virtual bool IsSupportedInternal()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool IsSupported()
|
||||||
|
{
|
||||||
|
return IsSupportedInternal();
|
||||||
|
}
|
||||||
|
private static Plugin[] _plugins = null;
|
||||||
|
public static TPlugin[] Get<TPlugin>(bool resetCache = false) where TPlugin : Plugin
|
||||||
|
{
|
||||||
|
Plugin[] plugins = Get(resetCache);
|
||||||
|
return plugins.OfType<TPlugin>().ToArray();
|
||||||
|
}
|
||||||
|
public static Plugin[] Get(bool resetCache = false)
|
||||||
|
{
|
||||||
|
if (resetCache)
|
||||||
|
{
|
||||||
|
_plugins = null; // should not be cached? // actually, yes it should...
|
||||||
|
|
||||||
|
// 2020-12-12 20:54 by beckermj
|
||||||
|
// ACTUALLY, it depends on whether the configuration needs to be persisted across calls to Get()
|
||||||
|
// [it does] and whether the list of plugins needs to be reloaded when CustomPlugins is modified
|
||||||
|
// [it shouldn't, but it does] .
|
||||||
|
//
|
||||||
|
// The safest way we can handle this RIGHT NOW is to prevent any plugin from being loaded until after CustomPlugins
|
||||||
|
// is initialized by UIApplication.
|
||||||
|
//
|
||||||
|
// We call Plugins.Get(new Feature[] { KnownFeatures.UWTPlatform }) to retrieve the available User Interface plugins
|
||||||
|
// that supply the UWT Platform implementation (e.g. GTK, Windows Forms, etc.) - and this causes CustomPlugins to not
|
||||||
|
// load properly since it loads AFTER this initial call to Plugins.Get().
|
||||||
|
//
|
||||||
|
// So I add ed a resetCache parameter that when specified TRUE will clear the cache and then return the appropriate
|
||||||
|
// plugin. This way we can continue caching future calls to Get() without missing out on CustomPlugins.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_plugins == null)
|
||||||
|
{
|
||||||
|
Type[] types = Reflection.TypeLoader.GetAvailableTypes(new Type[] { typeof(Plugin) });
|
||||||
|
System.Collections.Generic.List<Plugin> plugins = new System.Collections.Generic.List<Plugin>();
|
||||||
|
for (int i = 0; i < types.Length; i++)
|
||||||
|
{
|
||||||
|
if (types[i].IsAbstract)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if (types[i].IsSubclassOf(typeof(ICustomPlugin)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Plugin plg = (Plugin)types[i].Assembly.CreateInstance(types[i].FullName);
|
||||||
|
plugins.Add(plg);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Application.Instance != null)
|
||||||
|
{
|
||||||
|
Plugin[] plugins2 = Application.Instance.GetAdditionalPlugins();
|
||||||
|
for (int i = 0; i < plugins2.Length; i++)
|
||||||
|
{
|
||||||
|
plugins.Add(plugins2[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_plugins = plugins.ToArray();
|
||||||
|
|
||||||
|
if (resetCache)
|
||||||
|
{
|
||||||
|
_plugins = null;
|
||||||
|
return plugins.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _plugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TPlugin[] Get<TPlugin>(Feature[] providedFeatures, bool resetCache = false) where TPlugin : Plugin
|
||||||
|
{
|
||||||
|
Plugin[] plugins = Get(providedFeatures, resetCache);
|
||||||
|
return plugins.OfType<TPlugin>().ToArray();
|
||||||
|
}
|
||||||
|
public static Plugin[] Get(Feature[] providedFeatures, bool resetCache = false)
|
||||||
|
{
|
||||||
|
System.Collections.Generic.List<Plugin> list = new System.Collections.Generic.List<Plugin>();
|
||||||
|
Plugin[] plugins = Get(resetCache);
|
||||||
|
for (int i = 0; i < plugins.Length; i++)
|
||||||
|
{
|
||||||
|
if (!plugins[i].AutoRegister)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!plugins[i].IsSupported())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int j = 0; j < providedFeatures.Length; j++)
|
||||||
|
{
|
||||||
|
if (plugins[i].ProvidedFeatures.Contains(providedFeatures[j]))
|
||||||
|
list.Add(plugins[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TPlugin Get<TPlugin>(Guid id) where TPlugin : Plugin
|
||||||
|
{
|
||||||
|
Plugin plugin = Get(id);
|
||||||
|
return (TPlugin)plugin;
|
||||||
|
}
|
||||||
|
public static Plugin Get(Guid id)
|
||||||
|
{
|
||||||
|
Plugin[] plugins = Get();
|
||||||
|
for (int i = 0; i < plugins.Length; i++)
|
||||||
|
{
|
||||||
|
if (plugins[i].ID == id)
|
||||||
|
return plugins[i];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of MBS Framework for .NET Core.
|
||||||
|
//
|
||||||
|
// MBS Framework for .NET Core 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.
|
||||||
|
//
|
||||||
|
// MBS Framework for .NET Core 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 MBS Framework for .NET Core. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Core.Extensibility;
|
||||||
|
|
||||||
|
|
||||||
|
public class PluginPropertyBag : PropertyBag
|
||||||
|
{
|
||||||
|
private Plugin Plugin { get; }
|
||||||
|
|
||||||
|
protected override void OnInitialized(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnInitialized(e);
|
||||||
|
|
||||||
|
string[] paths = Application.Instance.EnumerateDataPaths();
|
||||||
|
foreach (string datapath in paths)
|
||||||
|
{
|
||||||
|
string path = String.Format("{0}/plugins/{1}/config.xml", datapath, this.Plugin.ID.ToString("b"));
|
||||||
|
if (System.IO.File.Exists(path))
|
||||||
|
{
|
||||||
|
Console.WriteLine("found config in {0}", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal PluginPropertyBag(Plugin plugin)
|
||||||
|
{
|
||||||
|
Plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPropertyValueRequested<T>(PropertyValueRequestedEventArgs<T> e)
|
||||||
|
{
|
||||||
|
base.OnPropertyValueRequested(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
187
framework-dotnet/src/lib/MBS.Core/Extensibility/PropertyBag.cs
Normal file
187
framework-dotnet/src/lib/MBS.Core/Extensibility/PropertyBag.cs
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of MBS Framework for .NET Core.
|
||||||
|
//
|
||||||
|
// MBS Framework for .NET Core 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.
|
||||||
|
//
|
||||||
|
// MBS Framework for .NET Core 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 MBS Framework for .NET Core. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Core.Extensibility;
|
||||||
|
|
||||||
|
public class PropertyValueRequestedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public Guid ID { get; }
|
||||||
|
public object Value { get; set; }
|
||||||
|
|
||||||
|
public bool Cache { get; set; } = true;
|
||||||
|
public bool Handled { get; set; } = false;
|
||||||
|
|
||||||
|
public PropertyValueRequestedEventArgs(Guid id, object value)
|
||||||
|
{
|
||||||
|
ID = id;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class PropertyValueRequestedEventArgs<T> : PropertyValueRequestedEventArgs
|
||||||
|
{
|
||||||
|
public new T Value { get { return (T)base.Value; } set { base.Value = value; } }
|
||||||
|
|
||||||
|
public PropertyValueRequestedEventArgs(Guid id, T value) : base(id, value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PropertyValueChangingEventArgs : System.ComponentModel.CancelEventArgs
|
||||||
|
{
|
||||||
|
public Guid ID { get; }
|
||||||
|
public object OldValue { get; }
|
||||||
|
public object NewValue { get; set; }
|
||||||
|
|
||||||
|
public PropertyValueChangingEventArgs(Guid id, object oldValue, object newValue)
|
||||||
|
{
|
||||||
|
ID = id;
|
||||||
|
OldValue = oldValue;
|
||||||
|
NewValue = newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class PropertyValueChangedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public Guid ID { get; }
|
||||||
|
public object OldValue { get; }
|
||||||
|
public object NewValue { get; }
|
||||||
|
|
||||||
|
public PropertyValueChangedEventArgs(Guid id, object oldValue, object newValue)
|
||||||
|
{
|
||||||
|
ID = id;
|
||||||
|
OldValue = oldValue;
|
||||||
|
NewValue = newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PropertyBag
|
||||||
|
{
|
||||||
|
private Dictionary<Guid, object> _settings = new Dictionary<Guid, object>();
|
||||||
|
private Dictionary<Guid, string> _names = new Dictionary<Guid, string>();
|
||||||
|
public string GetName(Guid id)
|
||||||
|
{
|
||||||
|
if (_names.ContainsKey(id))
|
||||||
|
return _names[id];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public void SetName(Guid id, string name)
|
||||||
|
{
|
||||||
|
_names[id] = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<Guid, object> _PropertyValues = new Dictionary<Guid, object>();
|
||||||
|
public bool Contains(Guid id)
|
||||||
|
{
|
||||||
|
return _PropertyValues.ContainsKey(id);
|
||||||
|
}
|
||||||
|
public bool SetValue<T>(Guid id, T value)
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
lock (_PropertyValues)
|
||||||
|
{
|
||||||
|
object oldValue = null;
|
||||||
|
if (!_PropertyValues.ContainsKey(id) || (!(
|
||||||
|
(_PropertyValues[id] == null && (value as object) == null) ||
|
||||||
|
(_PropertyValues[id] != null && _PropertyValues[id].Equals(value)))))
|
||||||
|
{
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (_PropertyValues.ContainsKey(id))
|
||||||
|
{
|
||||||
|
oldValue = _PropertyValues[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
PropertyValueChangingEventArgs e = new PropertyValueChangingEventArgs(id, oldValue, value);
|
||||||
|
OnPropertyValueChanging(e);
|
||||||
|
if (e.Cancel)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_PropertyValues[id] = value;
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
OnPropertyValueChanged(new PropertyValueChangedEventArgs(id, oldValue, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<PropertyValueChangingEventArgs> PropertyValueChanging;
|
||||||
|
protected virtual void OnPropertyValueChanging(PropertyValueChangingEventArgs e)
|
||||||
|
{
|
||||||
|
PropertyValueChanging?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
public event EventHandler<PropertyValueChangedEventArgs> PropertyValueChanged;
|
||||||
|
protected virtual void OnPropertyValueChanged(PropertyValueChangedEventArgs e)
|
||||||
|
{
|
||||||
|
PropertyValueChanged?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T GetValue<T>(Guid id, T defaultValue = default(T))
|
||||||
|
{
|
||||||
|
lock (_PropertyValues)
|
||||||
|
{
|
||||||
|
if (_PropertyValues.ContainsKey(id))
|
||||||
|
{
|
||||||
|
if (_PropertyValues[id] is T val)
|
||||||
|
{
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PropertyValueRequestedEventArgs<T> e = new PropertyValueRequestedEventArgs<T>(id, defaultValue);
|
||||||
|
OnPropertyValueRequested(e);
|
||||||
|
if (e.Handled)
|
||||||
|
{
|
||||||
|
if (e.Cache)
|
||||||
|
{
|
||||||
|
_PropertyValues[id] = e.Value;
|
||||||
|
}
|
||||||
|
return e.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<PropertyValueRequestedEventArgs> PropertyValueRequested;
|
||||||
|
protected virtual void OnPropertyValueRequested<T>(PropertyValueRequestedEventArgs<T> e)
|
||||||
|
{
|
||||||
|
PropertyValueRequested?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<KeyValuePair<Guid, object>> GetAll()
|
||||||
|
{
|
||||||
|
return _PropertyValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Initialized { get; private set; } = false;
|
||||||
|
protected virtual void OnInitialized(EventArgs e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
if (Initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
OnInitialized(EventArgs.Empty);
|
||||||
|
Initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
45
framework-dotnet/src/lib/MBS.Core/FindFileOptions.cs
Normal file
45
framework-dotnet/src/lib/MBS.Core/FindFileOptions.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// FindFileOptions.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2022 Mike Becker's Software
|
||||||
|
//
|
||||||
|
// This program 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.
|
||||||
|
//
|
||||||
|
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
using System;
|
||||||
|
namespace MBS.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controls the behavior of relative file resolution.
|
||||||
|
/// </summary>
|
||||||
|
[Flags()]
|
||||||
|
public enum FindFileOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns all matching fully-qualified file paths across all global,
|
||||||
|
/// application, and user directories.
|
||||||
|
/// </summary>
|
||||||
|
All = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// Returns only file paths that are writable by the user (i.e., in the
|
||||||
|
/// user's local or roaming data directory).
|
||||||
|
/// </summary>
|
||||||
|
UserWritable = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// Allows the user to create a file if it does not exist (i.e., returns
|
||||||
|
/// a file name even if it does not exist)
|
||||||
|
/// </summary>
|
||||||
|
Create = 4
|
||||||
|
}
|
||||||
35
framework-dotnet/src/lib/MBS.Core/IO/DirectoryExtensions.cs
Normal file
35
framework-dotnet/src/lib/MBS.Core/IO/DirectoryExtensions.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of Mocha.NET.
|
||||||
|
//
|
||||||
|
// Mocha.NET 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.
|
||||||
|
//
|
||||||
|
// Mocha.NET 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 Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Core.IO;
|
||||||
|
|
||||||
|
public static class DirectoryExtensions
|
||||||
|
{
|
||||||
|
public static string[] GetFiles(string path, string[] searchPatterns, SearchOption options)
|
||||||
|
{
|
||||||
|
string[] result = new string[0];
|
||||||
|
int j = 0;
|
||||||
|
foreach (string ext in searchPatterns)
|
||||||
|
{
|
||||||
|
string[] filenames = Directory.GetFiles(path, ext, options);
|
||||||
|
Array.Resize<string>(ref result, result.Length + filenames.Length);
|
||||||
|
Array.Copy(filenames, 0, result, j, filenames.Length);
|
||||||
|
j += filenames.Length;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -164,6 +164,11 @@ namespace MBS.Core
|
|||||||
public const string DefaultAlphabet = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
public const string DefaultAlphabet = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
public const string DefaultAlphabetNoSpecialChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
public const string DefaultAlphabetNoSpecialChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
public const string CapitalAlphabetNoSpecialChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
public const string CapitalAlphanumeric = "_-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
public const string CapitalAlphanumericNoSpecialChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
private static readonly CryptoRandom Random = new CryptoRandom();
|
private static readonly CryptoRandom Random = new CryptoRandom();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
|||||||
@ -0,0 +1,48 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace MBS.Core.Reflection;
|
||||||
|
|
||||||
|
public static class TypeExtensions
|
||||||
|
{
|
||||||
|
public static bool IsSubclassOfGeneric(this Type toCheck, Type generic)
|
||||||
|
{
|
||||||
|
// thanks https://stackoverflow.com/a/457708
|
||||||
|
|
||||||
|
while (toCheck != null && toCheck != typeof(object))
|
||||||
|
{
|
||||||
|
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
|
||||||
|
if (generic == cur)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type[] intfs = toCheck.GetInterfaces();
|
||||||
|
foreach (Type intf in intfs)
|
||||||
|
{
|
||||||
|
// !!! HACK HACK HACK !!!
|
||||||
|
bool hack = intf.Namespace.Equals(generic.Namespace) && intf.Name.Equals(generic.Name);
|
||||||
|
if (hack)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toCheck = toCheck.BaseType;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyInfo? GetProperty(this MethodBase methodBase)
|
||||||
|
{
|
||||||
|
Type declType = methodBase.DeclaringType;
|
||||||
|
foreach (PropertyInfo pi in declType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||||
|
{
|
||||||
|
if (pi.GetMethod == methodBase
|
||||||
|
|| pi.SetMethod == methodBase)
|
||||||
|
{
|
||||||
|
return pi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -129,12 +129,12 @@ public class TypeLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Type[] mvarAvailableTypes = null;
|
private static Type[] mvarAvailableTypes = null;
|
||||||
public static T[] GetAvailableTypes<T>(Assembly[] additionalAssemblies = null) where T : class
|
public static T[] GetAvailableTypes<T>(Assembly[] additionalAssemblies = null, bool resetCache = false) where T : class
|
||||||
{
|
{
|
||||||
Type[] ts = null;
|
Type[] ts = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ts = GetAvailableTypes(new Type[] { typeof(T) }, additionalAssemblies);
|
ts = GetAvailableTypes(new Type[] { typeof(T) }, additionalAssemblies, resetCache);
|
||||||
}
|
}
|
||||||
catch (ReflectionTypeLoadException ex)
|
catch (ReflectionTypeLoadException ex)
|
||||||
{
|
{
|
||||||
@ -156,8 +156,12 @@ public class TypeLoader
|
|||||||
}
|
}
|
||||||
return list.ToArray();
|
return list.ToArray();
|
||||||
}
|
}
|
||||||
public static Type[] GetAvailableTypes(Type[] inheritsFrom = null, Assembly[] additionalAssemblies = null)
|
public static Type[] GetAvailableTypes(Type[] inheritsFrom = null, Assembly[] additionalAssemblies = null, bool resetCache = false)
|
||||||
{
|
{
|
||||||
|
if (resetCache)
|
||||||
|
{
|
||||||
|
mvarAvailableTypes = null;
|
||||||
|
}
|
||||||
if (mvarAvailableTypes == null)
|
if (mvarAvailableTypes == null)
|
||||||
{
|
{
|
||||||
List<Type> types = new List<Type>();
|
List<Type> types = new List<Type>();
|
||||||
@ -197,16 +201,30 @@ public class TypeLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mvarAvailableTypes = types.ToArray();
|
mvarAvailableTypes = types.ToArray();
|
||||||
|
/*
|
||||||
|
foreach (Type t in mvarAvailableTypes)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Type load: {0}", t.FullName);
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inheritsFrom != null)
|
if (inheritsFrom != null)
|
||||||
{
|
{
|
||||||
List<Type> retval = new List<Type>();
|
List<Type> retval = new List<Type>();
|
||||||
for (int iTyp = 0; iTyp < mvarAvailableTypes.Length; iTyp++)
|
foreach (Type t in mvarAvailableTypes)
|
||||||
{
|
{
|
||||||
for (int jInh = 0; jInh < inheritsFrom.Length; jInh++)
|
string typeFullName = t.FullName;
|
||||||
|
foreach (Type inheritsFromType in inheritsFrom)
|
||||||
{
|
{
|
||||||
if (mvarAvailableTypes[iTyp].IsSubclassOf(inheritsFrom[jInh])) retval.Add(mvarAvailableTypes[iTyp]);
|
if (t.FullName.Contains("Mini."))
|
||||||
|
{
|
||||||
|
// Console.WriteLine(inheritsFromType.FullName + " ? inherits ? " + t.FullName);
|
||||||
|
}
|
||||||
|
if (t.IsSubclassOf(inheritsFromType))
|
||||||
|
{
|
||||||
|
retval.Add(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return retval.ToArray();
|
return retval.ToArray();
|
||||||
|
|||||||
137
framework-dotnet/src/lib/MBS.Core/StockType.cs
Normal file
137
framework-dotnet/src/lib/MBS.Core/StockType.cs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of MBS Framework for .NET Core.
|
||||||
|
//
|
||||||
|
// MBS Framework for .NET Core 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.
|
||||||
|
//
|
||||||
|
// MBS Framework for .NET Core 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 MBS Framework for .NET Core. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Core;
|
||||||
|
|
||||||
|
public enum StockType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
About,
|
||||||
|
Add,
|
||||||
|
Apply,
|
||||||
|
|
||||||
|
// these four do not have gtk-stock equivalents
|
||||||
|
ArrowDown,
|
||||||
|
ArrowLeft,
|
||||||
|
ArrowRight,
|
||||||
|
ArrowUp,
|
||||||
|
|
||||||
|
Bold,
|
||||||
|
Bookmarks,
|
||||||
|
Cancel,
|
||||||
|
CapsLockWarning, // not for buttons
|
||||||
|
CDROM,
|
||||||
|
Clear,
|
||||||
|
Close,
|
||||||
|
ColorPicker, // not for buttons
|
||||||
|
Connect,
|
||||||
|
Convert,
|
||||||
|
Copy,
|
||||||
|
Cut,
|
||||||
|
Delete,
|
||||||
|
DialogAuthentication, // not for buttons
|
||||||
|
DialogInfo,
|
||||||
|
DialogWarning,
|
||||||
|
DialogError,
|
||||||
|
DialogQuestion,
|
||||||
|
Directory, // not for buttons
|
||||||
|
Discard,
|
||||||
|
Disconnect,
|
||||||
|
DragAndDrop, // not for buttons
|
||||||
|
DragAndDropMultiple, // not for buttons
|
||||||
|
Edit,
|
||||||
|
Execute,
|
||||||
|
File,
|
||||||
|
Find,
|
||||||
|
FindAndReplace,
|
||||||
|
Floppy,
|
||||||
|
Folder,
|
||||||
|
Fullscreen,
|
||||||
|
GotoBottom,
|
||||||
|
GotoFirst,
|
||||||
|
GotoLast,
|
||||||
|
GotoTop,
|
||||||
|
GoBack,
|
||||||
|
GoDown,
|
||||||
|
GoForward,
|
||||||
|
GoUp,
|
||||||
|
HardDisk,
|
||||||
|
Help,
|
||||||
|
Home,
|
||||||
|
Index,
|
||||||
|
Indent,
|
||||||
|
Info,
|
||||||
|
Italic,
|
||||||
|
JumpTo,
|
||||||
|
JustifyCenter,
|
||||||
|
JustifyFill,
|
||||||
|
JustifyLeft,
|
||||||
|
JustifyRight,
|
||||||
|
LeaveFullscreen,
|
||||||
|
MissingImage, // not for buttons
|
||||||
|
MediaForward,
|
||||||
|
MediaNext,
|
||||||
|
MediaPause,
|
||||||
|
MediaPlay,
|
||||||
|
MediaPrevious,
|
||||||
|
MediaRecord,
|
||||||
|
MediaRewind,
|
||||||
|
MediaStop,
|
||||||
|
Network,
|
||||||
|
New,
|
||||||
|
No,
|
||||||
|
OK,
|
||||||
|
Open,
|
||||||
|
OrientationPortrait,
|
||||||
|
OrientationLandscape,
|
||||||
|
OrientationReverseLandscape,
|
||||||
|
OrientationReversePortrait,
|
||||||
|
PageSetup,
|
||||||
|
Paste,
|
||||||
|
Preferences,
|
||||||
|
Print,
|
||||||
|
PrintError, // not for buttons
|
||||||
|
PrintPaused, // not for buttons
|
||||||
|
PrintPreview,
|
||||||
|
PrintReport, // not for buttons
|
||||||
|
PrintWarning, // not for buttons
|
||||||
|
Properties,
|
||||||
|
Quit,
|
||||||
|
Redo,
|
||||||
|
Refresh,
|
||||||
|
Remove,
|
||||||
|
RevertToSaved,
|
||||||
|
Save,
|
||||||
|
SaveAs,
|
||||||
|
SelectAll,
|
||||||
|
SelectColor,
|
||||||
|
SelectFont,
|
||||||
|
SortAscending,
|
||||||
|
SortDescending,
|
||||||
|
SpellCheck,
|
||||||
|
Stop,
|
||||||
|
Strikethrough,
|
||||||
|
Undelete,
|
||||||
|
Underline,
|
||||||
|
Undo,
|
||||||
|
Unindent,
|
||||||
|
Yes,
|
||||||
|
Zoom100,
|
||||||
|
ZoomFit,
|
||||||
|
ZoomIn,
|
||||||
|
ZoomOut
|
||||||
|
}
|
||||||
@ -19,6 +19,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
|
||||||
namespace MBS.Core;
|
namespace MBS.Core;
|
||||||
|
|
||||||
public static class StreamExtensions
|
public static class StreamExtensions
|
||||||
@ -96,4 +98,33 @@ public static class StreamExtensions
|
|||||||
}
|
}
|
||||||
_streamPositions[st].Push(st.Position);
|
_streamPositions[st].Push(st.Position);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private const long BUFFER_SIZE=4096;
|
||||||
|
public static byte[] ReadToEnd(this Stream st)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[BUFFER_SIZE];
|
||||||
|
byte[] output = new byte[0];
|
||||||
|
int i = 0;
|
||||||
|
bool done = false;
|
||||||
|
while (!done)
|
||||||
|
{
|
||||||
|
int length = st.Read(buffer, 0, buffer.Length);
|
||||||
|
if (length == 0)
|
||||||
|
{
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length < BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
Array.Resize<byte>(ref buffer, length);
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.Resize<byte>(ref output, output.Length + buffer.Length);
|
||||||
|
Array.Copy(buffer, 0, output, i, buffer.Length);
|
||||||
|
i += buffer.Length;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user