Skip to content

Feature: Added an action to open File Explorers property window #16031

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Files.App.CsWin32/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,4 @@ WindowsCreateString
WindowsDeleteString
IPreviewHandler
AssocQueryString
GetModuleHandle
ShellExecuteEx
77 changes: 77 additions & 0 deletions src/Files.App/Actions/Open/OpenClassicPropertiesAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) 2024 Files Community
// Licensed under the MIT License. See the LICENSE.

using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.UI.Shell;

namespace Files.App.Actions
{
internal sealed class OpenClassicPropertiesAction : ObservableObject, IAction
{
private readonly IContentPageContext context;

public string Label
=> "OpenClassicProperties".GetLocalizedResource();

public string Description
=> "OpenClassicPropertiesDescription".GetLocalizedResource();

public RichGlyph Glyph
=> new(themedIconStyle: "App.ThemedIcons.Properties");

public HotKey HotKey
=> new(Keys.Enter, KeyModifiers.AltShift);

public bool IsExecutable =>
context.PageType is not ContentPageTypes.Home &&
(context.HasSelection && context.SelectedItems.Count == 1 ||
!context.HasSelection && context.PageType is not ContentPageTypes.SearchResults);

public OpenClassicPropertiesAction()
{
context = Ioc.Default.GetRequiredService<IContentPageContext>();

context.PropertyChanged += Context_PropertyChanged;
}

public Task ExecuteAsync(object? parameter = null)
{
if (context.HasSelection && context?.SelectedItem?.ItemPath is not null)
ExecuteShellCommand(context.SelectedItem.ItemPath);
else if (context?.Folder?.ItemPath is not null)
ExecuteShellCommand(context.Folder.ItemPath);

return Task.CompletedTask;
}

private unsafe void ExecuteShellCommand(string itemPath)
{
SHELLEXECUTEINFOW info = default;
info.cbSize = (uint)Marshal.SizeOf(info);
info.nShow = 5; // SW_SHOW
info.fMask = 0x0000000C;

var verb = "properties";
fixed (char* cVerb = verb)
info.lpVerb = cVerb;

fixed (char* lpFile = itemPath)
info.lpFile = lpFile;

PInvoke.ShellExecuteEx(ref info);
}

private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(IContentPageContext.PageType):
case nameof(IContentPageContext.HasSelection):
case nameof(IContentPageContext.Folder):
OnPropertyChanged(nameof(IsExecutable));
break;
}
}
}
}
1 change: 1 addition & 0 deletions src/Files.App/Data/Commands/Manager/CommandCodes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ public enum CommandCodes
OpenInVSCode,
OpenRepoInVSCode,
OpenProperties,
OpenClassicProperties,
OpenSettings,
OpenTerminal,
OpenTerminalAsAdmin,
Expand Down
2 changes: 2 additions & 0 deletions src/Files.App/Data/Commands/Manager/CommandManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public IRichCommand this[HotKey hotKey]
public IRichCommand OpenInVSCode => commands[CommandCodes.OpenInVSCode];
public IRichCommand OpenRepoInVSCode => commands[CommandCodes.OpenRepoInVSCode];
public IRichCommand OpenProperties => commands[CommandCodes.OpenProperties];
public IRichCommand OpenClassicProperties => commands[CommandCodes.OpenClassicProperties];
public IRichCommand OpenSettings => commands[CommandCodes.OpenSettings];
public IRichCommand OpenTerminal => commands[CommandCodes.OpenTerminal];
public IRichCommand OpenTerminalAsAdmin => commands[CommandCodes.OpenTerminalAsAdmin];
Expand Down Expand Up @@ -299,6 +300,7 @@ public IEnumerator<IRichCommand> GetEnumerator() =>
[CommandCodes.OpenInVSCode] = new OpenInVSCodeAction(),
[CommandCodes.OpenRepoInVSCode] = new OpenRepoInVSCodeAction(),
[CommandCodes.OpenProperties] = new OpenPropertiesAction(),
[CommandCodes.OpenClassicProperties] = new OpenClassicPropertiesAction(),
[CommandCodes.OpenSettings] = new OpenSettingsAction(),
[CommandCodes.OpenTerminal] = new OpenTerminalAction(),
[CommandCodes.OpenTerminalAsAdmin] = new OpenTerminalAsAdminAction(),
Expand Down
1 change: 1 addition & 0 deletions src/Files.App/Data/Commands/Manager/ICommandManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ public interface ICommandManager : IEnumerable<IRichCommand>
IRichCommand OpenInVSCode { get; }
IRichCommand OpenRepoInVSCode { get; }
IRichCommand OpenProperties { get; }
IRichCommand OpenClassicProperties { get; }
IRichCommand OpenSettings { get; }
IRichCommand OpenTerminal { get; }
IRichCommand OpenTerminalAsAdmin { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public interface IModifiableCommandManager : IEnumerable<IRichCommand>

IRichCommand PasteItem { get; }
IRichCommand DeleteItem { get; }
IRichCommand OpenProperties { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the MIT License. See the LICENSE.

using System.Collections.Frozen;
using System.Collections.Immutable;

namespace Files.App.Data.Commands
{
Expand All @@ -17,6 +16,7 @@ internal sealed class ModifiableCommandManager : IModifiableCommandManager
public IRichCommand None => ModifiableCommands[CommandCodes.None];
public IRichCommand PasteItem => ModifiableCommands[CommandCodes.PasteItem];
public IRichCommand DeleteItem => ModifiableCommands[CommandCodes.DeleteItem];
public IRichCommand OpenProperties => ModifiableCommands[CommandCodes.OpenProperties];

public ModifiableCommandManager()
{
Expand All @@ -35,6 +35,9 @@ public ModifiableCommandManager()
[CommandCodes.DeleteItem] = new ModifiableCommand(Commands.DeleteItem, new() {
{ KeyModifiers.Shift, Commands.DeleteItemPermanently }
}),
[CommandCodes.OpenProperties] = new ModifiableCommand(Commands.OpenProperties, new() {
{ KeyModifiers.Shift, Commands.OpenClassicProperties }
}),
}.ToFrozenDictionary();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -490,10 +490,10 @@ public static List<ContextMenuFlyoutItemViewModel> GetBaseItemMenuItems(
IsVisible = itemsSelected,
IsPrimary = true,
}.Build(),
new ContextMenuFlyoutItemViewModelBuilder(Commands.OpenProperties)
new ContextMenuFlyoutItemViewModelBuilder(ModifiableCommands.OpenProperties)
{
IsPrimary = true,
IsVisible = Commands.OpenProperties.IsExecutable
IsVisible = ModifiableCommands.OpenProperties.IsExecutable
}.Build(),
new ContextMenuFlyoutItemViewModelBuilder(Commands.OpenParentFolder).Build(),
new ContextMenuFlyoutItemViewModelBuilder(Commands.PinFolderToSidebar)
Expand Down
6 changes: 6 additions & 0 deletions src/Files.App/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -3063,9 +3063,15 @@
<data name="OpenProperties" xml:space="preserve">
<value>Open properties</value>
</data>
<data name="OpenClassicProperties" xml:space="preserve">
<value>Open File Explorer properties</value>
</data>
<data name="OpenPropertiesDescription" xml:space="preserve">
<value>Open properties window</value>
</data>
<data name="OpenClassicPropertiesDescription" xml:space="preserve">
<value>Open File Explorer properties window</value>
</data>
<data name="Locals" xml:space="preserve">
<value>Locals</value>
</data>
Expand Down
12 changes: 6 additions & 6 deletions src/Files.App/UserControls/InnerNavigationToolbar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -243,13 +243,13 @@
AccessKey="O"
AccessKeyInvoked="AppBarButton_AccessKeyInvoked"
AutomationProperties.AutomationId="InnerNavigationToolbarPropertiesButton"
Command="{x:Bind Commands.OpenProperties, Mode=OneWay}"
IsEnabled="{x:Bind Commands.OpenProperties.IsExecutable, Mode=OneWay}"
KeyboardAcceleratorTextOverride="{x:Bind Commands.OpenProperties.HotKeyText, Mode=OneWay}"
Label="{x:Bind Commands.OpenProperties.Label}"
Command="{x:Bind ModifiableCommands.OpenProperties, Mode=OneWay}"
IsEnabled="{x:Bind ModifiableCommands.OpenProperties.IsExecutable, Mode=OneWay}"
KeyboardAcceleratorTextOverride="{x:Bind ModifiableCommands.OpenProperties.HotKeyText, Mode=OneWay}"
Label="{x:Bind ModifiableCommands.OpenProperties.Label}"
LabelPosition="Collapsed"
ToolTipService.ToolTip="{x:Bind Commands.OpenProperties.LabelWithHotKey, Mode=OneWay}">
<controls:ThemedIcon Style="{x:Bind Commands.OpenProperties.ThemedIconStyle, Mode=OneTime}" />
ToolTipService.ToolTip="{x:Bind ModifiableCommands.OpenProperties.LabelWithHotKey, Mode=OneWay}">
<controls:ThemedIcon Style="{x:Bind ModifiableCommands.OpenProperties.ThemedIconStyle, Mode=OneTime}" />
</AppBarButton>

<!-- (Divider) -->
Expand Down