File context menu, element preview improvements
This commit is contained in:
@@ -9,11 +9,23 @@ namespace FileTime.App.Core.ViewModels.ItemPreview;
|
||||
[ViewModel]
|
||||
public partial class ElementPreviewViewModel : IItemPreviewViewModel, IAsyncInitable<IElement>
|
||||
{
|
||||
private record EncodingResult(char BinaryChar, string PartialResult);
|
||||
|
||||
private const int MaxTextPreviewSize = 1024 * 1024;
|
||||
|
||||
private static readonly List<Encoding> _encodings = new()
|
||||
{
|
||||
Encoding.UTF8,
|
||||
Encoding.Unicode,
|
||||
Encoding.ASCII,
|
||||
Encoding.UTF32,
|
||||
Encoding.BigEndianUnicode
|
||||
};
|
||||
|
||||
public ItemPreviewMode Mode { get; private set; }
|
||||
|
||||
[Property] private string? _textContent;
|
||||
[Property] private string? _textEncoding;
|
||||
|
||||
public async Task InitAsync(IElement element)
|
||||
{
|
||||
@@ -21,9 +33,17 @@ public partial class ElementPreviewViewModel : IItemPreviewViewModel, IAsyncInit
|
||||
{
|
||||
var content = await element.Provider.GetContentAsync(element, MaxTextPreviewSize);
|
||||
|
||||
TextContent = content is null
|
||||
? "Could not read any data from file " + element.Name
|
||||
: GetNormalizedText(Encoding.UTF8.GetString(content));
|
||||
if (content is null)
|
||||
{
|
||||
TextContent = "Could not read any data from file " + element.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
(TextContent, var encoding) = GetNormalizedText(content);
|
||||
TextEncoding = encoding is null
|
||||
? null
|
||||
: $"{encoding.EncodingName} ({encoding.WebName})";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -36,14 +56,58 @@ public partial class ElementPreviewViewModel : IItemPreviewViewModel, IAsyncInit
|
||||
_ => ItemPreviewMode.Text
|
||||
};
|
||||
|
||||
string GetNormalizedText(string text)
|
||||
(string, Encoding?) GetNormalizedText(byte[] data)
|
||||
{
|
||||
foreach (var c in text)
|
||||
var binaryCharacter = new Dictionary<string, EncodingResult>();
|
||||
foreach (var encoding in _encodings)
|
||||
{
|
||||
if (c < 32 && c != 9 && c != 10 && c != 13) return $"Binary data, contains '{(int) c}'";
|
||||
var text = encoding.GetString(data);
|
||||
var binary = false;
|
||||
for (var i = 0; i < text.Length; i++)
|
||||
{
|
||||
var c = text[i];
|
||||
if (c < 32 && c != 9 && c != 10 && c != 13)
|
||||
{
|
||||
binaryCharacter[encoding.EncodingName] =
|
||||
new EncodingResult(
|
||||
c,
|
||||
i == 0
|
||||
? string.Empty
|
||||
: text.Substring(0, i - 1)
|
||||
);
|
||||
|
||||
binary = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
if (binary) continue;
|
||||
|
||||
return (text, encoding);
|
||||
}
|
||||
|
||||
var stringBuilder = new StringBuilder();
|
||||
stringBuilder.AppendLine("The following binary characters were found by encodings:");
|
||||
foreach (var binaryByEncoding in binaryCharacter)
|
||||
{
|
||||
stringBuilder.AppendLine(binaryByEncoding.Key + ": " + (int) binaryByEncoding.Value.BinaryChar);
|
||||
}
|
||||
|
||||
var encodingsWithPartialResult = binaryCharacter.Where(e => !string.IsNullOrWhiteSpace(e.Value.PartialResult)).ToList();
|
||||
if (encodingsWithPartialResult.Count > 0)
|
||||
{
|
||||
stringBuilder.AppendLine("The following partial texts could be read by encodings:");
|
||||
foreach (var binaryByEncoding in encodingsWithPartialResult)
|
||||
{
|
||||
var text = binaryByEncoding.Value.PartialResult;
|
||||
|
||||
stringBuilder.AppendLine(binaryByEncoding.Key);
|
||||
stringBuilder.AppendLine(text);
|
||||
stringBuilder.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
return (stringBuilder.ToString(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,4 +5,5 @@ namespace FileTime.GuiApp.Services;
|
||||
public interface IContextMenuProvider
|
||||
{
|
||||
List<object> GetContextMenuForFolder(IContainer container);
|
||||
List<object> GetContextMenuForFile(IElement element);
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System.Globalization;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data.Converters;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.GuiApp.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
@@ -15,12 +16,16 @@ public class ContextMenuGenerator : IValueConverter
|
||||
{
|
||||
_contextMenuProvider ??= DI.ServiceProvider.GetRequiredService<IContextMenuProvider>();
|
||||
|
||||
if (value is IContainerViewModel containerViewModel)
|
||||
if (value is IContainerViewModel {Container: { } container})
|
||||
{
|
||||
return _contextMenuProvider.GetContextMenuForFolder(containerViewModel.Container);
|
||||
return _contextMenuProvider.GetContextMenuForFolder(container);
|
||||
}
|
||||
else if (value is IElementViewModel {Element: { } element})
|
||||
{
|
||||
return _contextMenuProvider.GetContextMenuForFile(element);
|
||||
}
|
||||
|
||||
return new object[] { new MenuItem() { Header = "asd" } };
|
||||
return new object[] {new MenuItem {Header = "asd"}};
|
||||
}
|
||||
|
||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.Versioning;
|
||||
using Avalonia.Media.Imaging;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.GuiApp.Helper;
|
||||
@@ -24,19 +25,20 @@ public static class WindowsSystemIconHelper
|
||||
return null;
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static ImagePath GetImagePathByIconPath(string path)
|
||||
{
|
||||
var environemntVariables = Environment.GetEnvironmentVariables();
|
||||
foreach (var keyo in environemntVariables.Keys)
|
||||
var environmentVariables = Environment.GetEnvironmentVariables();
|
||||
foreach (var keyObject in environmentVariables.Keys)
|
||||
{
|
||||
if (keyo is string key && environemntVariables[key] is string value)
|
||||
if (keyObject is string key && environmentVariables[key] is string value)
|
||||
{
|
||||
path = path.Replace($"%{key}%", value);
|
||||
}
|
||||
}
|
||||
|
||||
var parts = path.Split(',');
|
||||
(var parsedResourceId, var path2) = parts.Length >= 2 && long.TryParse(parts[^1], out var id)
|
||||
var (parsedResourceId, path2) = parts.Length >= 2 && long.TryParse(parts[^1], out var id)
|
||||
? (id, NormalizePath(string.Join(',', parts[..^1])))
|
||||
: (0, NormalizePath(path));
|
||||
|
||||
|
||||
@@ -8,4 +8,9 @@ public class LinuxContextMenuProvider : IContextMenuProvider
|
||||
{
|
||||
return new List<object>();
|
||||
}
|
||||
|
||||
public List<object> GetContextMenuForFile(IElement element)
|
||||
{
|
||||
return new List<object>();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using FileTime.Core.Models;
|
||||
@@ -10,6 +11,7 @@ using Microsoft.Win32;
|
||||
|
||||
namespace FileTime.GuiApp.Services;
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class WindowsContextMenuProvider : IContextMenuProvider
|
||||
{
|
||||
public List<object> GetContextMenuForFolder(IContainer container)
|
||||
@@ -17,17 +19,15 @@ public class WindowsContextMenuProvider : IContextMenuProvider
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) throw new NotSupportedException();
|
||||
|
||||
var menuItems = new List<object>();
|
||||
if (container.Provider is not ILocalContentProvider) return menuItems;
|
||||
|
||||
if (container.Provider is ILocalContentProvider)
|
||||
{
|
||||
using var directoryKey = Registry.ClassesRoot.OpenSubKey("Directory");
|
||||
ProcessRegistryKey(directoryKey, menuItems, container!.NativePath!.Path);
|
||||
}
|
||||
ProcessRegistryKeyForContainer(directoryKey, menuItems, container!.NativePath!.Path);
|
||||
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
private void ProcessRegistryKey(RegistryKey? contextMenuContainer, List<object> menuItems, string folderPath)
|
||||
private void ProcessRegistryKeyForContainer(RegistryKey? contextMenuContainer, List<object> menuItems, string folderPath)
|
||||
{
|
||||
using var shell = contextMenuContainer?.OpenSubKey("shell");
|
||||
if (shell == null) return;
|
||||
@@ -36,63 +36,42 @@ public class WindowsContextMenuProvider : IContextMenuProvider
|
||||
|
||||
foreach (var shellKey in shellSubKeys.Select(k => shell.OpenSubKey(k)).OfType<RegistryKey>())
|
||||
{
|
||||
var textBase = shellKey.GetValue(null) as string ?? shellKey.GetValue("MUIVerb") as string;
|
||||
var displayTextBase =
|
||||
shellKey.GetValue(null) as string
|
||||
?? shellKey.GetValue("MUIVerb") as string
|
||||
?? shellKey.Name.Split('\\').Last();
|
||||
|
||||
if (textBase == null) continue;
|
||||
string? displayText = null;
|
||||
displayText = displayTextBase.StartsWith("@")
|
||||
? ResolveText(displayTextBase)
|
||||
: displayTextBase;
|
||||
|
||||
string? text = null;
|
||||
if (textBase.StartsWith("@"))
|
||||
{
|
||||
var parts = textBase[1..].Split(',');
|
||||
if (parts.Length == 2 && long.TryParse(parts[1], out var parsedResourceId))
|
||||
{
|
||||
if (parsedResourceId < 0) parsedResourceId *= -1;
|
||||
if (displayText is null) continue;
|
||||
|
||||
text = NativeMethodHelpers.GetStringResource(string.Join(',', parts[..^1]), (uint) parsedResourceId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
text = textBase;
|
||||
}
|
||||
displayText = displayText.Replace("&", "");
|
||||
|
||||
if (text != null)
|
||||
{
|
||||
text = text.Replace("&", "");
|
||||
|
||||
object? image = null;
|
||||
try
|
||||
{
|
||||
if (shellKey.GetValue("Icon") is string iconPath)
|
||||
{
|
||||
var imagePath = WindowsSystemIconHelper.GetImagePathByIconPath(iconPath);
|
||||
if (imagePath.Type == Models.ImagePathType.Raw)
|
||||
{
|
||||
image = new Image()
|
||||
{
|
||||
Source = (IImage) imagePath.Image!
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
var image = shellKey.GetValue("Icon") is string iconPath
|
||||
? ResolveImage(iconPath)
|
||||
: null;
|
||||
|
||||
using var commandKey = shellKey.OpenSubKey("command");
|
||||
if (shellKey.GetSubKeyNames().Contains("command") && commandKey?.GetValue(null) is string commandString)
|
||||
if (commandKey?.GetValueNames().Contains("DelegateExecute") ?? false) continue;
|
||||
|
||||
if (GetCommandKey(shellKey, commandKey) is { } commandString)
|
||||
{
|
||||
var item = new MenuItem() {Header = text, Icon = image};
|
||||
item.Click += (o, e) => MenuItemClick(folderPath, commandString);
|
||||
var item = new MenuItem {Header = displayText, Icon = image};
|
||||
item.Click += (o, e) => HandleStartCommandMenuItemClick(folderPath, commandString);
|
||||
menuItems.Add(item);
|
||||
}
|
||||
else if (shellKey.GetValue("ExtendedSubCommandsKey") is string extendedCommands)
|
||||
{
|
||||
var rootMenuItems = new List<object>();
|
||||
|
||||
ProcessRegistryKey(Registry.ClassesRoot.OpenSubKey(extendedCommands), rootMenuItems, folderPath);
|
||||
ProcessRegistryKeyForContainer(Registry.ClassesRoot.OpenSubKey(extendedCommands), rootMenuItems, folderPath);
|
||||
|
||||
var rootMenu = new MenuItem {Header = text, Icon = image};
|
||||
if (rootMenuItems.Count == 0) continue;
|
||||
|
||||
var rootMenu = new MenuItem {Header = displayText, Icon = image};
|
||||
foreach (var item in rootMenuItems)
|
||||
{
|
||||
rootMenu.Items.Add(item);
|
||||
@@ -101,54 +80,209 @@ public class WindowsContextMenuProvider : IContextMenuProvider
|
||||
menuItems.Add(rootMenu);
|
||||
}
|
||||
}
|
||||
|
||||
static string? ResolveText(string textBase)
|
||||
{
|
||||
var parts = textBase[1..].Split(',');
|
||||
if (parts.Length == 2 && long.TryParse(parts[1], out var parsedResourceId))
|
||||
{
|
||||
if (parsedResourceId < 0) parsedResourceId *= -1;
|
||||
|
||||
return NativeMethodHelpers.GetStringResource(string.Join(',', parts[..^1]), (uint) parsedResourceId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static string? GetCommandKey(RegistryKey shellKey, RegistryKey? commandKey)
|
||||
{
|
||||
return
|
||||
shellKey.GetSubKeyNames().Contains("command")
|
||||
&& commandKey?.GetValue(null) is string commandString
|
||||
? commandString
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void MenuItemClick(string folderPath, string commandString)
|
||||
public List<object> GetContextMenuForFile(IElement element)
|
||||
{
|
||||
var commandPartsWithoutAp = commandString.Split('\"').ToList();
|
||||
var commandParts = new List<List<string>>();
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) throw new NotSupportedException();
|
||||
|
||||
for (var i = 0; i < commandPartsWithoutAp.Count; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
commandParts.Add(commandPartsWithoutAp[i].Split(' ').ToList());
|
||||
var menuItems = new List<object>();
|
||||
|
||||
if (element.Provider is not ILocalContentProvider) return menuItems;
|
||||
|
||||
var extension = element.Name.Split('.').LastOrDefault();
|
||||
if (extension is null) return menuItems;
|
||||
|
||||
using var extensionKey = Registry.ClassesRoot.OpenSubKey("." + extension);
|
||||
ProcessRegistryKeyForElement(extensionKey, menuItems, element!.NativePath!.Path);
|
||||
|
||||
return menuItems;
|
||||
}
|
||||
else
|
||||
|
||||
private void ProcessRegistryKeyForElement(RegistryKey? extensionKey, List<object> menuItems, string path)
|
||||
{
|
||||
commandParts.Add(new List<string> {commandPartsWithoutAp[i]});
|
||||
var openWithItems = GetElementOpenWithItems(extensionKey, path);
|
||||
if (openWithItems.Count > 0)
|
||||
{
|
||||
var openWithMenuItem = new MenuItem {Header = "Open with"};
|
||||
foreach (var openWithItem in openWithItems)
|
||||
{
|
||||
openWithMenuItem.Items.Add(openWithItem);
|
||||
}
|
||||
|
||||
menuItems.Add(openWithMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < commandParts.Count; i++)
|
||||
private List<object> GetElementOpenWithItems(RegistryKey? extensionKey, string path)
|
||||
{
|
||||
for (var i2 = 0; i2 < commandParts[i].Count; i2++)
|
||||
List<object> menuItems = new();
|
||||
var openWithProgIds = extensionKey?.OpenSubKey("OpenWithProgids");
|
||||
if (openWithProgIds is null) return menuItems;
|
||||
|
||||
foreach (var valueName in openWithProgIds.GetValueNames())
|
||||
{
|
||||
commandParts[i][i2] = commandParts[i][i2].Replace("%1", folderPath).Replace("%V", folderPath);
|
||||
var programRegistryKey = Registry.ClassesRoot.OpenSubKey(valueName);
|
||||
if (programRegistryKey is null) continue;
|
||||
|
||||
var programOpenKey = programRegistryKey.OpenSubKey("shell")?.OpenSubKey("open");
|
||||
if (programOpenKey is null) continue;
|
||||
|
||||
|
||||
//Try get display name
|
||||
var displayText = GetDisplayText(programRegistryKey, programOpenKey);
|
||||
|
||||
//Try get executable path
|
||||
var programCommandKey = programOpenKey.OpenSubKey("command");
|
||||
if (programCommandKey?.GetValue(null) is not string command) continue;
|
||||
|
||||
var commandParts = ChopCommand(command);
|
||||
|
||||
var (executable, _) = TryGetExecutablePath(commandParts);
|
||||
|
||||
if (executable is null) continue;
|
||||
|
||||
displayText ??= Registry.ClassesRoot
|
||||
.OpenSubKey("Local Settings")
|
||||
?.OpenSubKey("Software")
|
||||
?.OpenSubKey("Microsoft")
|
||||
?.OpenSubKey("Windows")
|
||||
?.OpenSubKey("Shell")
|
||||
?.OpenSubKey("MuiCache")
|
||||
?.GetValue(executable + ".FriendlyAppName") as string;
|
||||
|
||||
if (displayText is null) continue;
|
||||
|
||||
var menuItem = new MenuItem {Header = displayText, Icon = ResolveImage(executable)};
|
||||
menuItem.Click +=
|
||||
(_, _) => HandleStartCommandMenuItemClick(
|
||||
path,
|
||||
command,
|
||||
commandParts: commandParts);
|
||||
menuItems.Add(menuItem);
|
||||
}
|
||||
|
||||
return menuItems;
|
||||
|
||||
static string? GetDisplayText(RegistryKey programRegistryKey, RegistryKey programOpenKey)
|
||||
{
|
||||
if (programRegistryKey.GetValue("FriendlyAppName") is string rootFriendAppName)
|
||||
return rootFriendAppName;
|
||||
|
||||
if (programOpenKey.GetValue("FriendlyAppName") is string openFriendAppName) return openFriendAppName;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var commandPartsWithoutEmpty = commandParts.SelectMany(c => c).Where(c => !string.IsNullOrWhiteSpace(c)).ToList();
|
||||
private static void HandleStartCommandMenuItemClick(
|
||||
string placeholderValue,
|
||||
string commandString,
|
||||
List<List<string>>? commandParts = null
|
||||
)
|
||||
{
|
||||
commandParts ??= ChopCommand(commandString);
|
||||
|
||||
ReplacePlaceholders(commandParts, placeholderValue);
|
||||
|
||||
var commandPartsWithoutEmpty = commandParts
|
||||
.SelectMany(c => c)
|
||||
.Where(c => !string.IsNullOrWhiteSpace(c))
|
||||
.ToList();
|
||||
|
||||
if (commandPartsWithoutEmpty.Count == 0)
|
||||
return;
|
||||
|
||||
if (commandPartsWithoutEmpty.Count == 1)
|
||||
{
|
||||
Process.Start(commandPartsWithoutEmpty[0]);
|
||||
return;
|
||||
}
|
||||
else if (commandPartsWithoutEmpty.Count > 1)
|
||||
|
||||
|
||||
if (commandParts[0].Count > 0)
|
||||
{
|
||||
var paramStartIndex1 = -1;
|
||||
var paramStartIndex2 = -1;
|
||||
var (executable, lastExecutablePart) = TryGetExecutablePath(commandParts);
|
||||
|
||||
if (executable is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (paramStartX, paramStartY) = GetPositionInArrayFromBySkipping(commandParts, 1, 0, lastExecutablePart);
|
||||
var arguments = SumList(commandParts, paramStartX, paramStartY);
|
||||
|
||||
using var process = new Process();
|
||||
process.StartInfo.FileName = executable;
|
||||
process.StartInfo.Arguments = arguments.TrimStart();
|
||||
process.Start();
|
||||
|
||||
return;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//TODO: error message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (argumentsStartIndexX, argumentsStartIndexY) = FindArgumentStartPosition(commandParts, commandPartsWithoutEmpty);
|
||||
var arguments2 = SumList(commandParts, argumentsStartIndexX, argumentsStartIndexY);
|
||||
using var process2 = new Process();
|
||||
process2.StartInfo.FileName = commandPartsWithoutEmpty[0];
|
||||
process2.StartInfo.Arguments = arguments2;
|
||||
process2.Start();
|
||||
|
||||
static void ReplacePlaceholders(List<List<string>> commandParts, string placeholderValue)
|
||||
{
|
||||
foreach (var commandPart in commandParts)
|
||||
{
|
||||
for (var i2 = 0; i2 < commandPart.Count; i2++)
|
||||
{
|
||||
commandPart[i2] = commandPart[i2]
|
||||
.Replace("%1", placeholderValue)
|
||||
.Replace("%V", placeholderValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static (int argumentsStartIndexX, int argumentsStartIndexY) FindArgumentStartPosition(
|
||||
List<List<string>> commandParts,
|
||||
List<string> commandPartsWithoutEmpty)
|
||||
{
|
||||
var argumentsStartIndexX = -1;
|
||||
var argumentsStartIndexY = -1;
|
||||
var found = false;
|
||||
|
||||
for (var x = 0; x < commandParts.Count && paramStartIndex1 == -1; x++)
|
||||
for (var x = 0; x < commandParts.Count && argumentsStartIndexX == -1; x++)
|
||||
{
|
||||
for (var y = 0; y < commandParts[x].Count; y++)
|
||||
{
|
||||
if (found)
|
||||
{
|
||||
paramStartIndex1 = x;
|
||||
paramStartIndex2 = y;
|
||||
argumentsStartIndexX = x;
|
||||
argumentsStartIndexY = y;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -159,73 +293,15 @@ public class WindowsContextMenuProvider : IContextMenuProvider
|
||||
}
|
||||
}
|
||||
|
||||
var arguments = SumList(commandParts, paramStartIndex1, paramStartIndex2);
|
||||
|
||||
try
|
||||
{
|
||||
using var process = new Process();
|
||||
process.StartInfo.FileName = commandPartsWithoutEmpty[0];
|
||||
process.StartInfo.Arguments = arguments;
|
||||
process.Start();
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (commandParts[0].Count > 0)
|
||||
{
|
||||
var executable = "";
|
||||
var lastExecutablePart = 0;
|
||||
for (lastExecutablePart = 0; !File.Exists(executable) && lastExecutablePart < commandParts[0].Count; lastExecutablePart++)
|
||||
{
|
||||
executable += (lastExecutablePart == 0 ? "" : " ") + commandParts[0][lastExecutablePart];
|
||||
return (argumentsStartIndexX, argumentsStartIndexY);
|
||||
}
|
||||
|
||||
lastExecutablePart--;
|
||||
|
||||
if (File.Exists(executable))
|
||||
{
|
||||
try
|
||||
{
|
||||
var (paramStartX, paramStartY) = GetCoordinatesFrom(commandParts, 1, 0, lastExecutablePart);
|
||||
arguments = SumList(commandParts, paramStartX, paramStartY);
|
||||
|
||||
using var process = new Process();
|
||||
process.StartInfo.FileName = executable;
|
||||
process.StartInfo.Arguments = arguments;
|
||||
process.Start();
|
||||
}
|
||||
catch
|
||||
{
|
||||
//TODO: error message
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO: ELSE error message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string SumList(List<List<string>> data, int paramStartIndex1, int paramStartIndex2)
|
||||
{
|
||||
var result = "";
|
||||
|
||||
for (var x = paramStartIndex1; x < data.Count; x++)
|
||||
{
|
||||
if (x % 2 == 1) result += "\"";
|
||||
|
||||
result += string.Join(
|
||||
' ',
|
||||
x == paramStartIndex1
|
||||
? data[x].Skip(paramStartIndex2)
|
||||
: data[x]
|
||||
);
|
||||
|
||||
if (x % 2 == 1) result += "\"";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static (int, int) GetCoordinatesFrom(List<List<string>> data, int skip, int startX = 0, int startY = 0)
|
||||
static (int positionX, int positionY) GetPositionInArrayFromBySkipping(
|
||||
List<List<string>> data,
|
||||
int skip,
|
||||
int startX = 0,
|
||||
int startY = 0
|
||||
)
|
||||
{
|
||||
int skipping = 0;
|
||||
var x = startX;
|
||||
@@ -250,4 +326,89 @@ public class WindowsContextMenuProvider : IContextMenuProvider
|
||||
|
||||
return (resultX, resultY);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<List<string>> ChopCommand(string commandString)
|
||||
{
|
||||
var commandPartsWithoutQuotationMark = commandString.Split('\"').ToList();
|
||||
var commandParts = new List<List<string>>();
|
||||
|
||||
for (var i = 0; i < commandPartsWithoutQuotationMark.Count; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
commandParts.Add(commandPartsWithoutQuotationMark[i].Split(' ').ToList());
|
||||
}
|
||||
else
|
||||
{
|
||||
commandParts.Add(new List<string> {commandPartsWithoutQuotationMark[i]});
|
||||
}
|
||||
}
|
||||
|
||||
return commandParts;
|
||||
}
|
||||
|
||||
static (string? executable, int lastExecutablePart) TryGetExecutablePath(List<List<string>> commandParts)
|
||||
{
|
||||
var executable = "";
|
||||
var lastExecutablePart = 0;
|
||||
|
||||
//Note: If the first block is empty, we will use the second one
|
||||
//Note: This can happen (or rather, the common case) when the command starts with ", for example
|
||||
// `"c:\...\...\xyz.exe" someParam` (without the ``)
|
||||
var executableIndex = commandParts[0].Count == 0 || commandParts[0].All(string.IsNullOrWhiteSpace)
|
||||
? 1
|
||||
: 0;
|
||||
|
||||
for (; !File.Exists(executable) && lastExecutablePart < commandParts[executableIndex].Count; lastExecutablePart++)
|
||||
{
|
||||
executable += (lastExecutablePart == 0 ? "" : " ") + commandParts[executableIndex][lastExecutablePart];
|
||||
}
|
||||
|
||||
if (executableIndex == 1) lastExecutablePart += commandParts[0].Count;
|
||||
|
||||
lastExecutablePart--;
|
||||
|
||||
return (File.Exists(executable) ? executable : null, lastExecutablePart);
|
||||
}
|
||||
|
||||
private static Image? ResolveImage(string iconPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var imagePath = WindowsSystemIconHelper.GetImagePathByIconPath(iconPath);
|
||||
if (imagePath.Type != Models.ImagePathType.Raw) return null;
|
||||
|
||||
return new Image
|
||||
{
|
||||
Source = (IImage) imagePath.Image!
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string SumList(List<List<string>> data, int paramStartIndex1, int paramStartIndex2)
|
||||
{
|
||||
var result = "";
|
||||
|
||||
for (var x = paramStartIndex1; x < data.Count; x++)
|
||||
{
|
||||
if (x % 2 == 1) result += "\"";
|
||||
|
||||
result += string.Join(
|
||||
' ',
|
||||
x == paramStartIndex1
|
||||
? data[x].Skip(paramStartIndex2)
|
||||
: data[x]
|
||||
);
|
||||
|
||||
if (x % 2 == 1) result += "\"";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -553,12 +553,19 @@
|
||||
HorizontalAlignment="Center"
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^.Mode, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Empty}, FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}"
|
||||
Text="Empty" />
|
||||
<ScrollViewer IsVisible="{Binding ItemPreviewService.ItemPreview^.Mode, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Text}, FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}">
|
||||
<Grid IsVisible="{Binding ItemPreviewService.ItemPreview^.Mode, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Text}, FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}" RowDefinitions="*, Auto">
|
||||
<ScrollViewer>
|
||||
<TextBox
|
||||
IsReadOnly="True"
|
||||
Text="{Binding ItemPreviewService.ItemPreview^.TextContent}"
|
||||
x:CompileBindings="False" />
|
||||
</ScrollViewer>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="5"
|
||||
Text="{Binding ItemPreviewService.ItemPreview^.TextEncoding, StringFormat=Encoding: {0}}"
|
||||
x:CompileBindings="False" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
Reference in New Issue
Block a user