Skip to content
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
91 changes: 91 additions & 0 deletions Source/NETworkManager.Utilities.WPF/PermissionToolTipHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System.Windows;
using System.Windows.Controls;

namespace NETworkManager.Utilities.WPF;

/// <summary>
/// Attached-property helper to show a hint (e.g. "requires elevated rights") as tooltip on a control,
/// which is disabled because the application is missing a permission (e.g. not running as administrator).
/// The tooltip is also shown while the control is disabled and only if <see cref="HasPermissionProperty"/>
/// is <see langword="false"/>. An existing tooltip of the control is never overwritten.
/// </summary>
public static class PermissionToolTipHelper
{
/// <summary>
/// Resource key of the tooltip style (limits the width and wraps long text).
/// Defined in "Resources/Styles/ToolTipStyles.xaml" of the application.
/// </summary>
private const string ToolTipStyleKey = "WrapToolTip";

/// <summary>
/// Text of the tooltip, which is shown if the permission is missing.
/// </summary>
public static readonly DependencyProperty TextProperty =
DependencyProperty.RegisterAttached(
"Text",
typeof(string),
typeof(PermissionToolTipHelper),
new PropertyMetadata(null, OnChanged));

public static void SetText(FrameworkElement element, string value) =>
element.SetValue(TextProperty, value);

public static string GetText(FrameworkElement element) =>
(string)element.GetValue(TextProperty);

/// <summary>
/// Indicates whether the permission is available (e.g. running as administrator).
/// Defaults to <see langword="true"/>, so no tooltip is shown until the binding is resolved.
/// </summary>
public static readonly DependencyProperty HasPermissionProperty =
DependencyProperty.RegisterAttached(
"HasPermission",
typeof(bool),
typeof(PermissionToolTipHelper),
new PropertyMetadata(true, OnChanged));

public static void SetHasPermission(FrameworkElement element, bool value) =>
element.SetValue(HasPermissionProperty, value);

public static bool GetHasPermission(FrameworkElement element) =>
(bool)element.GetValue(HasPermissionProperty);

/// <summary>
/// Indicates whether the tooltip was set by this helper (to only clear our own tooltip).
/// </summary>
private static readonly DependencyProperty IsAppliedProperty =
DependencyProperty.RegisterAttached(
"IsApplied",
typeof(bool),
typeof(PermissionToolTipHelper),
new PropertyMetadata(false));

private static void OnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not FrameworkElement element)
return;

var text = GetText(element);
var isApplied = (bool)element.GetValue(IsAppliedProperty);

if (!GetHasPermission(element) && !string.IsNullOrEmpty(text))
{
// Don't overwrite a tooltip that was set on the control itself
if (!isApplied && element.ToolTip != null)
return;

var toolTip = new ToolTip { Content = text };
toolTip.SetResourceReference(FrameworkElement.StyleProperty, ToolTipStyleKey);

element.ToolTip = toolTip;
ToolTipService.SetShowOnDisabled(element, true);
element.SetValue(IsAppliedProperty, true);
}
else if (isApplied)
{
element.ClearValue(FrameworkElement.ToolTipProperty);
element.ClearValue(ToolTipService.ShowOnDisabledProperty);
element.SetValue(IsAppliedProperty, false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@

<Style x:Key="ErrorImageRectangle" TargetType="{x:Type Rectangle}">
<Style.Resources>
<Style TargetType="{x:Type ToolTip}" BasedOn="{StaticResource DefaultToolTip}" />
<Style TargetType="{x:Type ToolTip}" BasedOn="{StaticResource ErrorToolTip}" />
</Style.Resources>
<Setter Property="Fill" Value="#b95353" />
<Setter Property="OpacityMask">
Expand Down
5 changes: 4 additions & 1 deletion Source/NETworkManager/Resources/Styles/ToolTipStyles.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

<Style TargetType="{x:Type TypeName=ToolTip}" BasedOn="{StaticResource ResourceKey=DefaultToolTip}" />

<Style x:Key="HelpToolTip" TargetType="{x:Type TypeName=ToolTip}" BasedOn="{StaticResource ResourceKey=DefaultToolTip}">
<!-- Generic tooltip for (long) text, limits the width and wraps the text -->
<Style x:Key="WrapToolTip" TargetType="{x:Type TypeName=ToolTip}" BasedOn="{StaticResource ResourceKey=DefaultToolTip}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TypeName=ToolTip}">
Expand Down Expand Up @@ -53,6 +54,8 @@
</Setter>
</Style>

<Style x:Key="HelpToolTip" TargetType="{x:Type TypeName=ToolTip}" BasedOn="{StaticResource ResourceKey=WrapToolTip}" />

<Style x:Key="WarnToolTip" TargetType="{x:Type TypeName=ToolTip}" BasedOn="{StaticResource ResourceKey=HelpToolTip}" />

<Style x:Key="ErrorToolTip" TargetType="{x:Type TypeName=ToolTip}" BasedOn="{StaticResource ResourceKey=HelpToolTip}" />
Expand Down
3 changes: 3 additions & 0 deletions Source/NETworkManager/Views/DiscoveryProtocolView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
xmlns:converters="clr-namespace:NETworkManager.Converters;assembly=NETworkManager.Converters"
xmlns:viewModels="clr-namespace:NETworkManager.ViewModels"
xmlns:localization="clr-namespace:NETworkManager.Localization.Resources;assembly=NETworkManager.Localization"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:settings="clr-namespace:NETworkManager.Settings;assembly=NETworkManager.Settings"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:DiscoveryProtocolViewModel}">
<UserControl.Resources>
Expand Down Expand Up @@ -65,6 +66,8 @@
<ComboBox Grid.Column="6" ItemsSource="{Binding Durations}"
SelectedItem="{Binding SelectedDuration}" />
<Button Grid.Column="8" Command="{Binding CaptureCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.NetworkPacketsCaptureAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}"
Style="{StaticResource ImageWithTextButton}">
<Button.Content>
<Grid>
Expand Down
17 changes: 14 additions & 3 deletions Source/NETworkManager/Views/FirewallView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@
<ContextMenu x:Key="RowContextMenu" Opened="ContextMenu_Opened" MinWidth="150">
<MenuItem Header="{x:Static localization:Strings.EnableRule}"
Command="{Binding Path=EnableRuleCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.FirewallAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}"
Visibility="{Binding Path=SelectedResult.IsEnabled, Converter={StaticResource BooleanReverseToVisibilityCollapsedConverter}}">
<MenuItem.Icon>
<Rectangle Width="16" Height="16" Fill="{DynamicResource MahApps.Brushes.Gray3}">
Expand All @@ -110,6 +112,8 @@
</MenuItem>
<MenuItem Header="{x:Static localization:Strings.DisableRule}"
Command="{Binding Path=DisableRuleCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.FirewallAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}"
Visibility="{Binding Path=SelectedResult.IsEnabled, Converter={StaticResource BooleanToVisibilityCollapsedConverter}}">
<MenuItem.Icon>
<Rectangle Width="16" Height="16" Fill="{DynamicResource MahApps.Brushes.Gray3}">
Expand All @@ -120,7 +124,9 @@
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="{x:Static localization:Strings.EditRuleDots}"
Command="{Binding Path=EditRuleCommand}">
Command="{Binding Path=EditRuleCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.FirewallAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}">
<MenuItem.Icon>
<Rectangle Width="16" Height="16" Fill="{DynamicResource MahApps.Brushes.Gray3}">
<Rectangle.OpacityMask>
Expand All @@ -130,7 +136,9 @@
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="{x:Static localization:Strings.DeleteRule}"
Command="{Binding Path=DeleteRuleCommand}">
Command="{Binding Path=DeleteRuleCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.FirewallAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}">
<MenuItem.Icon>
<Rectangle Width="16" Height="16" Fill="{DynamicResource MahApps.Brushes.Gray3}">
<Rectangle.OpacityMask>
Expand Down Expand Up @@ -529,7 +537,10 @@
Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Right">
<Button Command="{Binding Path=AddRuleCommand}" Style="{StaticResource ImageWithTextButton}">
<Button Command="{Binding Path=AddRuleCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.FirewallAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}"
Style="{StaticResource ImageWithTextButton}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
Expand Down
29 changes: 24 additions & 5 deletions Source/NETworkManager/Views/HostsFileEditorView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
<ContextMenu x:Key="RowContextMenu" Opened="ContextMenu_Opened" MinWidth="150">
<MenuItem Header="{x:Static Member=localization:Strings.EnableEntry}"
Command="{Binding Path=EnableEntryCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.HostsFileEditorAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}"
Visibility="{Binding Path=SelectedResult.IsEnabled, Converter={StaticResource ResourceKey=BooleanReverseToVisibilityCollapsedConverter}}">
<MenuItem.Icon>
<Rectangle Width="16" Height="16"
Expand All @@ -102,6 +104,8 @@
</MenuItem>
<MenuItem Header="{x:Static Member=localization:Strings.DisableEntry}"
Command="{Binding Path=DisableEntryCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.HostsFileEditorAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}"
Visibility="{Binding Path=SelectedResult.IsEnabled, Converter={StaticResource ResourceKey=BooleanToVisibilityCollapsedConverter}}">
<MenuItem.Icon>
<Rectangle Width="16" Height="16"
Expand All @@ -114,7 +118,9 @@
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="{x:Static Member=localization:Strings.EditEntryDots}"
Command="{Binding Path=EditEntryCommand}">
Command="{Binding Path=EditEntryCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.HostsFileEditorAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}">
<MenuItem.Icon>
<Rectangle Width="16" Height="16"
Fill="{DynamicResource ResourceKey=MahApps.Brushes.Gray3}">
Expand All @@ -125,7 +131,9 @@
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="{x:Static Member=localization:Strings.DeleteEntry}"
Command="{Binding Path=DeleteEntryCommand}">
Command="{Binding Path=DeleteEntryCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.HostsFileEditorAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}">
<MenuItem.Icon>
<Rectangle Width="16" Height="16"
Fill="{DynamicResource ResourceKey=MahApps.Brushes.Gray3}">
Expand Down Expand Up @@ -170,6 +178,8 @@
<ContextMenu x:Key="MultiRowContextMenu" Opened="ContextMenu_Opened" MinWidth="150">
<MenuItem Header="{x:Static Member=localization:Strings.Enable}"
Command="{Binding Path=EnableEntryCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.HostsFileEditorAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}"
Visibility="{Binding Path=IsAnySelectedEntryDisabled, Converter={StaticResource ResourceKey=BooleanToVisibilityCollapsedConverter}}">
<MenuItem.Icon>
<Rectangle Width="16" Height="16"
Expand All @@ -183,6 +193,8 @@
</MenuItem>
<MenuItem Header="{x:Static Member=localization:Strings.Disable}"
Command="{Binding Path=DisableEntryCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.HostsFileEditorAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}"
Visibility="{Binding Path=IsAnySelectedEntryEnabled, Converter={StaticResource ResourceKey=BooleanToVisibilityCollapsedConverter}}">
<MenuItem.Icon>
<Rectangle Width="16" Height="16"
Expand All @@ -195,7 +207,9 @@
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="{x:Static Member=localization:Strings.EditEntriesDots}"
Command="{Binding Path=EditEntryCommand}">
Command="{Binding Path=EditEntryCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.HostsFileEditorAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}">
<MenuItem.Icon>
<Rectangle Width="16" Height="16"
Fill="{DynamicResource ResourceKey=MahApps.Brushes.Gray3}">
Expand All @@ -206,7 +220,9 @@
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="{x:Static Member=localization:Strings.DeleteEntries}"
Command="{Binding Path=DeleteEntryCommand}">
Command="{Binding Path=DeleteEntryCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.HostsFileEditorAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}">
<MenuItem.Icon>
<Rectangle Width="16" Height="16"
Fill="{DynamicResource ResourceKey=MahApps.Brushes.Gray3}">
Expand Down Expand Up @@ -316,7 +332,10 @@
Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Right">
<Button Command="{Binding AddEntryCommand}" Style="{StaticResource ImageWithTextButton}">
<Button Command="{Binding AddEntryCommand}"
wpfHelpers:PermissionToolTipHelper.Text="{x:Static localization:Strings.HostsFileEditorAdminMessage}"
wpfHelpers:PermissionToolTipHelper.HasPermission="{Binding Source={x:Static settings:ConfigurationManager.Current}, Path=IsAdmin}"
Style="{StaticResource ImageWithTextButton}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
Expand Down
Loading
Loading