Allow external tools to have any namespace / class name if annotated
This change is more convenient at the cost of a little duplicate code in ToolManager. The annotation is [ExternalToolEntryPointForm], and having no more than one such class per assembly is enforced.
This commit is contained in:
parent
eab44d2d94
commit
1fdb7a6fe2
|
@ -102,13 +102,15 @@ namespace BizHawk.Client.ApiHawk
|
|||
}
|
||||
}
|
||||
|
||||
var customFormType = externalToolFile.GetTypes().FirstOrDefault(t => t != null && t.FullName == "BizHawk.Client.EmuHawk.CustomMainForm");
|
||||
var availTypes = externalToolFile.GetTypes();
|
||||
var customFormType = availTypes.FirstOrDefault(t => t.FullName == "BizHawk.Client.EmuHawk.CustomMainForm")
|
||||
?? availTypes.SingleOrDefault(t => typeof(IExternalToolForm).IsAssignableFrom(t) && t.CustomAttributes.Any(cad => cad.AttributeType == typeof(ExternalToolEntryPointFormAttribute)));
|
||||
if (customFormType == null)
|
||||
{
|
||||
item.ToolTipText = "Does not have a CustomMainForm";
|
||||
item.ToolTipText = "Does not have a correctly-formatted CustomMainForm or a form decorated with [ExternalToolEntryPointForm]";
|
||||
item.Enabled = false;
|
||||
}
|
||||
item.Tag = fileName;
|
||||
item.Tag = (fileName, customFormType?.FullName);
|
||||
|
||||
attributes = externalToolFile.GetCustomAttributes(typeof(BizHawkExternalToolUsageAttribute), false);
|
||||
if (attributes != null && attributes.Length == 1)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ExternalToolEntryPointFormAttribute : Attribute {}
|
||||
}
|
|
@ -1415,7 +1415,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
item.Click += delegate
|
||||
{
|
||||
Tools.Load<IExternalToolForm>((string)item.Tag);
|
||||
var (fileName, customFormTypeName) = ((string, string)) item.Tag;
|
||||
Tools.LoadExternalToolForm(fileName, customFormTypeName);
|
||||
};
|
||||
}
|
||||
else
|
||||
|
|
|
@ -94,84 +94,49 @@ namespace BizHawk.Client.EmuHawk
|
|||
public T Load<T>(string toolPath, bool focus = true)
|
||||
where T : class, IToolForm
|
||||
{
|
||||
bool isExternal = typeof(T) == typeof(IExternalToolForm);
|
||||
|
||||
if (!IsAvailable<T>() && !isExternal)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
T existingTool;
|
||||
if (isExternal)
|
||||
{
|
||||
existingTool = (T)_tools.FirstOrDefault(t => t is T && t.GetType().Assembly.Location == toolPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
existingTool = (T)_tools.FirstOrDefault(t => t is T);
|
||||
}
|
||||
if (!IsAvailable<T>()) return null;
|
||||
|
||||
var existingTool = _tools.OfType<T>().FirstOrDefault();
|
||||
if (existingTool != null)
|
||||
{
|
||||
if (existingTool.IsDisposed)
|
||||
{
|
||||
_tools.Remove(existingTool);
|
||||
}
|
||||
else
|
||||
if (!existingTool.IsDisposed)
|
||||
{
|
||||
if (focus)
|
||||
{
|
||||
existingTool.Show();
|
||||
existingTool.Focus();
|
||||
}
|
||||
|
||||
return existingTool;
|
||||
}
|
||||
_tools.Remove(existingTool);
|
||||
}
|
||||
|
||||
IToolForm newTool = CreateInstance<T>(toolPath);
|
||||
|
||||
if (newTool == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (newTool is Form form)
|
||||
{
|
||||
form.Owner = _owner;
|
||||
}
|
||||
|
||||
if (isExternal)
|
||||
{
|
||||
ApiInjector.UpdateApis(_apiProvider, newTool);
|
||||
}
|
||||
var newTool = CreateInstance<T>(toolPath);
|
||||
if (newTool == null) return null;
|
||||
|
||||
if (newTool is Form form) form.Owner = _owner;
|
||||
ServiceInjector.UpdateServices(_emulator.ServiceProvider, newTool);
|
||||
SetBaseProperties(newTool);
|
||||
string toolType = typeof(T).ToString();
|
||||
|
||||
var toolTypeName = typeof(T).ToString();
|
||||
// auto settings
|
||||
if (newTool is IToolFormAutoConfig tool)
|
||||
if (newTool is IToolFormAutoConfig autoConfigTool)
|
||||
{
|
||||
if (!_config.CommonToolSettings.TryGetValue(toolType, out var settings))
|
||||
{
|
||||
settings = new ToolDialogSettings();
|
||||
_config.CommonToolSettings[toolType] = settings;
|
||||
}
|
||||
|
||||
AttachSettingHooks(tool, settings);
|
||||
AttachSettingHooks(
|
||||
autoConfigTool,
|
||||
_config.CommonToolSettings.TryGetValue(toolTypeName, out var settings)
|
||||
? settings
|
||||
: (_config.CommonToolSettings[toolTypeName] = new ToolDialogSettings())
|
||||
);
|
||||
}
|
||||
|
||||
// custom settings
|
||||
if (HasCustomConfig(newTool))
|
||||
{
|
||||
if (!_config.CustomToolSettings.TryGetValue(toolType, out var settings))
|
||||
{
|
||||
settings = new Dictionary<string, object>();
|
||||
_config.CustomToolSettings[toolType] = settings;
|
||||
}
|
||||
|
||||
InstallCustomConfig(newTool, settings);
|
||||
InstallCustomConfig(
|
||||
newTool,
|
||||
_config.CustomToolSettings.TryGetValue(toolTypeName, out var settings)
|
||||
? settings
|
||||
: (_config.CustomToolSettings[toolTypeName] = new Dictionary<string, object>())
|
||||
);
|
||||
}
|
||||
|
||||
newTool.Restart();
|
||||
|
@ -186,6 +151,56 @@ namespace BizHawk.Client.EmuHawk
|
|||
return (T)newTool;
|
||||
}
|
||||
|
||||
/// <summary>Loads the external tool's entry form.</summary>
|
||||
public IExternalToolForm LoadExternalToolForm(string toolPath, string customFormTypeName, bool focus = true)
|
||||
{
|
||||
var existingTool = _tools.OfType<IExternalToolForm>().FirstOrDefault(t => t.GetType().Assembly.Location == toolPath);
|
||||
if (existingTool != null)
|
||||
{
|
||||
if (!existingTool.IsDisposed)
|
||||
{
|
||||
if (focus)
|
||||
{
|
||||
existingTool.Show();
|
||||
existingTool.Focus();
|
||||
}
|
||||
return existingTool;
|
||||
}
|
||||
_tools.Remove(existingTool);
|
||||
}
|
||||
|
||||
var newTool = (IExternalToolForm) CreateInstance(typeof(IExternalToolForm), toolPath, customFormTypeName);
|
||||
if (newTool == null) return null;
|
||||
if (newTool is Form form) form.Owner = _owner;
|
||||
ApiInjector.UpdateApis(_apiProvider, newTool);
|
||||
ServiceInjector.UpdateServices(_emulator.ServiceProvider, newTool);
|
||||
SetBaseProperties(newTool);
|
||||
// auto settings
|
||||
if (newTool is IToolFormAutoConfig autoConfigTool)
|
||||
{
|
||||
AttachSettingHooks(
|
||||
autoConfigTool,
|
||||
_config.CommonToolSettings.TryGetValue(customFormTypeName, out var settings)
|
||||
? settings
|
||||
: (_config.CommonToolSettings[customFormTypeName] = new ToolDialogSettings())
|
||||
);
|
||||
}
|
||||
// custom settings
|
||||
if (HasCustomConfig(newTool))
|
||||
{
|
||||
InstallCustomConfig(
|
||||
newTool,
|
||||
_config.CustomToolSettings.TryGetValue(customFormTypeName, out var settings)
|
||||
? settings
|
||||
: (_config.CustomToolSettings[customFormTypeName] = new Dictionary<string, object>())
|
||||
);
|
||||
}
|
||||
|
||||
newTool.Restart();
|
||||
newTool.Show();
|
||||
return newTool;
|
||||
}
|
||||
|
||||
public void AutoLoad()
|
||||
{
|
||||
var genericSettings = _config.CommonToolSettings
|
||||
|
@ -629,8 +644,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
/// </summary>
|
||||
/// <param name="toolType">Type of tool you want to create</param>
|
||||
/// <param name="dllPath">Path dll for an external tool</param>
|
||||
/// <param name="toolTypeName">For external tools, <see cref="Type.FullName"/> of the entry form's type (<paramref name="toolType"/> will be <see cref="IExternalToolForm"/>)</param>
|
||||
/// <returns>New instance of an IToolForm</returns>
|
||||
private IToolForm CreateInstance(Type toolType, string dllPath)
|
||||
private IToolForm CreateInstance(Type toolType, string dllPath, string toolTypeName = null)
|
||||
{
|
||||
IToolForm tool;
|
||||
|
||||
|
@ -645,7 +661,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
try
|
||||
{
|
||||
tool = Activator.CreateInstanceFrom(dllPath, "BizHawk.Client.EmuHawk.CustomMainForm").Unwrap() as IExternalToolForm;
|
||||
tool = Activator.CreateInstanceFrom(dllPath, toolTypeName ?? "BizHawk.Client.EmuHawk.CustomMainForm").Unwrap() as IExternalToolForm;
|
||||
if (tool == null)
|
||||
{
|
||||
MessageBox.Show($"It seems that the object CustomMainForm does not implement {nameof(IExternalToolForm)}. Please review the code.", "No, no, no. Wrong Way !", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
|
|
Loading…
Reference in New Issue