resolved merge conflicts and validated that it works as expected

This commit is contained in:
Alekhya Reddy
2020-10-27 09:39:22 -07:00
70 changed files with 1773 additions and 1067 deletions

View File

@@ -70,24 +70,33 @@ namespace Microsoft.PowerToys.Settings.UI.Library
{
if (SettingsExists(powertoy, fileName))
{
// Given the file already exists, to deserialize the file and read it's content.
T deserializedSettings = GetFile<T>(powertoy, fileName);
// IF the file needs to be modified, to save the new configurations accordingly.
if (deserializedSettings.UpgradeSettingsConfiguration())
try
{
SaveSettings(deserializedSettings.ToJsonString(), powertoy, fileName);
// Given the file already exists, to deserialize the file and read it's content.
T deserializedSettings = GetFile<T>(powertoy, fileName);
// If the file needs to be modified, to save the new configurations accordingly.
if (deserializedSettings.UpgradeSettingsConfiguration())
{
SaveSettings(deserializedSettings.ToJsonString(), powertoy, fileName);
}
return deserializedSettings;
}
return deserializedSettings;
}
else
{
// If the settings file does not exist, to create a new object with default parameters and save it to a newly created settings file.
T newSettingsItem = new T();
SaveSettings(newSettingsItem.ToJsonString(), powertoy, fileName);
return newSettingsItem;
// Catch json deserialization exceptions when the file is corrupt and has an invalid json.
// If there are any deserialization issues like in https://github.com/microsoft/PowerToys/issues/7500, log the error and create a new settings.json file.
// This is different from the case where we have trailing zeros following a valid json file, which we have handled by trimming the trailing zeros.
catch (JsonException ex)
{
Logger.LogError($"Exception encountered while loading {powertoy} settings.", ex);
}
}
// If the settings file does not exist or if the file is corrupt, to create a new object with default parameters and save it to a newly created settings file.
T newSettingsItem = new T();
SaveSettings(newSettingsItem.ToJsonString(), powertoy, fileName);
return newSettingsItem;
}
// Given the powerToy folder name and filename to be accessed, this function deserializes and returns the file.

View File

@@ -32,6 +32,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library.Utilities
Log(message, "INFO");
}
public static void LogError(string message)
{
Log(message, "ERROR");
#if DEBUG
Debugger.Break();
#endif
}
public static void LogError(string message, Exception e)
{
Log(
@@ -42,6 +50,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library.Utilities
"Stack trace: " + Environment.NewLine +
e?.StackTrace,
"ERROR");
#if DEBUG
Debugger.Break();
#endif
}
private static void Log(string message, string type)

View File

@@ -86,6 +86,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
private bool _keepDateModified;
private int _encoderGuidId;
public bool IsListViewFocusRequested { get; set; }
public bool IsEnabled
{
get
@@ -257,6 +259,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
imageSizes.Add(newSize);
_advancedSizes = imageSizes;
SavesImageSizes(imageSizes);
// Set the focus requested flag to indicate that an add operation has occurred during the ContainerContentChanging event
IsListViewFocusRequested = true;
}
public void DeleteImageSize(int id)

View File

@@ -5,6 +5,7 @@
using System;
using System.Windows;
using Microsoft.PowerLauncher.Telemetry;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using Microsoft.PowerToys.Settings.UI.Views;
using Microsoft.PowerToys.Telemetry;
using Microsoft.Toolkit.Wpf.UI.XamlHost;
@@ -67,16 +68,17 @@ namespace Microsoft.PowerToys.Settings.UI.Runner
{
if (ShellPage.ShellHandler.IPCResponseHandleList != null)
{
try
var success = JsonObject.TryParse(msg, out JsonObject json);
if (success)
{
JsonObject json = JsonObject.Parse(msg);
foreach (Action<JsonObject> handle in ShellPage.ShellHandler.IPCResponseHandleList)
{
handle(json);
}
}
catch (Exception)
else
{
Logger.LogError("Failed to parse JSON from IPC message.");
}
}
};

View File

@@ -69,6 +69,11 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VCRTForwarders.140" Version="1.0.6" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers">
<Version>3.3.0</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>

View File

@@ -13,7 +13,7 @@ using Windows.UI.Popups;
namespace Microsoft.PowerToys.Settings.UI.Runner
{
public class Program
public static class Program
{
// Quantity of arguments
private const int ArgumentsQty = 5;
@@ -37,9 +37,9 @@ namespace Microsoft.PowerToys.Settings.UI.Runner
App app = new App();
app.InitializeComponent();
if (args.Length >= ArgumentsQty)
if (args != null && args.Length >= ArgumentsQty)
{
int.TryParse(args[2], out int powerToysPID);
_ = int.TryParse(args[2], out int powerToysPID);
PowerToysPID = powerToysPID;
if (args[4] == "true")

View File

@@ -6,36 +6,25 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
AutomationProperties.Name="{x:Bind Header, Mode=OneTime}"
d:DesignHeight="300"
d:DesignWidth="400">
<StackPanel Orientation="Vertical">
<TextBox x:Name="HotkeyTextBox"
x:Uid="SettingsPage_SetShortcut"
AutomationProperties.HelpText="{Binding ElementName=ShortcutWarningLabelText, Path=Text}"
IsReadOnly="True">
<ToolTipService.ToolTip>
<ToolTip>
<StackPanel Orientation="Vertical">
<TextBlock x:Uid="ShortcutWarningLabel"/>
<TextBlock Text="{x:Bind Keys, Mode=OneTime}" FontWeight="SemiBold"/>
</StackPanel>
</ToolTip>
<TextBlock x:Name="ShortcutWarningLabelText">
<Run x:Uid="ShortcutWarningLabel"/>
<LineBreak/>
<Run Text="{x:Bind Keys, Mode=OneTime}" FontWeight="SemiBold"/>
</TextBlock>
</ToolTipService.ToolTip>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="TitleText"
Text="{x:Bind Header, Mode=OneTime}"
Foreground="{Binding Path=IsEnabled, ElementName=HotkeyTextBox, Converter={StaticResource ModuleEnabledToForegroundConverter}}"
/>
<TextBlock x:Uid="SettingsPage_SetShortcut_Glyph"
x:Name="TitleGlyph" Text="&#xE946;"
FontFamily="Segoe MDL2 Assets"
Margin="4,4,0,0"
Foreground="{Binding Path=IsEnabled, ElementName=HotkeyTextBox, Converter={StaticResource ModuleEnabledToForegroundConverter}}"
/>
</StackPanel>
<TextBox x:Uid="SettingsPage_SetShortcut"
x:Name="HotkeyTextBox"
Margin="0,5,0,0"
IsReadOnly="True"
/>
</StackPanel>
<TextBox.Header>
<TextBlock>
<Run Text="{x:Bind Header, Mode=OneTime}"/>
<Run Text="&#xE946;" FontFamily="Segoe MDL2 Assets"/>
</TextBlock>
</TextBox.Header>
</TextBox>
</UserControl>

View File

@@ -62,10 +62,10 @@
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
AutomationProperties.LabeledBy="{Binding ElementName=FancyZones_LaunchEditorButtonControl}">
<StackPanel Orientation="Horizontal">
<Viewbox Height="12" Width="12">
<PathIcon Data="M896 0v896H0V0h896zM768 768V128H128v640h640zM0 1920v-896h1920v896H0zm128-768v640h1664v-640H128zM1024 0h896v896h-896V0zm768 768V128h-640v640h640z"/>
<Viewbox Height="14" Width="14" Margin="-1,1,0,0">
<PathIcon Data="M45,48H25.5V45H45V25.5H25.5v-3H45V3H25.5V0H48V48ZM22.5,48H3V45H22.5V3H3V0H25.5V48ZM0,48V0H3V48Z"/>
</Viewbox>
<TextBlock Margin="12,0,0,0"
<TextBlock Margin="8,0,0,0"
Name="FancyZones_LaunchEditorButtonControl"
x:Uid="FancyZones_LaunchEditorButtonControl"/>
</StackPanel>

View File

@@ -89,21 +89,19 @@
<!-- Replaced the Radiobuttons parent control with a StackPanel to mitigate the Tab and Arrow key related keyboard navigation issues due to XAML Islands
Tracking issue in the winui repository - https://github.com/microsoft/microsoft-ui-xaml/issues/3156 -->
<TextBlock Name="RadioButtons_Name_Theme"
x:Uid="RadioButtons_Name_Theme"
<TextBlock x:Name="RadioButtons_Name_Theme"
x:Uid="ColorModeHeader"
Margin="{StaticResource SmallTopMargin}"/>
<StackPanel AutomationProperties.LabeledBy="{Binding ElementName=RadioButtons_Name_Theme}">
<RadioButton x:Uid="GeneralPage_Radio_Theme_Dark"
Content="Dark"
<RadioButton x:Uid="Radio_Theme_Dark"
IsChecked="{ Binding Mode=TwoWay, Path=IsDarkThemeRadioButtonChecked}"/>
<RadioButton x:Uid="GeneralPage_Radio_Theme_Light"
Content="Light"
<RadioButton x:Uid="Radio_Theme_Light"
IsChecked="{ Binding Mode=TwoWay, Path=IsLightThemeRadioButtonChecked}"/>
<RadioButton x:Uid="GeneralPage_Radio_Theme_Default"
Content="System default"
<RadioButton x:Uid="Radio_Theme_Default"
IsChecked="{ Binding Mode=TwoWay, Path=IsSystemThemeRadioButtonChecked}"/>
<HyperlinkButton x:Uid="Windows_Color_Settings" NavigateUri="ms-settings:colors"/>
</StackPanel>
<ToggleSwitch x:Uid="GeneralPage_ToggleSwitch_RunAtStartUp"

View File

@@ -65,7 +65,8 @@
SelectionMode="None"
ScrollViewer.HorizontalScrollMode="Enabled"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.IsHorizontalRailEnabled="True">
ScrollViewer.IsHorizontalRailEnabled="True"
ContainerContentChanging="ImagesSizesListView_ContainerContentChanging">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
@@ -277,7 +278,9 @@
x:Uid="ImageResizer_FilenameFormatPlaceholder"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
Margin="{StaticResource SmallTopMargin}"
AutomationProperties.LabeledBy="{Binding ElementName=ImageResizer_FilenameFormatHeader}">
AutomationProperties.LabeledBy="{Binding ElementName=ImageResizer_FilenameFormatHeader}"
AutomationProperties.HelpText="{Binding ElementName=FileFormatTextBlock, Path=Text}"
>
<TextBox.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Name="ImageResizer_FilenameFormatHeader"
@@ -290,44 +293,34 @@
</StackPanel>
</TextBox.Header>
<ToolTipService.ToolTip>
<StackPanel>
<TextBlock x:Uid="ImageResizer_FileFormatDescription"/>
<TextBlock Margin="{StaticResource SmallTopMargin}">
<Run Text="%1" FontWeight="Bold" />
<Run Text=" - "/>
<Run x:Uid="ImageResizer_Formatting_Filename" />
</TextBlock>
<TextBlock>
<Run Text="%2" FontWeight="Bold" />
<Run Text=" - "/>
<Run x:Uid="ImageResizer_Formatting_Sizename"/>
</TextBlock>
<TextBlock>
<Run Text="%3" FontWeight="Bold" />
<Run Text=" - "/>
<Run x:Uid="ImageResizer_Formatting_SelectedWidth"/>
</TextBlock>
<TextBlock>
<Run Text="%4" FontWeight="Bold" />
<Run Text=" - "/>
<Run x:Uid="ImageResizer_Formatting_SelectedHeight"/>
</TextBlock>
<TextBlock>
<Run Text="%5" FontWeight="Bold" />
<Run Text=" - "/>
<Run x:Uid="ImageResizer_Formatting_ActualWidth"/>
</TextBlock>
<TextBlock>
<Run Text="%6" FontWeight="Bold" />
<Run Text=" - "/>
<Run x:Uid="ImageResizer_Formatting_ActualHeight"/>
</TextBlock>
</StackPanel>
<TextBlock x:Name="FileFormatTextBlock">
<Run x:Uid="ImageResizer_FileFormatDescription"/>
<LineBreak/>
<LineBreak/>
<Run Text="%1" FontWeight="Bold" />
<Run Text=" - "/>
<Run x:Uid="ImageResizer_Formatting_Filename" />
<LineBreak/>
<Run Text="%2" FontWeight="Bold" />
<Run Text=" - "/>
<Run x:Uid="ImageResizer_Formatting_Sizename"/>
<LineBreak/>
<Run Text="%3" FontWeight="Bold" />
<Run Text=" - "/>
<Run x:Uid="ImageResizer_Formatting_SelectedWidth"/>
<LineBreak/>
<Run Text="%4" FontWeight="Bold" />
<Run Text=" - "/>
<Run x:Uid="ImageResizer_Formatting_SelectedHeight"/>
<LineBreak/>
<Run Text="%5" FontWeight="Bold" />
<Run Text=" - "/>
<Run x:Uid="ImageResizer_Formatting_ActualWidth"/>
<LineBreak/>
<Run Text="%6" FontWeight="Bold" />
<Run Text=" - "/>
<Run x:Uid="ImageResizer_Formatting_ActualHeight"/>
</TextBlock>
</ToolTipService.ToolTip>
</TextBox>

View File

@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Linq;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using Microsoft.PowerToys.Settings.UI.Library.ViewModels;
@@ -45,5 +46,18 @@ namespace Microsoft.PowerToys.Settings.UI.Views
{
}
}
private void ImagesSizesListView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
if (ViewModel.IsListViewFocusRequested)
{
// Set focus to the last item in the ListView
int size = ImagesSizesListView.Items.Count;
((ListViewItem)ImagesSizesListView.ContainerFromIndex(size - 1)).Focus(FocusState.Programmatic);
// Reset the focus requested flag
ViewModel.IsListViewFocusRequested = false;
}
}
}
}

View File

@@ -146,19 +146,28 @@
<TextBlock x:Uid="Appearance_GroupSettings"
Style="{StaticResource SettingsGroupTitleStyle}"
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher, Converter={StaticResource ModuleEnabledToForegroundConverter}}" />
<TextBlock x:Uid="PowerLauncher_Theme"
<!-- We cannot navigate to all the radio buttons using the arrow keys because of an XYNavigation issue in the RadioButtons control.
The screen reader does not read the heading when we tab into a radio button, even though the LabeledBy automation property is set.
Link to the issue in the winui repository - https://github.com/microsoft/microsoft-ui-xaml/issues/3156 -->
<TextBlock x:Uid="ColorModeHeader"
x:Name="RadioButtons_Name_Theme"
Margin="{StaticResource SmallTopMargin}"
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher, Converter={StaticResource ModuleEnabledToForegroundConverter}}" />
<muxc:RadioButtons IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher}">
<RadioButton x:Uid="PowerLauncher_Radio_Theme_Dark"
<StackPanel AutomationProperties.LabeledBy="{Binding ElementName=RadioButtons_Name_Theme}">
<RadioButton x:Uid="Radio_Theme_Dark"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher}"
IsChecked="{Binding Mode=TwoWay, Path=IsDarkThemeRadioButtonChecked}" />
<RadioButton x:Uid="PowerLauncher_Radio_Theme_Light"
<RadioButton x:Uid="Radio_Theme_Light"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher}"
IsChecked="{Binding Mode=TwoWay, Path=IsLightThemeRadioButtonChecked}" />
<RadioButton x:Uid="PowerLauncher_Radio_Theme_Default"
<RadioButton x:Uid="Radio_Theme_Default"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.EnablePowerLauncher}"
IsChecked="{Binding Mode=TwoWay, Path=IsSystemThemeRadioButtonChecked}" />
</muxc:RadioButtons>
<HyperlinkButton x:Uid="Windows_Color_Settings" NavigateUri="ms-settings:colors"/>
</StackPanel>
</StackPanel>
<RelativePanel x:Name="SidePanel"

View File

@@ -41,10 +41,9 @@
</winui:NavigationViewItem.Icon>
</winui:NavigationViewItem>
<!-- TO DO: Update icon -->
<winui:NavigationViewItem x:Uid="Shell_FancyZones" helpers:NavHelper.NavigateTo="views:FancyZonesPage" AutomationProperties.HeadingLevel="Level1">
<winui:NavigationViewItem.Icon>
<PathIcon Data="M896 0v896H0V0h896zM768 768V128H128v640h640zM0 1920v-896h1920v896H0zm128-768v640h1664v-640H128zM1024 0h896v896h-896V0zm768 768V128h-640v640h640z"></PathIcon>
<PathIcon Data="M45,48H25.5V45H45V25.5H25.5v-3H45V3H25.5V0H48V48ZM22.5,48H3V45H22.5V3H3V0H25.5V48ZM0,48V0H3V48Z"/>
</winui:NavigationViewItem.Icon>
</winui:NavigationViewItem>
@@ -54,35 +53,30 @@
</winui:NavigationViewItem.Icon>
</winui:NavigationViewItem>
<!-- TO DO: Update icon -->
<winui:NavigationViewItem x:Uid="Shell_ImageResizer" helpers:NavHelper.NavigateTo="views:ImageResizerPage" AutomationProperties.HeadingLevel="Level1">
<winui:NavigationViewItem.Icon>
<PathIcon Data="M0 768h1408v1152H0V768zm128 1024h870l-582-581-288 288v293zm1152 0v-102l-224-223-101 101 223 224h102zM128 896v421l288-287 448 447 192-191 224 224V896H128zm832 256q-26 0-45-19t-19-45q0-26 19-45t45-19q26 0 45 19t19 45q0 26-19 45t-45 19zm960-512V347l-339 338-90-90 338-339h-293V128h512v512h-128zm-768-512h256v128h-256V128zm-128 128H768V128h256v128zm-384 0H384V128h256v128zm-384 0H0V128h256v128zM128 640H0V384h128v256zm1920 128v256h-128V768h128zm-128 384h128v256h-128v-256zm0 384h128v256h-128v-256zm-384 256h256v128h-256v-128z"></PathIcon>
</winui:NavigationViewItem.Icon>
</winui:NavigationViewItem>
<!-- TO DO: Update icon -->
<winui:NavigationViewItem x:Uid="Shell_KeyboardManager" helpers:NavHelper.NavigateTo="views:KeyboardManagerPage" AutomationProperties.HeadingLevel="Level1">
<winui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xE765;"/>
</winui:NavigationViewItem.Icon>
</winui:NavigationViewItem>
<!-- TO DO: Update icon -->
<winui:NavigationViewItem x:Uid="Shell_PowerRename" helpers:NavHelper.NavigateTo="views:PowerRenamePage" AutomationProperties.HeadingLevel="Level1">
<winui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xE8AC;"/>
</winui:NavigationViewItem.Icon>
</winui:NavigationViewItem>
<!-- TO DO: Update icon -->
<winui:NavigationViewItem x:Uid="Shell_PowerLauncher" helpers:NavHelper.NavigateTo="views:PowerLauncherPage" AutomationProperties.HeadingLevel="Level1">
<winui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xE773;"/>
</winui:NavigationViewItem.Icon>
</winui:NavigationViewItem>
<!-- TO DO: Update icon -->
<winui:NavigationViewItem x:Uid="Shell_ShortcutGuide" helpers:NavHelper.NavigateTo="views:ShortcutGuidePage" AutomationProperties.HeadingLevel="Level1">
<winui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xEDA7;"/>
@@ -94,7 +88,6 @@
DefaultHeader="{x:Bind ViewModel.Selected.Content, Mode=OneWay}">
<behaviors:NavigationViewHeaderBehavior.DefaultHeaderTemplate>
<DataTemplate>
<!-- TODO: Style clean up-->
<Grid Margin="0, -2, 0, 6">
<TextBlock
Text="{Binding}"

View File

@@ -90,17 +90,18 @@
The screen reader does not read the heading when we tab into a radio button, even though the LabeledBy automation property is set.
Link to the issue in the winui repository - https://github.com/microsoft/microsoft-ui-xaml/issues/3156 -->
<TextBlock Name="ShortcutGuide_Theme"
x:Uid="ShortcutGuide_Theme"
x:Uid="ColorModeHeader"
Margin="{StaticResource SmallTopMargin}"
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<muxc:RadioButtons IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
SelectedIndex="{x:Bind Mode=TwoWay, Path=ViewModel.ThemeIndex}"
Margin="{StaticResource XXSmallTopMargin}"
AutomationProperties.LabeledBy="{Binding ElementName=ShortcutGuide_Theme}">
<RadioButton x:Uid="GeneralPage_Radio_Theme_Dark" />
<RadioButton x:Uid="GeneralPage_Radio_Theme_Light" />
<RadioButton x:Uid="GeneralPage_Radio_Theme_Default"/>
<RadioButton x:Uid="Radio_Theme_Dark" />
<RadioButton x:Uid="Radio_Theme_Light" />
<RadioButton x:Uid="Radio_Theme_Default"/>
</muxc:RadioButtons>
<HyperlinkButton x:Uid="Windows_Color_Settings" NavigateUri="ms-settings:colors"/>
</StackPanel>
<RelativePanel x:Name="SidePanel"

View File

@@ -24,6 +24,7 @@ namespace ColorPicker.Mouse
private readonly IUserSettings _userSettings;
private System.Windows.Point _previousMousePosition = new System.Windows.Point(-1, 1);
private Color _previousColor = Color.Transparent;
private bool _colorFormatChanged;
[ImportingConstructor]
public MouseInfoProvider(AppStateHandler appStateMonitor, IUserSettings userSettings)
@@ -40,6 +41,7 @@ namespace ColorPicker.Mouse
_mouseHook = new MouseHook();
_userSettings = userSettings;
_userSettings.CopiedColorRepresentation.PropertyChanged += CopiedColorRepresentation_PropertyChanged;
}
public event EventHandler<Color> MouseColorChanged;
@@ -73,9 +75,10 @@ namespace ColorPicker.Mouse
}
var color = GetPixelColor(mousePosition);
if (_previousColor != color)
if (_previousColor != color || _colorFormatChanged)
{
_previousColor = color;
_colorFormatChanged = false;
MouseColorChanged?.Invoke(this, color);
}
}
@@ -137,6 +140,11 @@ namespace ColorPicker.Mouse
OnMouseDown?.Invoke(this, p);
}
private void CopiedColorRepresentation_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
_colorFormatChanged = true;
}
private void DisposeHook()
{
if (_timer.IsEnabled)

View File

@@ -37,6 +37,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Canvas_Layout_Editor" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Canvas layout editor]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Layout-Editor für Canvas]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Choose_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Choose your layout for this desktop]]></Val>
@@ -118,6 +127,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Fancy_Zones_Main_Editor" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[FancyZones main editor]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[FancyZones-Haupteditor]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Name" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Name]]></Val>

View File

@@ -37,6 +37,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Canvas_Layout_Editor" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Canvas layout editor]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Editor de diseño de lienzo]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Choose_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Choose your layout for this desktop]]></Val>
@@ -118,6 +127,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Fancy_Zones_Main_Editor" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[FancyZones main editor]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Editor principal de FancyZones]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Name" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Name]]></Val>

View File

@@ -37,6 +37,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Canvas_Layout_Editor" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Canvas layout editor]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Éditeur de disposition de canevas]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Choose_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Choose your layout for this desktop]]></Val>
@@ -118,6 +127,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Fancy_Zones_Main_Editor" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[FancyZones main editor]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Éditeur principal de FancyZones]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Name" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Name]]></Val>

View File

@@ -37,6 +37,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Canvas_Layout_Editor" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Canvas layout editor]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Editor voor canvasindeling]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Choose_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Choose your layout for this desktop]]></Val>
@@ -118,6 +127,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Fancy_Zones_Main_Editor" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[FancyZones main editor]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[FancyZones-hoofdeditor]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Name" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Name]]></Val>

View File

@@ -37,6 +37,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Canvas_Layout_Editor" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Canvas layout editor]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Editor de layout de tela]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Choose_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Choose your layout for this desktop]]></Val>
@@ -118,6 +127,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Fancy_Zones_Main_Editor" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[FancyZones main editor]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Editor principal do FancyZones]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Name" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Name]]></Val>

View File

@@ -37,6 +37,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Canvas_Layout_Editor" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Canvas layout editor]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Tuval düzeni düzenleyicisi]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Choose_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Choose your layout for this desktop]]></Val>
@@ -118,6 +127,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Fancy_Zones_Main_Editor" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[FancyZones main editor]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[FancyZones ana düzenleyicisi]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Name" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Name]]></Val>

View File

@@ -616,7 +616,7 @@ void FancyZones::ToggleEditor() noexcept
winrt::com_ptr<IZoneWindow> zoneWindow;
std::shared_lock readLock(m_lock);
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, NULL);
@@ -625,7 +625,7 @@ void FancyZones::ToggleEditor() noexcept
{
zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor);
}
if (!zoneWindow)
{
return;
@@ -639,7 +639,8 @@ void FancyZones::ToggleEditor() noexcept
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] {
allMonitors = FancyZonesUtils::GetAllMonitorRects<&MONITORINFOEX::rcWork>();
} }).wait();
} })
.wait();
UINT currentDpi = 0;
for (const auto& monitor : allMonitors)
@@ -650,15 +651,15 @@ void FancyZones::ToggleEditor() noexcept
{
if (currentDpi == 0)
{
currentDpi = dpiX;
continue;
currentDpi = dpiX;
continue;
}
if (currentDpi != dpiX)
{
MessageBoxW(NULL,
GET_RESOURCE_STRING(IDS_SPAN_ACROSS_ZONES_WARNING).c_str(),
GET_RESOURCE_STRING(IDS_POWERTOYS_FANCYZONES).c_str(),
MB_OK | MB_ICONWARNING);
GET_RESOURCE_STRING(IDS_SPAN_ACROSS_ZONES_WARNING).c_str(),
GET_RESOURCE_STRING(IDS_POWERTOYS_FANCYZONES).c_str(),
MB_OK | MB_ICONWARNING);
break;
}
}
@@ -693,8 +694,9 @@ void FancyZones::ToggleEditor() noexcept
mi.cbSize = sizeof(mi);
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] {
GetMonitorInfo(monitor, &mi);
} }).wait();
GetMonitorInfo(monitor, &mi);
} })
.wait();
const auto x = mi.rcWork.left;
const auto y = mi.rcWork.top;
@@ -981,7 +983,7 @@ void FancyZones::UpdateZoneWindows() noexcept
auto callback = [](HMONITOR monitor, HDC, RECT*, LPARAM data) -> BOOL {
capture* params = reinterpret_cast<capture*>(data);
MONITORINFOEX mi{ { .cbSize = sizeof(mi)} };
MONITORINFOEX mi{ { .cbSize = sizeof(mi) } };
if (GetMonitorInfoW(monitor, &mi))
{
auto& displayDeviceIdxMap = *(params->displayDeviceIdx);
@@ -1006,8 +1008,8 @@ void FancyZones::UpdateZoneWindows() noexcept
if (deviceId.empty())
{
deviceId = GetSystemMetrics(SM_REMOTESESSION) ?
L"\\\\?\\DISPLAY#REMOTEDISPLAY#" :
L"\\\\?\\DISPLAY#LOCALDISPLAY#";
L"\\\\?\\DISPLAY#REMOTEDISPLAY#" :
L"\\\\?\\DISPLAY#LOCALDISPLAY#";
fancyZones->AddZoneWindow(monitor, deviceId);
}
@@ -1180,21 +1182,24 @@ bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept
else
{
auto workArea = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor);
auto zoneSet = workArea->ActiveZoneSet();
if (zoneSet)
if (workArea)
{
const auto zones = zoneSet->GetZones();
for (const auto& [zoneId, zone] : zones)
auto zoneSet = workArea->ActiveZoneSet();
if (zoneSet)
{
RECT zoneRect = zone->GetZoneRect();
const auto zones = zoneSet->GetZones();
for (const auto& [zoneId, zone] : zones)
{
RECT zoneRect = zone->GetZoneRect();
zoneRect.left += monitorRect.left;
zoneRect.right += monitorRect.left;
zoneRect.top += monitorRect.top;
zoneRect.bottom += monitorRect.top;
zoneRect.left += monitorRect.left;
zoneRect.right += monitorRect.left;
zoneRect.top += monitorRect.top;
zoneRect.bottom += monitorRect.top;
zoneRects.emplace_back(zoneRect);
zoneRectsInfo.emplace_back(zoneId, workArea);
zoneRects.emplace_back(zoneRect);
zoneRectsInfo.emplace_back(zoneId, workArea);
}
}
}
}
@@ -1224,21 +1229,24 @@ bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept
if (currentMonitorRect.top <= currentMonitorRect.bottom)
{
auto workArea = m_workAreaHandler.GetWorkArea(m_currentDesktopId, current);
auto zoneSet = workArea->ActiveZoneSet();
if (zoneSet)
if (workArea)
{
const auto zones = zoneSet->GetZones();
for (const auto& [zoneId, zone] : zones)
auto zoneSet = workArea->ActiveZoneSet();
if (zoneSet)
{
RECT zoneRect = zone->GetZoneRect();
const auto zones = zoneSet->GetZones();
for (const auto& [zoneId, zone] : zones)
{
RECT zoneRect = zone->GetZoneRect();
zoneRect.left += currentMonitorRect.left;
zoneRect.right += currentMonitorRect.left;
zoneRect.top += currentMonitorRect.top;
zoneRect.bottom += currentMonitorRect.top;
zoneRect.left += currentMonitorRect.left;
zoneRect.right += currentMonitorRect.left;
zoneRect.top += currentMonitorRect.top;
zoneRect.bottom += currentMonitorRect.top;
zoneRects.emplace_back(zoneRect);
zoneRectsInfo.emplace_back(zoneId, workArea);
zoneRects.emplace_back(zoneRect);
zoneRectsInfo.emplace_back(zoneId, workArea);
}
}
}
}
@@ -1351,9 +1359,9 @@ bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept
{
monitor = MonitorFromWindow(GetForegroundWindow(), MONITOR_DEFAULTTONULL);
}
auto zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor);
if (zoneWindow->ActiveZoneSet() != nullptr)
if (zoneWindow && zoneWindow->ActiveZoneSet() != nullptr)
{
if (vkCode == VK_UP || vkCode == VK_DOWN)
{

View File

@@ -307,9 +307,15 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
// Whenever a remap is added move to the bottom of the screen
scrollViewer.ChangeView(nullptr, scrollViewer.ScrollableHeight(), nullptr);
});
// Set accessible name for the addRemapKey button
addRemapKey.SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_ADD_KEY_REMAP_BUTTON)));
// Add tooltip for add button which would appear on hover
ToolTip addRemapKeytoolTip;
addRemapKeytoolTip.Content(box_value(GET_RESOURCE_STRING(IDS_ADD_KEY_REMAP_BUTTON)));
ToolTipService::SetToolTip(addRemapKey, addRemapKeytoolTip);
// Header and example text at the top of the window
StackPanel helperText;
helperText.Children().Append(keyRemapInfoHeader);

View File

@@ -294,9 +294,15 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa
// Whenever a remap is added move to the bottom of the screen
scrollViewer.ChangeView(nullptr, scrollViewer.ScrollableHeight(), nullptr);
});
// Set accessible name for the add shortcut button
addShortcut.SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_ADD_SHORTCUT_BUTTON)));
// Add tooltip for add button which would appear on hover
ToolTip addShortcuttoolTip;
addShortcuttoolTip.Content(box_value(GET_RESOURCE_STRING(IDS_ADD_SHORTCUT_BUTTON)));
ToolTipService::SetToolTip(addShortcut, addShortcuttoolTip);
// Header and example text at the top of the window
StackPanel helperText;
helperText.Children().Append(shortcutRemapInfoHeader);

View File

@@ -105,6 +105,12 @@ void ShortcutControl::AddNewShortcutControlRow(Grid& parent, std::vector<std::ve
targetAppTextBox.PlaceholderText(KeyboardManagerConstants::DefaultAppName);
targetAppTextBox.Text(targetAppName);
// GotFocus handler will be called whenever the user tabs into or clicks on the textbox
targetAppTextBox.GotFocus([targetAppTextBox](auto const& sender, auto const& e) {
// Select all text for accessible purpose
targetAppTextBox.SelectAll();
});
// LostFocus handler will be called whenever text is updated by a user and then they click something else or tab to another control. Does not get called if Text is updated while the TextBox isn't in focus (i.e. from code)
targetAppTextBox.LostFocus([&keyboardRemapControlObjects, parent, targetAppTextBox](auto const& sender, auto const& e) {
// Get index of targetAppTextBox button
@@ -226,8 +232,15 @@ void ShortcutControl::AddNewShortcutControlRow(Grid& parent, std::vector<std::ve
// delete the ShortcutControl objects so that they get destructed
keyboardRemapControlObjects.erase(keyboardRemapControlObjects.begin() + bufferIndex);
});
// To set the accessible name of the delete button
deleteShortcut.SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_DELETE_REMAPPING_BUTTON)));
// Add tooltip for delete button which would appear on hover
ToolTip deleteShortcuttoolTip;
deleteShortcuttoolTip.Content(box_value(GET_RESOURCE_STRING(IDS_DELETE_REMAPPING_BUTTON)));
ToolTipService::SetToolTip(deleteShortcut, deleteShortcuttoolTip);
parent.SetColumn(deleteShortcut, KeyboardManagerConstants::ShortcutTableRemoveColIndex);
parent.SetRow(deleteShortcut, parent.RowDefinitions().Size() - 1);
parent.Children().Append(deleteShortcut);

View File

@@ -176,8 +176,15 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(Grid& parent, std::vector<s
// delete the SingleKeyRemapControl objects so that they get destructed
keyboardRemapControlObjects.erase(keyboardRemapControlObjects.begin() + bufferIndex);
});
// To set the accessible name of the delete button
deleteRemapKeys.SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_DELETE_REMAPPING_BUTTON)));
// Add tooltip for delete button which would appear on hover
ToolTip deleteRemapKeystoolTip;
deleteRemapKeystoolTip.Content(box_value(GET_RESOURCE_STRING(IDS_DELETE_REMAPPING_BUTTON)));
ToolTipService::SetToolTip(deleteRemapKeys, deleteRemapKeystoolTip);
parent.SetColumn(deleteRemapKeys, KeyboardManagerConstants::RemapTableRemoveColIndex);
parent.SetRow(deleteRemapKeys, parent.RowDefinitions().Size() - 1);
parent.Children().Append(deleteRemapKeys);

View File

@@ -21,12 +21,11 @@ namespace Microsoft.Plugin.Folder.Sources.Result
public Wox.Plugin.Result Create(IPublicAPI contextApi)
{
var result = new Wox.Plugin.Result
var result = new Wox.Plugin.Result(StringMatcher.FuzzySearch(Search, Path.GetFileName(FilePath)).MatchData)
{
Title = Title,
SubTitle = string.Format(CultureInfo.CurrentCulture, Properties.Resources.wox_plugin_folder_select_file_result_subtitle, FilePath),
IcoPath = FilePath,
TitleHighlightData = StringMatcher.FuzzySearch(Search, Path.GetFileName(FilePath)).MatchData,
Action = c => ShellAction.Execute(FilePath, contextApi),
ContextData = new SearchResult { Type = ResultType.File, FullPath = FilePath },
};

View File

@@ -33,13 +33,12 @@ namespace Microsoft.Plugin.Folder.Sources.Result
public Wox.Plugin.Result Create(IPublicAPI contextApi)
{
return new Wox.Plugin.Result
return new Wox.Plugin.Result(StringMatcher.FuzzySearch(Search, Title).MatchData)
{
Title = Title,
IcoPath = Path,
SubTitle = string.Format(CultureInfo.CurrentCulture, Properties.Resources.wox_plugin_folder_select_folder_result_subtitle, Subtitle),
QueryTextDisplay = Path,
TitleHighlightData = StringMatcher.FuzzySearch(Search, Title).MatchData,
ContextData = new SearchResult { Type = ResultType.Folder, FullPath = Path },
Action = c => ShellAction.Execute(Path, contextApi),
};

View File

@@ -24,13 +24,12 @@ namespace Microsoft.Plugin.Folder
public Result Create(IPublicAPI contextApi)
{
return new Result
return new Result(StringMatcher.FuzzySearch(Search, Title).MatchData)
{
Title = Title,
IcoPath = Path,
SubTitle = string.Format(CultureInfo.CurrentCulture, Properties.Resources.wox_plugin_folder_select_folder_result_subtitle, Subtitle),
QueryTextDisplay = Path,
TitleHighlightData = StringMatcher.FuzzySearch(Search, Title).MatchData,
ContextData = new SearchResult { Type = ResultType.Folder, FullPath = Path },
Action = c => _shellAction.Execute(Path, contextApi),
};

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Plugin.Program.ProgramArgumentParser;
using Mono.Collections.Generic;
using NUnit.Framework;
using Wox.Plugin;
@@ -34,7 +35,7 @@ namespace Microsoft.Plugin.Program.UnitTests.ProgramArgumentParser
// basic version of the Quey parser which can be found at Wox.Core.Plugin.QueryBuilder but did not want to create a project reference
var splittedSearchString = inputQuery?.Split(Query.TermSeparator, System.StringSplitOptions.RemoveEmptyEntries);
var cleanQuery = string.Join(Query.TermSeparator, splittedSearchString);
var query = new Query(cleanQuery, cleanQuery, splittedSearchString, string.Empty);
var query = new Query(cleanQuery, cleanQuery, new ReadOnlyCollection<string>(splittedSearchString), string.Empty);
// Act
string program = null, programArguments = null;

View File

@@ -19,9 +19,9 @@ namespace Microsoft.Plugin.Program
if (!string.IsNullOrEmpty(query?.Search))
{
// First Argument is always (part of) the program, 2nd term is possibly a Program Argument
if (query.Terms.Length > 1)
if (query.Terms.Count > 1)
{
for (var i = 1; i < query.Terms.Length; i++)
for (var i = 1; i < query.Terms.Count; i++)
{
if (!string.Equals(query.Terms[i], DoubleDash, StringComparison.Ordinal))
{

View File

@@ -19,9 +19,9 @@ namespace Microsoft.Plugin.Program
if (!string.IsNullOrEmpty(query?.Search))
{
// First Argument is always (part of) the program, 2nd term is possibly a Program Argument
if (query.Terms.Length > 1)
if (query.Terms.Count > 1)
{
for (var i = 1; i < query.Terms.Length; i++)
for (var i = 1; i < query.Terms.Count; i++)
{
if (!ArgumentPrefixRegex.IsMatch(query.Terms[i]))
{

View File

@@ -8,6 +8,7 @@ using System.Runtime.InteropServices.ComTypes;
using System.Text;
using Accessibility;
using Microsoft.Plugin.Program.Logger;
using Wox.Plugin.Logger;
namespace Microsoft.Plugin.Program.Programs
{
@@ -131,6 +132,7 @@ namespace Microsoft.Plugin.Program.Programs
public bool HasArguments { get; set; }
// Retrieve the target path using Shell Link
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "HRESULT E_FAIL is thrown while fetching description and E_FAIL does not relate to any specific exception.")]
public string RetrieveTargetPath(string path)
{
var link = new ShellLink();
@@ -160,8 +162,16 @@ namespace Microsoft.Plugin.Program.Programs
if (!string.IsNullOrEmpty(target))
{
buffer = new StringBuilder(MAX_PATH);
((IShellLinkW)link).GetDescription(buffer, MAX_PATH);
Description = buffer.ToString();
try
{
((IShellLinkW)link).GetDescription(buffer, MAX_PATH);
Description = buffer.ToString();
}
catch (Exception e)
{
Log.Exception($"|Failed to fetch description for {target}, {e.Message}", e, GetType());
Description = string.Empty;
}
StringBuilder argumentBuffer = new StringBuilder(MAX_PATH);
((IShellLinkW)link).GetArguments(argumentBuffer, argumentBuffer.Capacity);

View File

@@ -109,7 +109,7 @@ namespace Microsoft.Plugin.Program.Programs
// To set the title to always be the displayname of the packaged application
result.Title = DisplayName;
result.TitleHighlightData = StringMatcher.FuzzySearch(query, Name).MatchData;
result.SetTitleHighlightData(StringMatcher.FuzzySearch(query, Name).MatchData);
var toolTipTitle = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", Properties.Resources.powertoys_run_plugin_program_file_name, result.Title);
var toolTipText = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", Properties.Resources.powertoys_run_plugin_program_file_path, Package.Location);

View File

@@ -233,7 +233,7 @@ namespace Microsoft.Plugin.Program.Programs
// To set the title for the result to always be the name of the application
result.Title = Name;
result.TitleHighlightData = StringMatcher.FuzzySearch(query, Name).MatchData;
result.SetTitleHighlightData(StringMatcher.FuzzySearch(query, Name).MatchData);
var toolTipTitle = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", Properties.Resources.powertoys_run_plugin_program_file_name, result.Title);
var toolTipText = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", Properties.Resources.powertoys_run_plugin_program_file_path, FullPath);

View File

@@ -32,5 +32,10 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers">
<Version>3.3.0</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -40,7 +40,7 @@ namespace Microsoft.Plugin.Uri.UnitTests.UriHelper
[TestCase("[::]", true, "http://[::]/")]
[TestCase("[2001:0DB8::1]", true, "http://[2001:db8::1]/")]
[TestCase("[2001:0DB8::1]:80", true, "http://[2001:db8::1]/")]
public void TryParse_CanParseHostName(string query, bool expectedSuccess, string expectedResult)
public void TryParseCanParseHostName(string query, bool expectedSuccess, string expectedResult)
{
// Arrange
var parser = new ExtendedUriParser();

View File

@@ -78,10 +78,10 @@ namespace Wox.Core.Plugin
metadata.PluginDirectory = pluginDirectory;
// for plugins which doesn't has ActionKeywords key
metadata.ActionKeywords = metadata.ActionKeywords ?? new List<string> { metadata.ActionKeyword };
metadata.SetActionKeywords(metadata.GetActionKeywords() ?? new List<string> { metadata.ActionKeyword });
// for plugin still use old ActionKeyword
metadata.ActionKeyword = metadata.ActionKeywords?[0];
metadata.ActionKeyword = metadata.GetActionKeywords()?[0];
}
catch (Exception e)
{

View File

@@ -125,7 +125,7 @@ namespace Wox.Core.Plugin
}
// Plugins may have multiple ActionKeywords, eg. WebSearch
plugin.Metadata.ActionKeywords.Where(x => x != Query.GlobalPluginWildcardSign)
plugin.Metadata.GetActionKeywords().Where(x => x != Query.GlobalPluginWildcardSign)
.ToList()
.ForEach(x => NonGlobalPlugins[x] = plugin);
}
@@ -244,7 +244,7 @@ namespace Wox.Core.Plugin
private static bool IsGlobalPlugin(PluginMetadata metadata)
{
return metadata.ActionKeywords.Contains(Query.GlobalPluginWildcardSign);
return metadata.GetActionKeywords().Contains(Query.GlobalPluginWildcardSign);
}
/// <summary>
@@ -258,7 +258,6 @@ namespace Wox.Core.Plugin
}
public static IEnumerable<PluginPair> GetPluginsForInterface<T>()
where T : IFeatures
{
return AllPlugins.Where(p => p.Plugin is T);
}
@@ -320,7 +319,7 @@ namespace Wox.Core.Plugin
NonGlobalPlugins[newActionKeyword] = plugin;
}
plugin.Metadata.ActionKeywords.Add(newActionKeyword);
plugin.Metadata.GetActionKeywords().Add(newActionKeyword);
}
/// <summary>
@@ -332,7 +331,7 @@ namespace Wox.Core.Plugin
var plugin = GetPluginForId(id);
if (oldActionkeyword == Query.GlobalPluginWildcardSign
&& // Plugins may have multiple ActionKeywords that are global, eg. WebSearch
plugin.Metadata.ActionKeywords
plugin.Metadata.GetActionKeywords()
.Where(x => x == Query.GlobalPluginWildcardSign)
.ToList()
.Count == 1)
@@ -345,7 +344,7 @@ namespace Wox.Core.Plugin
NonGlobalPlugins.Remove(oldActionkeyword);
}
plugin.Metadata.ActionKeywords.Remove(oldActionkeyword);
plugin.Metadata.GetActionKeywords().Remove(oldActionkeyword);
}
public static void ReplaceActionKeyword(string id, string oldActionKeyword, string newActionKeyword)

View File

@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Collections.Generic;
using Wox.Plugin;
namespace Wox.Core.Plugin
@@ -63,7 +64,7 @@ namespace Wox.Core.Plugin
}
// A new query is constructed for each plugin as they have different action keywords
var query = new Query(rawQuery, search, terms, pluginActionKeyword);
var query = new Query(rawQuery, search, new ReadOnlyCollection<string>(terms), pluginActionKeyword);
pluginQueryPair.TryAdd(pluginPair, query);
}
@@ -80,7 +81,7 @@ namespace Wox.Core.Plugin
{
if (!pluginQueryPair.ContainsKey(globalPlugin))
{
var query = new Query(rawQuery, rawQuery, terms, string.Empty);
var query = new Query(rawQuery, rawQuery, new ReadOnlyCollection<string>(terms), string.Empty);
pluginQueryPair.Add(globalPlugin, query);
}
}

View File

@@ -20,7 +20,7 @@ namespace Wox.Infrastructure.UserSettings
var settings = Plugins[metadata.ID];
if (settings.ActionKeywords?.Count > 0)
{
metadata.ActionKeywords = settings.ActionKeywords;
metadata.SetActionKeywords(settings.ActionKeywords);
metadata.ActionKeyword = settings.ActionKeywords[0];
}
@@ -32,7 +32,7 @@ namespace Wox.Infrastructure.UserSettings
{
ID = metadata.ID,
Name = metadata.Name,
ActionKeywords = metadata.ActionKeywords,
ActionKeywords = metadata.GetActionKeywords(),
Disabled = metadata.Disabled,
};
}

View File

@@ -2,6 +2,9 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Globalization;
namespace Wox.Plugin
{
public static class AllowedLanguage
@@ -18,8 +21,14 @@ namespace Wox.Plugin
public static bool IsAllowed(string language)
{
return language.ToUpper() == CSharp.ToUpper()
|| language.ToUpper() == Executable.ToUpper();
if (language == null)
{
throw new ArgumentNullException(nameof(language));
}
// Using InvariantCulture since this is a command line arg
return language.ToUpper(CultureInfo.InvariantCulture) == CSharp.ToUpper(CultureInfo.InvariantCulture)
|| language.ToUpper(CultureInfo.InvariantCulture) == Executable.ToUpper(CultureInfo.InvariantCulture);
}
}
}

View File

@@ -6,11 +6,7 @@ using System.Collections.Generic;
namespace Wox.Plugin
{
public interface IFeatures
{
}
public interface IContextMenu : IFeatures
public interface IContextMenu
{
List<ContextMenuResult> LoadContextMenus(Result selectedResult);
}
@@ -18,14 +14,14 @@ namespace Wox.Plugin
/// <summary>
/// Represent plugins that support internationalization
/// </summary>
public interface IPluginI18n : IFeatures
public interface IPluginI18n
{
string GetTranslatedPluginTitle();
string GetTranslatedPluginDescription();
}
public interface IResultUpdated : IFeatures
public interface IResultUpdated
{
event ResultUpdatedEventHandler ResultsUpdated;
}

View File

@@ -6,7 +6,7 @@ using System.Collections.Generic;
namespace Wox.Plugin
{
public interface IDelayedExecutionPlugin : IFeatures
public interface IDelayedExecutionPlugin
{
List<Result> Query(Query query, bool delayedExecution);
}

View File

@@ -0,0 +1,14 @@
{
"Projects": [
{
"LanguageSet": "Azure_Languages",
"LocItems": [
{
"SourceFile": "src\\modules\\launcher\\Wox.Plugin\\Properties\\Resources.resx",
"CopyOption": "LangIDOnName",
"OutputPath": "src\\modules\\launcher\\Wox.Plugin\\Properties"
}
]
}
]
}

View File

@@ -14,6 +14,13 @@ namespace Wox.Plugin
{
private string _pluginDirectory;
private List<string> _actionKeywords;
public PluginMetadata(List<string> actionKeywords = null)
{
_actionKeywords = actionKeywords;
}
public string ID { get; set; }
public string Name { get; set; }
@@ -51,7 +58,15 @@ namespace Wox.Plugin
public string ActionKeyword { get; set; }
public List<string> ActionKeywords { get; set; }
public List<string> GetActionKeywords()
{
return _actionKeywords;
}
public void SetActionKeywords(List<string> value)
{
_actionKeywords = value;
}
public string IcoPath { get; set; }

View File

@@ -2,6 +2,8 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Wox.Plugin
{
public class PluginPair
@@ -19,7 +21,8 @@ namespace Wox.Plugin
{
if (obj is PluginPair r)
{
return string.Equals(r.Metadata.ID, Metadata.ID);
// Using Ordinal since this is used internally
return string.Equals(r.Metadata.ID, Metadata.ID, StringComparison.Ordinal);
}
else
{
@@ -29,7 +32,8 @@ namespace Wox.Plugin
public override int GetHashCode()
{
var hashcode = Metadata.ID?.GetHashCode() ?? 0;
// Using Ordinal since this is used internally
var hashcode = Metadata.ID?.GetHashCode(StringComparison.Ordinal) ?? 0;
return hashcode;
}
}

View File

@@ -0,0 +1,90 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Wox.Plugin.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Wox.Plugin.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Copying path {0} has failed, it will now be deleted for consistency.
/// </summary>
public static string filesfolder_copy_failed {
get {
return ResourceManager.GetString("filesfolder_copy_failed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Not able to delete folder {0}, please go to the location and manually delete it.
/// </summary>
public static string filesfolder_removefolder_failed {
get {
return ResourceManager.GetString("filesfolder_removefolder_failed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unable to verify folders and files between {0} and {1}.
/// </summary>
public static string filesfolder_verifybothfolderfilesequal_failed {
get {
return ResourceManager.GetString("filesfolder_verifybothfolderfilesequal_failed", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="filesfolder_copy_failed" xml:space="preserve">
<value>Copying path {0} has failed, it will now be deleted for consistency</value>
<comment>parameter: targetPath</comment>
</data>
<data name="filesfolder_removefolder_failed" xml:space="preserve">
<value>Not able to delete folder {0}, please go to the location and manually delete it</value>
<comment>parameter: path</comment>
</data>
<data name="filesfolder_verifybothfolderfilesequal_failed" xml:space="preserve">
<value>Unable to verify folders and files between {0} and {1}</value>
<comment>paramaters: fromPath, toPath</comment>
</data>
</root>

View File

@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Collections.Generic;
namespace Wox.Plugin
{
@@ -18,7 +19,7 @@ namespace Wox.Plugin
/// Initializes a new instance of the <see cref="Query"/> class.
/// to allow unit tests for plug ins
/// </summary>
public Query(string rawQuery, string search, string[] terms, string actionKeyword = "")
public Query(string rawQuery, string search, ReadOnlyCollection<string> terms, string actionKeyword = "")
{
Search = search;
RawQuery = rawQuery;
@@ -41,9 +42,9 @@ namespace Wox.Plugin
public string Search { get; internal set; }
/// <summary>
/// Gets or sets the raw query splited into a string array.
/// Gets the raw query splited into a string array.
/// </summary>
public string[] Terms { get; set; }
public ReadOnlyCollection<string> Terms { get; private set; }
/// <summary>
/// Query can be splited into multiple terms by whitespace

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Windows;
using System.Windows.Media;
@@ -16,6 +17,7 @@ namespace Wox.Plugin
private ToolTipData _toolTipData;
private string _pluginDirectory;
private string _icoPath;
private IList<int> _titleHighlightData;
public string Title
{
@@ -26,7 +28,13 @@ namespace Wox.Plugin
set
{
_title = value.Replace("\n", " ");
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
// Using Ordinal since this is used internally
_title = value.Replace("\n", " ", StringComparison.Ordinal);
}
}
@@ -90,15 +98,32 @@ namespace Wox.Plugin
public int Score { get; set; }
/// <summary>
/// Gets or sets a list of indexes for the characters to be highlighted in Title
/// </summary>
public IList<int> TitleHighlightData { get; set; }
public Result(IList<int> titleHighlightData = null, IList<int> subTitleHighlightData = null)
{
_titleHighlightData = titleHighlightData;
SubTitleHighlightData = subTitleHighlightData;
}
/// <summary>
/// Gets or sets a list of indexes for the characters to be highlighted in SubTitle
/// Gets a list of indexes for the characters to be highlighted in Title
/// </summary>
public IList<int> SubTitleHighlightData { get; set; }
public IList<int> GetTitleHighlightData()
{
return _titleHighlightData;
}
/// <summary>
/// Sets a list of indexes for the characters to be highlighted in Title
/// </summary>
public void SetTitleHighlightData(IList<int> value)
{
_titleHighlightData = value;
}
/// <summary>
/// Gets a list of indexes for the characters to be highlighted in SubTitle
/// </summary>
public IList<int> SubTitleHighlightData { get; private set; }
/// <summary>
/// Gets or sets only results that originQuery match with current query will be displayed in the panel
@@ -129,10 +154,11 @@ namespace Wox.Plugin
{
var r = obj as Result;
var equality = string.Equals(r?.Title, Title) &&
string.Equals(r?.SubTitle, SubTitle) &&
string.Equals(r?.IcoPath, IcoPath) &&
TitleHighlightData == r.TitleHighlightData &&
// Using Ordinal since this is used internally
var equality = string.Equals(r?.Title, Title, StringComparison.Ordinal) &&
string.Equals(r?.SubTitle, SubTitle, StringComparison.Ordinal) &&
string.Equals(r?.IcoPath, IcoPath, StringComparison.Ordinal) &&
GetTitleHighlightData() == r.GetTitleHighlightData() &&
SubTitleHighlightData == r.SubTitleHighlightData;
return equality;
@@ -140,18 +166,16 @@ namespace Wox.Plugin
public override int GetHashCode()
{
var hashcode = (Title?.GetHashCode() ?? 0) ^
(SubTitle?.GetHashCode() ?? 0);
// Using Ordinal since this is used internally
var hashcode = (Title?.GetHashCode(StringComparison.Ordinal) ?? 0) ^
(SubTitle?.GetHashCode(StringComparison.Ordinal) ?? 0);
return hashcode;
}
public override string ToString()
{
return string.Format("{0} : {1}", Title, SubTitle);
}
public Result()
{
// Using CurrentCulture since this is user facing
return string.Format(CultureInfo.CurrentCulture, "{0} : {1}", Title, SubTitle);
}
/// <summary>

View File

@@ -9,7 +9,12 @@ namespace Wox.Plugin
{
public class ResultUpdatedEventArgs : EventArgs
{
public List<Result> Results { get; set; }
public List<Result> Results { get; private set; }
public ResultUpdatedEventArgs(List<Result> results = null)
{
Results = results;
}
public Query Query { get; set; }
}

View File

@@ -3,9 +3,11 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using Wox.Plugin.Logger;
using Wox.Plugin.Properties;
namespace Wox.Plugin.SharedCommands
{
@@ -56,9 +58,10 @@ namespace Wox.Plugin.SharedCommands
string error = $"Copying path {targetPath} has failed";
Log.Exception(error, e, MethodBase.GetCurrentMethod().DeclaringType);
#if DEBUG
throw e;
throw;
#else
System.Windows.MessageBox.Show(string.Format("Copying path {0} has failed, it will now be deleted for consistency", targetPath));
// Using CurrentCulture since this is user facing
System.Windows.MessageBox.Show(string.Format(CultureInfo.CurrentCulture, Resources.filesfolder_copy_failed, targetPath));
RemoveFolder(targetPath);
#endif
}
@@ -91,9 +94,10 @@ namespace Wox.Plugin.SharedCommands
string error = $"Unable to verify folders and files between {fromPath} and {toPath}";
Log.Exception(error, e, MethodBase.GetCurrentMethod().DeclaringType);
#if DEBUG
throw e;
throw;
#else
System.Windows.MessageBox.Show(string.Format(error));
// Using CurrentCulture since this is user facing
System.Windows.MessageBox.Show(string.Format(CultureInfo.CurrentCulture, Resources.filesfolder_verifybothfolderfilesequal_failed, fromPath, toPath));
return false;
#endif
}
@@ -113,12 +117,13 @@ namespace Wox.Plugin.SharedCommands
catch (Exception e)
#pragma warning restore CS0168 // Variable is declared but never used
{
string error = $"Not able to delete folder {path}, please go to the location and manually delete it";
string error = $"Not able to delete folder {path}";
Log.Exception(error, e, MethodBase.GetCurrentMethod().DeclaringType);
#if DEBUG
throw e;
throw;
#else
System.Windows.MessageBox.Show(string.Format(error));
// Using CurrentCulture since this is user facing
System.Windows.MessageBox.Show(string.Format(CultureInfo.CurrentCulture, Resources.filesfolder_removefolder_failed, path));
#endif
}
}

View File

@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
using System.Text;
using static Wox.Plugin.SharedCommands.ShellCommand;
namespace Wox.Plugin.SharedCommands
{
internal static class NativeMethods
{
[DllImport("user32.dll")]
public static extern bool EnumThreadWindows(uint threadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
public static extern int GetWindowTextLength(IntPtr hwnd);
}
}

View File

@@ -15,8 +15,13 @@ namespace Wox.Plugin.SharedCommands
/// Opens search in a new browser. If no browser path is passed in then Chrome is used.
/// Leave browser path blank to use Chrome.
/// </summary>
public static void NewBrowserWindow(this string url, string browserPath)
public static void NewBrowserWindow(this Uri url, string browserPath)
{
if (url == null)
{
throw new ArgumentNullException(nameof(url));
}
var browserExecutableName = browserPath?
.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.None)
.Last();
@@ -24,7 +29,7 @@ namespace Wox.Plugin.SharedCommands
var browser = string.IsNullOrEmpty(browserExecutableName) ? "chrome" : browserPath;
// Internet Explorer will open url in new browser window, and does not take the --new-window parameter
var browserArguments = browserExecutableName == "iexplore.exe" ? url : "--new-window " + url;
var browserArguments = browserExecutableName == "iexplore.exe" ? url.AbsoluteUri : "--new-window " + url.AbsoluteUri;
try
{
@@ -34,7 +39,7 @@ namespace Wox.Plugin.SharedCommands
{
var psi = new ProcessStartInfo
{
FileName = url,
FileName = url.AbsoluteUri,
UseShellExecute = true,
};
Process.Start(psi);
@@ -44,24 +49,29 @@ namespace Wox.Plugin.SharedCommands
/// <summary>
/// Opens search as a tab in the default browser chosen in Windows settings.
/// </summary>
public static void NewTabInBrowser(this string url, string browserPath)
public static void NewTabInBrowser(this Uri url, string browserPath)
{
if (url == null)
{
throw new ArgumentNullException(nameof(url));
}
try
{
if (!string.IsNullOrEmpty(browserPath))
{
Process.Start(browserPath, url);
Process.Start(browserPath, url.AbsoluteUri);
}
else
{
Process.Start(url);
Process.Start(url.AbsoluteUri);
}
}
// This error may be thrown for Process.Start(browserPath, url)
catch (System.ComponentModel.Win32Exception)
{
Process.Start(url);
Process.Start(url.AbsoluteUri);
}
}
}

View File

@@ -4,7 +4,6 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
@@ -14,19 +13,15 @@ namespace Wox.Plugin.SharedCommands
{
public delegate bool EnumThreadDelegate(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(uint threadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
private static extern int GetWindowTextLength(IntPtr hwnd);
private static bool containsSecurityWindow;
public static Process RunAsDifferentUser(ProcessStartInfo processStartInfo)
{
if (processStartInfo == null)
{
throw new ArgumentNullException(nameof(processStartInfo));
}
processStartInfo.Verb = "RunAsUser";
var process = Process.Start(processStartInfo);
@@ -55,7 +50,7 @@ namespace Wox.Plugin.SharedCommands
ProcessThreadCollection ptc = Process.GetCurrentProcess().Threads;
for (int i = 0; i < ptc.Count; i++)
{
EnumThreadWindows((uint)ptc[i].Id, CheckSecurityThread, IntPtr.Zero);
NativeMethods.EnumThreadWindows((uint)ptc[i].Id, CheckSecurityThread, IntPtr.Zero);
}
}
@@ -71,8 +66,8 @@ namespace Wox.Plugin.SharedCommands
private static string GetWindowTitle(IntPtr hwnd)
{
StringBuilder sb = new StringBuilder(GetWindowTextLength(hwnd) + 1);
GetWindowText(hwnd, sb, sb.Capacity);
StringBuilder sb = new StringBuilder(NativeMethods.GetWindowTextLength(hwnd) + 1);
_ = NativeMethods.GetWindowText(hwnd, sb, sb.Capacity);
return sb.ToString();
}

View File

@@ -22,7 +22,7 @@ namespace Wox.Plugin
private const string HighContrastWhiteTheme = "HighContrast.Accent5";
private Theme currentTheme;
private bool _disposed = false;
private bool _disposed;
public event ThemeChangedHandler ThemeChanged;

View File

@@ -16,7 +16,7 @@ namespace Wox.Plugin
{
if (string.IsNullOrEmpty(title))
{
throw new ArgumentException("title cannot be null or empty", "title");
throw new ArgumentException("title cannot be null or empty", nameof(title));
}
Title = title;

View File

@@ -13,6 +13,7 @@
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<Platforms>x64</Platforms>
<NeutralLanguage>en-US</NeutralLanguage>
</PropertyGroup>
@@ -68,6 +69,10 @@
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
<PackageReference Include="MahApps.Metro" Version="2.3.0" />
<PackageReference Include="ControlzEx" Version="4.3.2" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Mono.Cecil" Version="0.11.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.6.5" />
@@ -96,4 +101,17 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using Mono.Collections.Generic;
using NUnit.Framework;
using Wox.Core.Plugin;
using Wox.Plugin;
@@ -26,7 +27,7 @@ namespace Wox.Test
// Arrange
var nonGlobalPlugins = new Dictionary<string, PluginPair>
{
{ ">", new PluginPair { Metadata = new PluginMetadata { ActionKeywords = new List<string> { ">" } } } },
{ ">", new PluginPair { Metadata = new PluginMetadata(new List<string> { ">" } ) } },
};
string searchQuery = "> file.txt file2 file3";
@@ -43,7 +44,7 @@ namespace Wox.Test
// Arrange
var nonGlobalPlugins = new Dictionary<string, PluginPair>
{
{ ">", new PluginPair { Metadata = new PluginMetadata { ActionKeywords = new List<string> { ">" }, Disabled = true } } },
{ ">", new PluginPair { Metadata = new PluginMetadata(new List<string> { ">" }) { Disabled = true } } },
};
string searchQuery = "> file.txt file2 file3";
@@ -72,7 +73,7 @@ namespace Wox.Test
{
// Arrange
string searchQuery = "> query";
var firstPlugin = new PluginPair { Metadata = new PluginMetadata { ActionKeywords = new List<string> { ">" } } };
var firstPlugin = new PluginPair { Metadata = new PluginMetadata(new List<string> { ">" } ) };
var secondPlugin = new PluginPair { Metadata = new PluginMetadata { ActionKeyword = ">" } };
var nonGlobalPluginWithActionKeywords = new Dictionary<string, PluginPair>
@@ -85,7 +86,7 @@ namespace Wox.Test
{ ">", secondPlugin },
};
string[] terms = { ">", "query" };
Query expectedQuery = new Query("> query", "query", terms, ">");
Query expectedQuery = new Query("> query", "query", new ReadOnlyCollection<string>(terms), ">");
// Act
var queriesForPluginsWithActionKeywords = QueryBuilder.Build(ref searchQuery, nonGlobalPluginWithActionKeywords);
@@ -103,7 +104,7 @@ namespace Wox.Test
public void QueryBuilderShouldGenerateCorrectQueriesForPluginsWithMultipleActionKeywords()
{
// Arrange
var plugin = new PluginPair { Metadata = new PluginMetadata { ActionKeywords = new List<string> { "a", "b" } } };
var plugin = new PluginPair { Metadata = new PluginMetadata(new List<string> { "a", "b" } ) };
var nonGlobalPlugins = new Dictionary<string, PluginPair>
{
{ "a", plugin },
@@ -129,7 +130,7 @@ namespace Wox.Test
public void QueryBuildShouldGenerateSameSearchQueryWithOrWithoutSpaceAfterActionKeyword()
{
// Arrange
var plugin = new PluginPair { Metadata = new PluginMetadata { ActionKeywords = new List<string> { "a" } } };
var plugin = new PluginPair { Metadata = new PluginMetadata(new List<string> { "a" } ) };
var nonGlobalPlugins = new Dictionary<string, PluginPair>
{
{ "a", plugin },
@@ -198,8 +199,8 @@ namespace Wox.Test
// Assert
// Using Ordinal since this is used internally
Assert.IsTrue(firstQuery.Terms[0].Equals("cd", StringComparison.Ordinal) && firstQuery.Terms[1].Equals("efgh", StringComparison.Ordinal) && firstQuery.Terms.Length == 2);
Assert.IsTrue(secondQuery.Terms[0].Equals("efgh", StringComparison.Ordinal) && secondQuery.Terms.Length == 1);
Assert.IsTrue(firstQuery.Terms[0].Equals("cd", StringComparison.Ordinal) && firstQuery.Terms[1].Equals("efgh", StringComparison.Ordinal) && firstQuery.Terms.Count == 2);
Assert.IsTrue(secondQuery.Terms[0].Equals("efgh", StringComparison.Ordinal) && secondQuery.Terms.Count == 1);
}
}
}

View File

@@ -40,8 +40,8 @@
<Item ItemId=";FileExplorer_Admin_Restart_Warning_Description" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Some of the File Explorer modules could not be turned off/on as per your settings. Please restart PowerToys as admin for the changes to take place.]]></Val>
<Tgt Cat="Text" Stat="Update" Orig="New">
<Val><![CDATA[Einige der Datei-Explorer-Module konnten gemäß Ihren Einstellungen nicht registriert bzw. aus der Registrierung entfernt werden. Starten Sie PowerToys als Administrator neu, damit die Änderungen ausgeführt werden können.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Einige der Datei-Explorer-Module konnten gemäß Ihren Einstellungen nicht aktiviert bzw. deaktiviert werden. Starten Sie PowerToys als Administrator neu, damit die Änderungen ausgeführt werden können.]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Some of the File Explorer modules could not be registered/unregistered as per your settings. Please restart PowerToys as admin for the changes to take place.]]></Val>
@@ -70,8 +70,8 @@
<Item ItemId=";FileExplorer_Admin_Restart_Warning_Title" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Couldn't modify File Explorer modules]]></Val>
<Tgt Cat="Text" Stat="Update" Orig="New">
<Val><![CDATA[Fehler beim Ändern der Datei-Explorer-Module.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Fehler beim Ändern von Datei-Explorer-Modulen]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Failed to modify File Explorer modules]]></Val>

View File

@@ -40,8 +40,8 @@
<Item ItemId=";FileExplorer_Admin_Restart_Warning_Description" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Some of the File Explorer modules could not be turned off/on as per your settings. Please restart PowerToys as admin for the changes to take place.]]></Val>
<Tgt Cat="Text" Stat="Update" Orig="New">
<Val><![CDATA[No se pudieron registrar algunos módulos del Explorador de archivos, o no se pudo anular su registro, según la configuración. Reinicie PowerToys como administrador para que los cambios se apliquen.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[No se pudieron activar o desactivar algunos módulos del Explorador de archivos según la configuración. Reinicie PowerToys como administrador para que los cambios se apliquen.]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Some of the File Explorer modules could not be registered/unregistered as per your settings. Please restart PowerToys as admin for the changes to take place.]]></Val>
@@ -70,7 +70,7 @@
<Item ItemId=";FileExplorer_Admin_Restart_Warning_Title" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Couldn't modify File Explorer modules]]></Val>
<Tgt Cat="Text" Stat="Update" Orig="New">
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[No se pudieron modificar los módulos del Explorador de archivos]]></Val>
</Tgt>
<Prev Cat="Text">

View File

@@ -40,8 +40,8 @@
<Item ItemId=";FileExplorer_Admin_Restart_Warning_Description" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Some of the File Explorer modules could not be turned off/on as per your settings. Please restart PowerToys as admin for the changes to take place.]]></Val>
<Tgt Cat="Text" Stat="Update" Orig="New">
<Val><![CDATA[Impossible d'inscrire/de désinscrire certains modules de l'Explorateur de fichiers selon vos paramètres. Redémarrez PowerToys comme administrateur pour appliquer les changements.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Impossible de désactiver/d'activer certains modules de l'Explorateur de fichiers selon vos paramètres. Redémarrez PowerToys comme administrateur pour appliquer les changements.]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Some of the File Explorer modules could not be registered/unregistered as per your settings. Please restart PowerToys as admin for the changes to take place.]]></Val>
@@ -70,8 +70,8 @@
<Item ItemId=";FileExplorer_Admin_Restart_Warning_Title" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Couldn't modify File Explorer modules]]></Val>
<Tgt Cat="Text" Stat="Update" Orig="New">
<Val><![CDATA[La modification des modules de l'Explorateur de fichiers a échoué]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Impossible de modifier les modules de l'Explorateur de fichiers]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Failed to modify File Explorer modules]]></Val>

View File

@@ -40,8 +40,8 @@
<Item ItemId=";FileExplorer_Admin_Restart_Warning_Description" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Some of the File Explorer modules could not be turned off/on as per your settings. Please restart PowerToys as admin for the changes to take place.]]></Val>
<Tgt Cat="Text" Stat="Update" Orig="New">
<Val><![CDATA[Een aantal modules van Bestandenverkenner kunnen niet worden geregistreerd/uitgeschreven vanwege uw instellingen. Start PowerToys opnieuw als beheerder om de wijzigingen door te voeren.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Een aantal modules van Bestandenverkenner kunnen niet worden in-/uitgeschakeld vanwege uw instellingen. Start PowerToys opnieuw als beheerder om de wijzigingen door te voeren.]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Some of the File Explorer modules could not be registered/unregistered as per your settings. Please restart PowerToys as admin for the changes to take place.]]></Val>
@@ -70,7 +70,7 @@
<Item ItemId=";FileExplorer_Admin_Restart_Warning_Title" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Couldn't modify File Explorer modules]]></Val>
<Tgt Cat="Text" Stat="Update" Orig="New">
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Kan de modules van Bestandenverkenner niet wijzigen]]></Val>
</Tgt>
<Prev Cat="Text">

View File

@@ -40,8 +40,8 @@
<Item ItemId=";FileExplorer_Admin_Restart_Warning_Description" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Some of the File Explorer modules could not be turned off/on as per your settings. Please restart PowerToys as admin for the changes to take place.]]></Val>
<Tgt Cat="Text" Stat="Update" Orig="New">
<Val><![CDATA[Não foi possível registrar/cancelar o registro de alguns dos módulos do Explorador de Arquivos de acordo com as configurações. Reinicie os PowerToys como administrador para que as alterações entrem em vigor.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Não foi possível ativar/desativar alguns dos módulos do Explorador de Arquivos de acordo com as configurações. Reinicie o PowerToys como administrador para que as alterações entrem em vigor.]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Some of the File Explorer modules could not be registered/unregistered as per your settings. Please restart PowerToys as admin for the changes to take place.]]></Val>
@@ -70,7 +70,7 @@
<Item ItemId=";FileExplorer_Admin_Restart_Warning_Title" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Couldn't modify File Explorer modules]]></Val>
<Tgt Cat="Text" Stat="Update" Orig="New">
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Falha ao modificar os módulos do Explorador de Arquivos]]></Val>
</Tgt>
<Prev Cat="Text">

View File

@@ -40,8 +40,8 @@
<Item ItemId=";FileExplorer_Admin_Restart_Warning_Description" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Some of the File Explorer modules could not be turned off/on as per your settings. Please restart PowerToys as admin for the changes to take place.]]></Val>
<Tgt Cat="Text" Stat="Update" Orig="New">
<Val><![CDATA[Bazı Dosya Gezgini modülleri, ayarlarınıza göre kaydedilemedi/kaydı silinemedi. Değişikliklerin geçerli olması için lütfen PowerToys'u yönetici olarak yeniden başlatın.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Bazı Dosya Gezgini modülleri, ayarlarınıza göre devre dışı bırakılamadı/etkinleştirilemedi. Değişikliklerin geçerli olması için lütfen PowerToys'u yönetici olarak yeniden başlatın.]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Some of the File Explorer modules could not be registered/unregistered as per your settings. Please restart PowerToys as admin for the changes to take place.]]></Val>
@@ -70,7 +70,7 @@
<Item ItemId=";FileExplorer_Admin_Restart_Warning_Title" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Couldn't modify File Explorer modules]]></Val>
<Tgt Cat="Text" Stat="Update" Orig="New">
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Dosya Gezgini modülleri değiştirilemedi]]></Val>
</Tgt>
<Prev Cat="Text">