mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-29 23:40:27 +00:00
Minor tweaks
Translation util only for debug build (unused in release) Simplify some plugin load expressions
This commit is contained in:
parent
76afe91bbb
commit
ae74ee7931
4 changed files with 127 additions and 121 deletions
|
@ -1,101 +1,104 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using static PKHeX.WinForms.PluginLoadSetting;
|
||||||
|
|
||||||
namespace PKHeX.WinForms
|
namespace PKHeX.WinForms;
|
||||||
|
|
||||||
|
public static class PluginLoader
|
||||||
{
|
{
|
||||||
public static class PluginLoader
|
public static IEnumerable<T> LoadPlugins<T>(string pluginPath, PluginLoadSetting loadSetting) where T : class
|
||||||
{
|
{
|
||||||
public static IEnumerable<T> LoadPlugins<T>(string pluginPath, PluginLoadSetting loadSetting) where T : class
|
var dllFileNames = !Directory.Exists(pluginPath)
|
||||||
{
|
? Array.Empty<string>() // Don't immediately return, as we may be loading plugins merged with this .exe
|
||||||
var dllFileNames = !Directory.Exists(pluginPath)
|
: Directory.EnumerateFiles(pluginPath, "*.dll", SearchOption.AllDirectories);
|
||||||
? Enumerable.Empty<string>()
|
var assemblies = GetAssemblies(dllFileNames, loadSetting);
|
||||||
: Directory.EnumerateFiles(pluginPath, "*.dll", SearchOption.AllDirectories);
|
var pluginTypes = GetPluginsOfType<T>(assemblies);
|
||||||
var assemblies = GetAssemblies(dllFileNames, loadSetting);
|
return LoadPlugins<T>(pluginTypes);
|
||||||
var pluginTypes = GetPluginsOfType<T>(assemblies);
|
}
|
||||||
return LoadPlugins<T>(pluginTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<T> LoadPlugins<T>(IEnumerable<Type> pluginTypes) where T : class
|
private static IEnumerable<T> LoadPlugins<T>(IEnumerable<Type> pluginTypes) where T : class
|
||||||
|
{
|
||||||
|
foreach (var t in pluginTypes)
|
||||||
{
|
{
|
||||||
foreach (var t in pluginTypes)
|
T? activate;
|
||||||
{
|
try { activate = (T?)Activator.CreateInstance(t); }
|
||||||
T? activate;
|
|
||||||
try { activate = (T?)Activator.CreateInstance(t); }
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine($"Unable to load plugin [{t.Name}]: {t.FullName}");
|
|
||||||
System.Diagnostics.Debug.WriteLine(ex.Message);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (activate != null)
|
|
||||||
yield return activate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<Assembly> GetAssemblies(IEnumerable<string> dllFileNames, PluginLoadSetting loadSetting)
|
|
||||||
{
|
|
||||||
var assemblies = dllFileNames.Select(GetPluginLoadMethod(loadSetting));
|
|
||||||
if (loadSetting is PluginLoadSetting.LoadFromMerged or PluginLoadSetting.LoadFileMerged or PluginLoadSetting.UnsafeMerged)
|
|
||||||
assemblies = assemblies.Concat(new[] { Assembly.GetExecutingAssembly() }); // load merged too
|
|
||||||
return assemblies;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Func<string, Assembly> GetPluginLoadMethod(PluginLoadSetting pls) => pls switch
|
|
||||||
{
|
|
||||||
PluginLoadSetting.LoadFrom or PluginLoadSetting.LoadFromMerged => Assembly.LoadFrom,
|
|
||||||
PluginLoadSetting.LoadFile or PluginLoadSetting.LoadFileMerged => Assembly.LoadFile,
|
|
||||||
PluginLoadSetting.UnsafeLoadFrom or PluginLoadSetting.UnsafeMerged => Assembly.UnsafeLoadFrom,
|
|
||||||
_ => throw new NotImplementedException($"PluginLoadSetting: {pls} method not defined."),
|
|
||||||
};
|
|
||||||
|
|
||||||
private static IEnumerable<Type> GetPluginsOfType<T>(IEnumerable<Assembly> assemblies)
|
|
||||||
{
|
|
||||||
var pluginType = typeof(T);
|
|
||||||
return assemblies.SelectMany(z => GetPluginTypes(z, pluginType));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<Type> GetPluginTypes(Assembly z, Type pluginType)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Handle Costura merged plugin dll's; need to Attach for them to correctly retrieve their dependencies.
|
|
||||||
var assemblyLoaderType = z.GetType("Costura.AssemblyLoader", false);
|
|
||||||
var attachMethod = assemblyLoaderType?.GetMethod("Attach", BindingFlags.Static | BindingFlags.Public);
|
|
||||||
attachMethod?.Invoke(null, Array.Empty<object>());
|
|
||||||
|
|
||||||
var types = z.GetTypes();
|
|
||||||
return types.Where(type => IsTypePlugin(type, pluginType));
|
|
||||||
}
|
|
||||||
// User plugins can be out of date, with mismatching API surfaces.
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine($"Unable to load plugin [{pluginType.Name}]: {z.FullName}");
|
Debug.WriteLine($"Unable to load plugin [{t.Name}]: {t.FullName}");
|
||||||
System.Diagnostics.Debug.WriteLine(ex.Message);
|
Debug.WriteLine(ex.Message);
|
||||||
if (ex is ReflectionTypeLoadException rtle)
|
continue;
|
||||||
{
|
|
||||||
foreach (var le in rtle.LoaderExceptions)
|
|
||||||
{
|
|
||||||
if (le is not null)
|
|
||||||
System.Diagnostics.Debug.WriteLine(le.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Array.Empty<Type>();
|
|
||||||
}
|
}
|
||||||
}
|
if (activate != null)
|
||||||
|
yield return activate;
|
||||||
private static bool IsTypePlugin(Type type, Type pluginType)
|
|
||||||
{
|
|
||||||
if (type.IsInterface || type.IsAbstract)
|
|
||||||
return false;
|
|
||||||
var name = pluginType.FullName;
|
|
||||||
if (name == null)
|
|
||||||
return false;
|
|
||||||
if (type.GetInterface(name) == null)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Assembly> GetAssemblies(IEnumerable<string> dllFileNames, PluginLoadSetting loadSetting)
|
||||||
|
{
|
||||||
|
var loadMethod = GetPluginLoadMethod(loadSetting);
|
||||||
|
var assemblies = dllFileNames.Select(loadMethod);
|
||||||
|
if (loadSetting.IsMerged())
|
||||||
|
assemblies = assemblies.Concat(new[] { Assembly.GetExecutingAssembly() }); // load merged too
|
||||||
|
return assemblies;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Func<string, Assembly> GetPluginLoadMethod(PluginLoadSetting pls) => pls switch
|
||||||
|
{
|
||||||
|
LoadFrom or LoadFromMerged => Assembly.LoadFrom,
|
||||||
|
LoadFile or LoadFileMerged => Assembly.LoadFile,
|
||||||
|
UnsafeLoadFrom or UnsafeMerged => Assembly.UnsafeLoadFrom,
|
||||||
|
_ => throw new IndexOutOfRangeException($"PluginLoadSetting: {pls} method not defined."),
|
||||||
|
};
|
||||||
|
|
||||||
|
public static bool IsMerged(this PluginLoadSetting loadSetting) => loadSetting is LoadFromMerged or LoadFileMerged or UnsafeMerged;
|
||||||
|
|
||||||
|
private static IEnumerable<Type> GetPluginsOfType<T>(IEnumerable<Assembly> assemblies)
|
||||||
|
{
|
||||||
|
var interfaceTypeName = typeof(T).FullName;
|
||||||
|
if (interfaceTypeName is null)
|
||||||
|
return Array.Empty<Type>();
|
||||||
|
return assemblies.SelectMany(z => GetPluginTypes(z, interfaceTypeName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Type> GetPluginTypes(Assembly z, string interfaceTypeName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Handle Costura merged plugin dll's; need to Attach for them to correctly retrieve their dependencies.
|
||||||
|
var assemblyLoaderType = z.GetType("Costura.AssemblyLoader", false);
|
||||||
|
var attachMethod = assemblyLoaderType?.GetMethod("Attach", BindingFlags.Static | BindingFlags.Public);
|
||||||
|
attachMethod?.Invoke(null, Array.Empty<object>());
|
||||||
|
|
||||||
|
var types = z.GetTypes();
|
||||||
|
return types.Where(type => IsTypePlugin(type, interfaceTypeName));
|
||||||
|
}
|
||||||
|
// User plugins can be out of date, with mismatching API surfaces.
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.WriteLine($"Unable to load plugin [{interfaceTypeName}]: {z.FullName}");
|
||||||
|
Debug.WriteLine(ex.Message);
|
||||||
|
if (ex is not ReflectionTypeLoadException rtle)
|
||||||
|
return Array.Empty<Type>();
|
||||||
|
|
||||||
|
foreach (var le in rtle.LoaderExceptions)
|
||||||
|
{
|
||||||
|
if (le is not null)
|
||||||
|
Debug.WriteLine(le.Message);
|
||||||
|
}
|
||||||
|
return Array.Empty<Type>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsTypePlugin(Type type, string interfaceTypeName)
|
||||||
|
{
|
||||||
|
if (type.IsInterface || type.IsAbstract)
|
||||||
|
return false;
|
||||||
|
if (type.GetInterface(interfaceTypeName) == null)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ namespace PKHeX.WinForms
|
||||||
var headers = dgData.Columns.Cast<DataGridViewColumn>();
|
var headers = dgData.Columns.Cast<DataGridViewColumn>();
|
||||||
await s.WriteLineAsync(string.Join(",", headers.Skip(1).Select(column => $"\"{column.HeaderText}\""))).ConfigureAwait(false);
|
await s.WriteLineAsync(string.Join(",", headers.Skip(1).Select(column => $"\"{column.HeaderText}\""))).ConfigureAwait(false);
|
||||||
|
|
||||||
foreach (var cells in from DataGridViewRow row in dgData.Rows select row.Cells.Cast<DataGridViewCell>())
|
foreach (var cells in dgData.Rows.Cast<DataGridViewRow>().Select(row => row.Cells.Cast<DataGridViewCell>()))
|
||||||
await s.WriteLineAsync(string.Join(",", cells.Skip(1).Select(cell => $"\"{cell.Value}\""))).ConfigureAwait(false);
|
await s.WriteLineAsync(string.Join(",", cells.Skip(1).Select(cell => $"\"{cell.Value}\""))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,17 +46,19 @@ namespace PKHeX.WinForms
|
||||||
|
|
||||||
private static void UpdateTranslations()
|
private static void UpdateTranslations()
|
||||||
{
|
{
|
||||||
|
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
|
||||||
|
var types = assembly.GetTypes();
|
||||||
// add mode
|
// add mode
|
||||||
WinFormsTranslator.SetRemovalMode(false);
|
WinFormsTranslator.SetRemovalMode(false);
|
||||||
WinFormsTranslator.LoadSettings<PKHeXSettings>(DefaultLanguage);
|
WinFormsTranslator.LoadSettings<PKHeXSettings>(DefaultLanguage);
|
||||||
WinFormsTranslator.LoadAllForms(LoadBanlist); // populate with every possible control
|
WinFormsTranslator.LoadAllForms(types, LoadBanlist); // populate with every possible control
|
||||||
WinFormsTranslator.UpdateAll(DefaultLanguage, Languages); // propagate to others
|
WinFormsTranslator.UpdateAll(DefaultLanguage, Languages); // propagate to others
|
||||||
WinFormsTranslator.DumpAll(Banlist); // dump current to file
|
WinFormsTranslator.DumpAll(Banlist); // dump current to file
|
||||||
|
|
||||||
// de-populate
|
// de-populate
|
||||||
WinFormsTranslator.SetRemovalMode(); // remove used keys, don't add any
|
WinFormsTranslator.SetRemovalMode(); // remove used keys, don't add any
|
||||||
WinFormsTranslator.LoadSettings<PKHeXSettings>(DefaultLanguage, false);
|
WinFormsTranslator.LoadSettings<PKHeXSettings>(DefaultLanguage, false);
|
||||||
WinFormsTranslator.LoadAllForms(LoadBanlist);
|
WinFormsTranslator.LoadAllForms(types, LoadBanlist);
|
||||||
WinFormsTranslator.RemoveAll(DefaultLanguage, PurgeBanlist); // remove all lines from above generated files that still remain
|
WinFormsTranslator.RemoveAll(DefaultLanguage, PurgeBanlist); // remove all lines from above generated files that still remain
|
||||||
|
|
||||||
// Move translated files from the debug exe loc to their project location
|
// Move translated files from the debug exe loc to their project location
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
@ -31,30 +30,37 @@ namespace PKHeX.WinForms
|
||||||
private static void TranslateForm(Control form, TranslationContext context)
|
private static void TranslateForm(Control form, TranslationContext context)
|
||||||
{
|
{
|
||||||
form.SuspendLayout();
|
form.SuspendLayout();
|
||||||
var formname = form.Name;
|
|
||||||
// Translate Title
|
// Translate Title
|
||||||
form.Text = context.GetTranslatedText(formname, form.Text);
|
var formName = form.Name;
|
||||||
|
form.Text = context.GetTranslatedText(formName, form.Text);
|
||||||
|
|
||||||
|
// Translate Controls
|
||||||
var translatable = GetTranslatableControls(form);
|
var translatable = GetTranslatableControls(form);
|
||||||
foreach (var c in translatable)
|
foreach (var c in translatable)
|
||||||
{
|
TranslateControl(c, context, formName);
|
||||||
if (c is Control r)
|
|
||||||
{
|
|
||||||
var current = r.Text;
|
|
||||||
var updated = context.GetTranslatedText($"{formname}.{r.Name}", current);
|
|
||||||
if (!ReferenceEquals(current, updated))
|
|
||||||
r.Text = updated;
|
|
||||||
}
|
|
||||||
else if (c is ToolStripItem t)
|
|
||||||
{
|
|
||||||
var current = t.Text;
|
|
||||||
var updated = context.GetTranslatedText($"{formname}.{t.Name}", current);
|
|
||||||
if (!ReferenceEquals(current, updated))
|
|
||||||
t.Text = updated;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
form.ResumeLayout();
|
form.ResumeLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void TranslateControl(object c, TranslationContext context, string formname)
|
||||||
|
{
|
||||||
|
if (c is Control r)
|
||||||
|
{
|
||||||
|
var current = r.Text;
|
||||||
|
var updated = context.GetTranslatedText($"{formname}.{r.Name}", current);
|
||||||
|
if (!ReferenceEquals(current, updated))
|
||||||
|
r.Text = updated;
|
||||||
|
}
|
||||||
|
else if (c is ToolStripItem t)
|
||||||
|
{
|
||||||
|
var current = t.Text;
|
||||||
|
var updated = context.GetTranslatedText($"{formname}.{t.Name}", current);
|
||||||
|
if (!ReferenceEquals(current, updated))
|
||||||
|
t.Text = updated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static IEnumerable<string> GetTranslationFile(string lang)
|
private static IEnumerable<string> GetTranslationFile(string lang)
|
||||||
{
|
{
|
||||||
var file = GetTranslationFileNameInternal(lang);
|
var file = GetTranslationFileNameInternal(lang);
|
||||||
|
@ -132,12 +138,14 @@ namespace PKHeX.WinForms
|
||||||
foreach (var dropDownItem in item.DropDownItems.OfType<ToolStripMenuItem>())
|
foreach (var dropDownItem in item.DropDownItems.OfType<ToolStripMenuItem>())
|
||||||
{
|
{
|
||||||
yield return dropDownItem;
|
yield return dropDownItem;
|
||||||
if (!dropDownItem.HasDropDownItems) continue;
|
if (!dropDownItem.HasDropDownItems)
|
||||||
|
continue;
|
||||||
foreach (ToolStripMenuItem subItem in GetToolsStripDropDownItems(dropDownItem))
|
foreach (ToolStripMenuItem subItem in GetToolsStripDropDownItems(dropDownItem))
|
||||||
yield return subItem;
|
yield return subItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
public static void UpdateAll(string baseLanguage, IEnumerable<string> others)
|
public static void UpdateAll(string baseLanguage, IEnumerable<string> others)
|
||||||
{
|
{
|
||||||
var baseContext = GetContext(baseLanguage);
|
var baseContext = GetContext(baseLanguage);
|
||||||
|
@ -161,16 +169,14 @@ namespace PKHeX.WinForms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void LoadAllForms(params string[] banlist)
|
public static void LoadAllForms(IEnumerable<System.Type> types, params string[] banlist)
|
||||||
{
|
{
|
||||||
var q = from t in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
|
types = types.Where(t => t.BaseType == typeof(Form) && !banlist.Contains(t.Name));
|
||||||
where t.BaseType == typeof(Form) && !banlist.Contains(t.Name)
|
foreach (var t in types)
|
||||||
select t;
|
|
||||||
foreach (var t in q)
|
|
||||||
{
|
{
|
||||||
var constructors = t.GetConstructors();
|
var constructors = t.GetConstructors();
|
||||||
if (constructors.Length == 0)
|
if (constructors.Length == 0)
|
||||||
{ Debug.WriteLine($"No constructors: {t.Name}"); continue; }
|
{ System.Diagnostics.Debug.WriteLine($"No constructors: {t.Name}"); continue; }
|
||||||
var argCount = constructors[0].GetParameters().Length;
|
var argCount = constructors[0].GetParameters().Length;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -179,7 +185,7 @@ namespace PKHeX.WinForms
|
||||||
// This is a debug utility method, will always be logging. Shouldn't ever fail.
|
// This is a debug utility method, will always be logging. Shouldn't ever fail.
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Debug.Write($"Failed to create a new form {t}");
|
System.Diagnostics.Debug.Write($"Failed to create a new form {t}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,6 +241,7 @@ namespace PKHeX.WinForms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class TranslationContext
|
public sealed class TranslationContext
|
||||||
|
@ -278,11 +285,5 @@ namespace PKHeX.WinForms
|
||||||
GetTranslatedText(kvp.Key, kvp.Value);
|
GetTranslatedText(kvp.Key, kvp.Value);
|
||||||
AddNew = oldAdd;
|
AddNew = oldAdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveKeys(TranslationContext other)
|
|
||||||
{
|
|
||||||
foreach (var kvp in other.Translation)
|
|
||||||
Translation.Remove(kvp.Key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue