From 0901b5493628d178c7f02c2eecd6d36700a5e79d Mon Sep 17 00:00:00 2001
From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
Date: Sat, 18 Jul 2026 23:45:16 +0200
Subject: [PATCH 1/3] Chore: Refactor profile views into a reusable control
---
.../IProfileHostViewModel.cs | 83 +++
.../NETworkManager.Profiles.csproj | 1 +
.../ProfileViewState.cs | 123 ++++
.../NETworkManager.Settings/SettingsInfo.cs | 418 +----------
.../ViewModels/DNSLookupHostViewModel.cs | 579 +--------------
.../ViewModels/IPGeolocationHostViewModel.cs | 577 +--------------
.../ViewModels/IPScannerHostViewModel.cs | 579 +--------------
.../ViewModels/NetworkInterfaceViewModel.cs | 500 +------------
.../ViewModels/PingMonitorHostViewModel.cs | 506 +------------
.../ViewModels/PortScannerHostViewModel.cs | 519 +------------
.../ViewModels/PowerShellHostViewModel.cs | 469 ++----------
.../ViewModels/ProfileHostViewModelBase.cs | 463 ++++++++++++
.../ViewModels/PuTTYHostViewModel.cs | 479 ++----------
.../ViewModels/RemoteDesktopHostViewModel.cs | 459 +-----------
.../ViewModels/SNMPHostViewModel.cs | 445 +-----------
.../ViewModels/TigerVNCHostViewModel.cs | 447 +-----------
.../ViewModels/TracerouteHostViewModel.cs | 446 +-----------
.../ViewModels/WakeOnLANViewModel.cs | 485 +------------
.../ViewModels/WebConsoleHostViewModel.cs | 453 +-----------
.../ViewModels/WhoisHostViewModel.cs | 443 +-----------
.../Views/Controls/ProfileExpanderPanel.xaml | 625 ++++++++++++++++
.../Controls/ProfileExpanderPanel.xaml.cs | 132 ++++
.../Views/DNSLookupHostView.xaml | 628 +---------------
.../Views/DNSLookupHostView.xaml.cs | 17 +-
.../Views/IPGeolocationHostView.xaml | 620 +---------------
.../Views/IPGeolocationHostView.xaml.cs | 17 +-
.../Views/IPScannerHostView.xaml | 628 +---------------
.../Views/IPScannerHostView.xaml.cs | 17 +-
.../Views/NetworkInterfaceView.xaml | 633 +---------------
.../Views/NetworkInterfaceView.xaml.cs | 10 +-
.../Views/PingMonitorHostView.xaml | 639 +---------------
.../Views/PingMonitorHostView.xaml.cs | 19 +-
.../Views/PortScannerHostView.xaml | 641 ++---------------
.../Views/PortScannerHostView.xaml.cs | 17 +-
.../Views/PowerShellHostView.xaml | 679 ++----------------
.../Views/PowerShellHostView.xaml.cs | 25 +-
.../NETworkManager/Views/PuTTYHostView.xaml | 678 ++---------------
.../Views/PuTTYHostView.xaml.cs | 28 +-
.../Views/RemoteDesktopHostView.xaml | 674 ++---------------
.../Views/RemoteDesktopHostView.xaml.cs | 21 +-
Source/NETworkManager/Views/SNMPHostView.xaml | 627 +---------------
.../NETworkManager/Views/SNMPHostView.xaml.cs | 17 +-
.../Views/TigerVNCHostView.xaml | 661 ++---------------
.../Views/TigerVNCHostView.xaml.cs | 24 +-
.../Views/TracerouteHostView.xaml | 627 +---------------
.../Views/TracerouteHostView.xaml.cs | 17 +-
.../NETworkManager/Views/WakeOnLANView.xaml | 610 +---------------
.../Views/WakeOnLANView.xaml.cs | 10 +-
.../Views/WebConsoleHostView.xaml | 637 +---------------
.../Views/WebConsoleHostView.xaml.cs | 17 +-
.../NETworkManager/Views/WhoisHostView.xaml | 619 +---------------
.../Views/WhoisHostView.xaml.cs | 17 +-
52 files changed, 2369 insertions(+), 16736 deletions(-)
create mode 100644 Source/NETworkManager.Profiles/IProfileHostViewModel.cs
create mode 100644 Source/NETworkManager.Settings/ProfileViewState.cs
create mode 100644 Source/NETworkManager/ViewModels/ProfileHostViewModelBase.cs
create mode 100644 Source/NETworkManager/Views/Controls/ProfileExpanderPanel.xaml
create mode 100644 Source/NETworkManager/Views/Controls/ProfileExpanderPanel.xaml.cs
diff --git a/Source/NETworkManager.Profiles/IProfileHostViewModel.cs b/Source/NETworkManager.Profiles/IProfileHostViewModel.cs
new file mode 100644
index 0000000000..dd79ff52ff
--- /dev/null
+++ b/Source/NETworkManager.Profiles/IProfileHostViewModel.cs
@@ -0,0 +1,83 @@
+using NETworkManager.Controls;
+using System.ComponentModel;
+using System.Windows.Input;
+
+namespace NETworkManager.Profiles;
+
+///
+/// Interface for a view model that hosts the shared profile panel (search, tag filter, group list) next to a
+/// tool-specific view, extending with the additional members the reusable
+/// profile panel control binds to.
+///
+public interface IProfileHostViewModel : IProfileManager
+{
+ ///
+ /// Gets or sets the selected profile.
+ ///
+ ProfileInfo SelectedProfile { get; set; }
+
+ ///
+ /// Gets or sets the search text.
+ ///
+ string Search { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether a search is in progress.
+ ///
+ bool IsSearching { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the profile filter popup is open.
+ ///
+ bool ProfileFilterIsOpen { get; set; }
+
+ ///
+ /// Gets the view for the profile filter tags.
+ ///
+ ICollectionView ProfileFilterTagsView { get; }
+
+ ///
+ /// Gets or sets a value indicating whether to match any profile filter tag.
+ ///
+ bool ProfileFilterTagsMatchAny { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to match all profile filter tags.
+ ///
+ bool ProfileFilterTagsMatchAll { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether a profile filter is currently applied.
+ ///
+ bool IsProfileFilterSet { get; set; }
+
+ ///
+ /// Gets the group expander state store for the profile list.
+ ///
+ GroupExpanderStateStore GroupExpanderStateStore { get; }
+
+ ///
+ /// Gets the command to open the profile filter popup.
+ ///
+ ICommand OpenProfileFilterCommand { get; }
+
+ ///
+ /// Gets the command to apply the profile filter.
+ ///
+ ICommand ApplyProfileFilterCommand { get; }
+
+ ///
+ /// Gets the command to clear the profile filter.
+ ///
+ ICommand ClearProfileFilterCommand { get; }
+
+ ///
+ /// Gets the command to expand all profile groups.
+ ///
+ ICommand ExpandAllProfileGroupsCommand { get; }
+
+ ///
+ /// Gets the command to collapse all profile groups.
+ ///
+ ICommand CollapseAllProfileGroupsCommand { get; }
+}
diff --git a/Source/NETworkManager.Profiles/NETworkManager.Profiles.csproj b/Source/NETworkManager.Profiles/NETworkManager.Profiles.csproj
index 5af1160527..d102667fd3 100644
--- a/Source/NETworkManager.Profiles/NETworkManager.Profiles.csproj
+++ b/Source/NETworkManager.Profiles/NETworkManager.Profiles.csproj
@@ -25,6 +25,7 @@
+
diff --git a/Source/NETworkManager.Settings/ProfileViewState.cs b/Source/NETworkManager.Settings/ProfileViewState.cs
new file mode 100644
index 0000000000..9f4c0e8103
--- /dev/null
+++ b/Source/NETworkManager.Settings/ProfileViewState.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Windows;
+using NETworkManager.Utilities;
+
+namespace NETworkManager.Settings;
+
+///
+/// Shared expanded/width state of the profile panel, used by every tool that hosts a profile list. Because all
+/// tools observe the same instance, resizing or collapsing the profile panel in one tool
+/// is reflected in every other tool automatically through data binding - no manual synchronization needed.
+///
+///
+/// reads the first time it is accessed. This is
+/// only safe once has completed (done early in App.xaml.cs, before the main
+/// window - and therefore any tool view - is created). Do not reference from eagerly
+/// loaded resources (e.g. App.xaml or globally merged style dictionaries).
+///
+public sealed class ProfileViewState : PropertyChangedBase
+{
+ public static ProfileViewState Current { get; }
+
+ static ProfileViewState()
+ {
+ Current = new ProfileViewState();
+ }
+
+ private readonly bool _isLoading;
+ private bool _canProfileWidthChange = true;
+ private double _tempProfileWidth;
+
+ private ProfileViewState()
+ {
+ _isLoading = true;
+
+ // Must be set before ExpandProfileView below, since assigning it can synchronously trigger
+ // ResizeProfile(false), which reads _tempProfileWidth.
+ _tempProfileWidth = SettingsManager.Current.Profile_Width;
+
+ ExpandProfileView = SettingsManager.Current.Profile_ExpandView;
+
+ ProfileWidth = ExpandProfileView
+ ? new GridLength(SettingsManager.Current.Profile_Width)
+ : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
+
+ _isLoading = false;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether the profile panel is expanded, shared across all tools.
+ ///
+ public bool ExpandProfileView
+ {
+ get;
+ set
+ {
+ if (value == field)
+ return;
+
+ if (!_isLoading)
+ SettingsManager.Current.Profile_ExpandView = value;
+
+ field = value;
+
+ if (_canProfileWidthChange)
+ ResizeProfile(false);
+
+ OnPropertyChanged();
+ }
+ }
+
+ ///
+ /// Gets or sets the width of the profile panel, shared across all tools.
+ ///
+ public GridLength ProfileWidth
+ {
+ get;
+ set
+ {
+ if (value == field)
+ return;
+
+ if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
+ GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
+ SettingsManager.Current.Profile_Width = value.Value;
+
+ field = value;
+
+ if (_canProfileWidthChange)
+ ResizeProfile(true);
+
+ OnPropertyChanged();
+ }
+ }
+
+ private void ResizeProfile(bool dueToChangedSize)
+ {
+ _canProfileWidthChange = false;
+
+ if (dueToChangedSize)
+ {
+ ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
+ GlobalStaticConfiguration.FloatPointFix;
+ }
+ else
+ {
+ if (ExpandProfileView)
+ {
+ ProfileWidth =
+ Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
+ GlobalStaticConfiguration.FloatPointFix
+ ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
+ : new GridLength(_tempProfileWidth);
+ }
+ else
+ {
+ _tempProfileWidth = ProfileWidth.Value;
+ ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
+ }
+ }
+
+ _canProfileWidthChange = true;
+ }
+}
diff --git a/Source/NETworkManager.Settings/SettingsInfo.cs b/Source/NETworkManager.Settings/SettingsInfo.cs
index 5a03e184b8..81931a83df 100644
--- a/Source/NETworkManager.Settings/SettingsInfo.cs
+++ b/Source/NETworkManager.Settings/SettingsInfo.cs
@@ -178,6 +178,34 @@ public int General_HistoryListEntries
}
} = GlobalStaticConfiguration.General_HistoryListEntries;
+ // Profile (shared across all tools with a profile panel)
+
+ public bool Profile_ExpandView
+ {
+ get;
+ set
+ {
+ if (value == field)
+ return;
+
+ field = value;
+ OnPropertyChanged();
+ }
+ } = GlobalStaticConfiguration.Profile_ExpandProfileView;
+
+ public double Profile_Width
+ {
+ get;
+ set
+ {
+ if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
+ return;
+
+ field = value;
+ OnPropertyChanged();
+ }
+ } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
+
// Window
public bool Window_ConfirmClose
@@ -855,32 +883,6 @@ public string NetworkInterface_InterfaceId
}
}
- public bool NetworkInterface_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double NetworkInterface_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
public string NetworkInterface_ExportFilePath
{
get;
@@ -1230,32 +1232,6 @@ public int IPScanner_MaxPortThreads
}
} = GlobalStaticConfiguration.IPScanner_MaxPortThreads;
- public bool IPScanner_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double IPScanner_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
public string IPScanner_ExportFilePath
{
get;
@@ -1390,32 +1366,6 @@ public int PortScanner_MaxPortThreads
}
} = GlobalStaticConfiguration.PortScanner_MaxPortThreads;
- public bool PortScanner_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double PortScanner_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
public string PortScanner_ExportFilePath
{
get;
@@ -1641,32 +1591,6 @@ public ExportFileType PingMonitor_ExportFileType
}
} = GlobalStaticConfiguration.PingMonitor_ExportFileType;
- public bool PingMonitor_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double PingMonitor_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
#endregion
#region Traceroute
@@ -1788,32 +1712,6 @@ public double Traceroute_MapHeight
}
} = GlobalStaticConfiguration.Traceroute_MapHeight;
- public bool Traceroute_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double Traceroute_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
public string Traceroute_ExportFilePath
{
get;
@@ -2028,32 +1926,6 @@ public int DNSLookup_Timeout
}
} = GlobalStaticConfiguration.DNSLookup_Timeout;
- public bool DNSLookup_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double DNSLookup_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
public string DNSLookup_ExportFilePath
{
get;
@@ -2565,32 +2437,6 @@ public bool RemoteDesktop_VisualStyles
}
}
- public bool RemoteDesktop_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double RemoteDesktop_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
#endregion
#region PowerShell
@@ -2660,32 +2506,6 @@ public ExecutionPolicy PowerShell_ExecutionPolicy
}
} = GlobalStaticConfiguration.PowerShell_ExecutionPolicy;
- public bool PowerShell_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double PowerShell_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
#endregion
#region PuTTY
@@ -2898,32 +2718,6 @@ public ObservableCollection PuTTY_ProfileHistory
}
} = [];
- public bool PuTTY_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double PuTTY_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
public string PuTTY_ApplicationFilePath
{
get;
@@ -3046,32 +2840,6 @@ public ObservableCollection TigerVNC_PortHistory
}
} = [];
- public bool TigerVNC_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double TigerVNC_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
public string TigerVNC_ApplicationFilePath
{
get;
@@ -3115,32 +2883,6 @@ public ObservableCollection WebConsole_UrlHistory
}
} = [];
- public bool WebConsole_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double WebConsole_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
public bool WebConsole_ShowAddressBar
{
get;
@@ -3327,32 +3069,6 @@ public SNMPV3PrivacyProvider SNMP_PrivacyProvider
}
} = GlobalStaticConfiguration.SNMP_PrivacyProvider;
- public bool SNMP_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double SNMP_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
public string SNMP_ExportFilePath
{
@@ -3633,32 +3349,6 @@ public ObservableCollection WakeOnLan_BroadcastHistory
}
} = [];
- public bool WakeOnLAN_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double WakeOnLAN_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
#endregion
#region Whois
@@ -3676,32 +3366,6 @@ public ObservableCollection Whois_DomainHistory
}
} = [];
- public bool Whois_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double Whois_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
public string Whois_ExportFilePath
{
get;
@@ -3745,32 +3409,6 @@ public ObservableCollection IPGeolocation_HostHistory
}
} = [];
- public bool IPGeolocation_ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_ExpandProfileView;
-
- public double IPGeolocation_ProfileWidth
- {
- get;
- set
- {
- if (Math.Abs(value - field) < GlobalStaticConfiguration.FloatPointFix)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_DefaultWidthExpanded;
-
public string IPGeolocation_ExportFilePath
{
get;
diff --git a/Source/NETworkManager/ViewModels/DNSLookupHostViewModel.cs b/Source/NETworkManager/ViewModels/DNSLookupHostViewModel.cs
index 6c3e8441f1..14e9865f44 100644
--- a/Source/NETworkManager/ViewModels/DNSLookupHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/DNSLookupHostViewModel.cs
@@ -1,33 +1,24 @@
-using Dragablz;
+using Dragablz;
using NETworkManager.Controls;
using NETworkManager.Localization.Resources;
using NETworkManager.Models;
using NETworkManager.Profiles;
-using NETworkManager.Settings;
using NETworkManager.Utilities;
using NETworkManager.Views;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.Linq;
-using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
namespace NETworkManager.ViewModels;
///
/// View model for the DNS lookup host view.
///
-public class DNSLookupHostViewModel : ViewModelBase, IProfileManager
+public class DNSLookupHostViewModel : ProfileHostViewModelBase
{
#region Variables
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
-
///
/// Gets the client for inter-tab operations.
///
@@ -54,9 +45,6 @@ public string InterTabPartition
///
public ObservableCollection TabItems { get; }
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
///
/// Gets or sets the index of the selected tab.
///
@@ -73,220 +61,15 @@ public int SelectedTabIndex
}
}
- #region Profiles
-
- ///
- /// Gets the collection view of profiles.
- ///
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the selected profile.
- ///
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- ///
- /// Gets or sets the search text.
- ///
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether a search is in progress.
- ///
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether the profile filter is open.
- ///
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets the collection view for profile filter tags.
- ///
- public ICollectionView ProfileFilterTagsView { get; }
-
- ///
- /// Gets the collection of profile filter tags.
- ///
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- ///
- /// Gets or sets a value indicating whether any tag match is sufficient for filtering.
- ///
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- ///
- /// Gets or sets a value indicating whether all tags must match for filtering.
- ///
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether a profile filter is set.
- ///
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- ///
- /// Gets or sets a value indicating whether the profile view is expanded.
- ///
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.DNSLookup_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the width of the profile view.
- ///
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.DNSLookup_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
#endregion
- #endregion
-
- #region Constructor, load settings
+ #region Constructor
///
/// Initializes a new instance of the class.
///
public DNSLookupHostViewModel()
{
- _isLoading = true;
-
-
InterTabClient = new DragablzInterTabClient(ApplicationName.DNSLookup);
InterTabPartition = nameof(ApplicationName.DNSLookup);
@@ -297,38 +80,18 @@ public DNSLookupHostViewModel()
new DragablzTabItem(Strings.NewTab, new DNSLookupView(tabId), tabId)
];
- // Profiles
- CreateTags();
-
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
+ InitializeProfileHost();
+ }
- SetProfilesView(new ProfileFilterInfo());
+ #endregion
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
+ #region Profile host
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ protected override ApplicationName ApplicationName => ApplicationName.DNSLookup;
- LoadSettings();
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.DNSLookup_Enabled;
- _isLoading = false;
- }
-
- ///
- /// Loads the settings.
- ///
- private void LoadSettings()
- {
- ExpandProfileView = SettingsManager.Current.DNSLookup_ExpandProfileView;
-
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.DNSLookup_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
-
- _tempProfileWidth = SettingsManager.Current.DNSLookup_ProfileWidth;
- }
+ protected override string GetSearchableField(ProfileInfo profile) => profile.DNSLookup_Host;
#endregion
@@ -368,159 +131,6 @@ private void LookupProfileAction()
AddTab(SelectedProfile.DNSLookup_Host);
}
- ///
- /// Gets the command to add a new profile.
- ///
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- ///
- /// Action to add a new profile.
- ///
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.DNSLookup);
- }
-
- ///
- /// Checks if the profile modification commands can be executed.
- ///
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- ///
- /// Gets the command to edit the selected profile.
- ///
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- ///
- /// Action to edit the selected profile.
- ///
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to copy the selected profile as a new profile.
- ///
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- ///
- /// Action to copy the selected profile as a new profile.
- ///
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to delete the selected profile.
- ///
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- ///
- /// Action to delete the selected profile.
- ///
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- ///
- /// Gets the command to edit a profile group.
- ///
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- ///
- /// Action to edit a profile group.
- ///
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- ///
- /// Gets the command to open the profile filter.
- ///
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- ///
- /// Action to open the profile filter.
- ///
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- ///
- /// Gets the command to apply the profile filter.
- ///
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- ///
- /// Action to apply the profile filter.
- ///
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to clear the profile filter.
- ///
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- ///
- /// Action to clear the profile filter.
- ///
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to expand all profile groups.
- ///
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- ///
- /// Action to expand all profile groups.
- ///
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- ///
- /// Gets the command to collapse all profile groups.
- ///
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- ///
- /// Action to collapse all profile groups.
- ///
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
///
/// Gets the callback for closing a tab item.
///
@@ -538,49 +148,6 @@ private static void CloseItemAction(ItemActionCallbackArgs args)
#region Methods
- ///
- /// Sets the IsExpanded property for all profile groups.
- ///
- /// The value to set.
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- ///
- /// Resizes the profile view.
- ///
- /// Indicates if the resize is due to a changed size.
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
///
/// Adds a new tab for the specified host.
///
@@ -595,129 +162,5 @@ public void AddTab(string host = null)
SelectedTabIndex = TabItems.Count - 1;
}
- ///
- /// Called when the view becomes visible.
- ///
- public void OnViewVisible()
- {
- _isViewActive = true;
-
- RefreshProfiles();
- }
-
- ///
- /// Called when the view is hidden.
- ///
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- ///
- /// Creates the profile filter tags.
- ///
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.DNSLookup_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- ///
- /// Sets the profiles view with the specified filter.
- ///
- /// The profile filter.
- /// The profile to select.
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.DNSLookup_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.DNSLookup_Host.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- ///
- /// Refreshes the profiles.
- ///
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
- #endregion
-
- #region Event
-
- ///
- /// Handles the OnProfilesUpdated event of the ProfileManager.
- ///
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- ///
- /// Handles the Tick event of the search dispatcher timer.
- ///
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/IPGeolocationHostViewModel.cs b/Source/NETworkManager/ViewModels/IPGeolocationHostViewModel.cs
index 82765b874d..dc6cac0a84 100644
--- a/Source/NETworkManager/ViewModels/IPGeolocationHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/IPGeolocationHostViewModel.cs
@@ -1,33 +1,23 @@
-using Dragablz;
+using Dragablz;
using NETworkManager.Controls;
using NETworkManager.Localization.Resources;
using NETworkManager.Models;
using NETworkManager.Profiles;
-using NETworkManager.Settings;
using NETworkManager.Utilities;
using NETworkManager.Views;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.Linq;
-using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
namespace NETworkManager.ViewModels;
///
/// View model for the IP geolocation host view.
///
-public class IPGeolocationHostViewModel : ViewModelBase, IProfileManager
+public class IPGeolocationHostViewModel : ProfileHostViewModelBase
{
#region Variables
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
-
///
/// Gets the client for inter-tab operations.
///
@@ -54,9 +44,6 @@ public string InterTabPartition
///
public ObservableCollection TabItems { get; }
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
///
/// Gets or sets the index of the selected tab.
///
@@ -73,208 +60,6 @@ public int SelectedTabIndex
}
}
- #region Profiles
-
- ///
- /// Gets the collection view of profiles.
- ///
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the selected profile.
- ///
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- ///
- /// Gets or sets the search text.
- ///
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether a search is in progress.
- ///
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether the profile filter is open.
- ///
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets the collection view for profile filter tags.
- ///
- public ICollectionView ProfileFilterTagsView { get; }
-
- ///
- /// Gets the collection of profile filter tags.
- ///
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- ///
- /// Gets or sets a value indicating whether any tag match is sufficient for filtering.
- ///
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- ///
- /// Gets or sets a value indicating whether all tags must match for filtering.
- ///
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether a profile filter is set.
- ///
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- ///
- /// Gets or sets a value indicating whether the profile view is expanded.
- ///
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.IPGeolocation_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the width of the profile view.
- ///
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.IPGeolocation_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
- #endregion
-
#endregion
#region Constructor
@@ -284,8 +69,6 @@ public GridLength ProfileWidth
///
public IPGeolocationHostViewModel()
{
- _isLoading = true;
-
InterTabClient = new DragablzInterTabClient(ApplicationName.IPGeolocation);
InterTabPartition = nameof(ApplicationName.IPGeolocation);
@@ -296,38 +79,18 @@ public IPGeolocationHostViewModel()
new DragablzTabItem(Strings.NewTab, new IPGeolocationView(tabId), tabId)
];
- // Profiles
- CreateTags();
-
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
-
- SetProfilesView(new ProfileFilterInfo());
-
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
-
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ InitializeProfileHost();
+ }
- LoadSettings();
+ #endregion
- _isLoading = false;
- }
+ #region Profile host
- ///
- /// Loads the settings.
- ///
- private void LoadSettings()
- {
- ExpandProfileView = SettingsManager.Current.IPGeolocation_ExpandProfileView;
+ protected override ApplicationName ApplicationName => ApplicationName.IPGeolocation;
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.IPGeolocation_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.IPGeolocation_Enabled;
- _tempProfileWidth = SettingsManager.Current.IPGeolocation_ProfileWidth;
- }
+ protected override string GetSearchableField(ProfileInfo profile) => profile.IPGeolocation_Host;
#endregion
@@ -367,159 +130,6 @@ private void QueryProfileAction()
AddTab(SelectedProfile.IPGeolocation_Host);
}
- ///
- /// Gets the command to add a new profile.
- ///
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- ///
- /// Action to add a new profile.
- ///
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.IPGeolocation);
- }
-
- ///
- /// Checks if the profile modification commands can be executed.
- ///
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- ///
- /// Gets the command to edit the selected profile.
- ///
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- ///
- /// Action to edit the selected profile.
- ///
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to copy the selected profile as a new profile.
- ///
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- ///
- /// Action to copy the selected profile as a new profile.
- ///
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to delete the selected profile.
- ///
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- ///
- /// Action to delete the selected profile.
- ///
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- ///
- /// Gets the command to edit a profile group.
- ///
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- ///
- /// Action to edit a profile group.
- ///
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- ///
- /// Gets the command to open the profile filter.
- ///
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- ///
- /// Action to open the profile filter.
- ///
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- ///
- /// Gets the command to apply the profile filter.
- ///
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- ///
- /// Action to apply the profile filter.
- ///
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to clear the profile filter.
- ///
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- ///
- /// Action to clear the profile filter.
- ///
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to expand all profile groups.
- ///
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- ///
- /// Action to expand all profile groups.
- ///
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- ///
- /// Gets the command to collapse all profile groups.
- ///
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- ///
- /// Action to collapse all profile groups.
- ///
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
///
/// Gets the callback for closing a tab item.
///
@@ -537,49 +147,6 @@ private static void CloseItemAction(ItemActionCallbackArgs args)
#region Methods
- ///
- /// Sets the IsExpanded property for all profile groups.
- ///
- /// The value to set.
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- ///
- /// Resizes the profile view.
- ///
- /// Indicates whether the resize is due to a size change.
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
///
/// Adds a new tab for the specified domain.
///
@@ -594,129 +161,5 @@ private void AddTab(string domain = null)
SelectedTabIndex = TabItems.Count - 1;
}
- ///
- /// Called when the view becomes visible.
- ///
- public void OnViewVisible()
- {
- _isViewActive = true;
-
- RefreshProfiles();
- }
-
- ///
- /// Called when the view is hidden.
- ///
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- ///
- /// Creates the profile filter tags.
- ///
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.IPGeolocation_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- ///
- /// Sets the profiles view with the specified filter.
- ///
- /// The profile filter.
- /// The profile to select.
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.IPGeolocation_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.IPGeolocation_Host.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- ///
- /// Refreshes the profiles.
- ///
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
- #endregion
-
- #region Event
-
- ///
- /// Handles the OnProfilesUpdated event of the ProfileManager.
- ///
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- ///
- /// Handles the Tick event of the search dispatcher timer.
- ///
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/IPScannerHostViewModel.cs b/Source/NETworkManager/ViewModels/IPScannerHostViewModel.cs
index 63924cec12..9ca9e59493 100644
--- a/Source/NETworkManager/ViewModels/IPScannerHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/IPScannerHostViewModel.cs
@@ -1,33 +1,23 @@
-using Dragablz;
+using Dragablz;
using NETworkManager.Controls;
using NETworkManager.Localization.Resources;
using NETworkManager.Models;
using NETworkManager.Profiles;
-using NETworkManager.Settings;
using NETworkManager.Utilities;
using NETworkManager.Views;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.Linq;
-using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
namespace NETworkManager.ViewModels;
///
/// View model for the IP scanner host view.
///
-public class IPScannerHostViewModel : ViewModelBase, IProfileManager
+public class IPScannerHostViewModel : ProfileHostViewModelBase
{
#region Variables
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
-
///
/// Gets the client for inter-tab operations.
///
@@ -54,9 +44,6 @@ public string InterTabPartition
///
public ObservableCollection TabItems { get; }
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
///
/// Gets or sets the index of the selected tab.
///
@@ -73,219 +60,15 @@ public int SelectedTabIndex
}
}
- #region Profiles
-
- ///
- /// Gets the collection view of profiles.
- ///
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the selected profile.
- ///
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- ///
- /// Gets or sets the search text.
- ///
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether a search is in progress.
- ///
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether the profile filter is open.
- ///
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets the collection view for profile filter tags.
- ///
- public ICollectionView ProfileFilterTagsView { get; }
-
- ///
- /// Gets the collection of profile filter tags.
- ///
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- ///
- /// Gets or sets a value indicating whether any tag match is sufficient for filtering.
- ///
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- ///
- /// Gets or sets a value indicating whether all tags must match for filtering.
- ///
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether a profile filter is set.
- ///
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- ///
- /// Gets or sets a value indicating whether the profile view is expanded.
- ///
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.IPScanner_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the width of the profile view.
- ///
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.IPScanner_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
- #endregion
-
#endregion
- #region Constructor, load settings
+ #region Constructor
///
/// Initializes a new instance of the class.
///
public IPScannerHostViewModel()
{
- _isLoading = true;
-
InterTabClient = new DragablzInterTabClient(ApplicationName.IPScanner);
InterTabPartition = nameof(ApplicationName.IPScanner);
@@ -296,38 +79,18 @@ public IPScannerHostViewModel()
new DragablzTabItem(Strings.NewTab, new IPScannerView(tabId), tabId)
];
- // Profiles
- CreateTags();
-
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
-
- SetProfilesView(new ProfileFilterInfo());
-
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
-
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ InitializeProfileHost();
+ }
- LoadSettings();
+ #endregion
- _isLoading = false;
- }
+ #region Profile host
- ///
- /// Loads the settings.
- ///
- private void LoadSettings()
- {
- ExpandProfileView = SettingsManager.Current.IPScanner_ExpandProfileView;
+ protected override ApplicationName ApplicationName => ApplicationName.IPScanner;
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.IPScanner_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.IPScanner_Enabled;
- _tempProfileWidth = SettingsManager.Current.IPScanner_ProfileWidth;
- }
+ protected override string GetSearchableField(ProfileInfo profile) => profile.IPScanner_HostOrIPRange;
#endregion
@@ -367,159 +130,6 @@ private void ScanProfileAction()
AddTab(SelectedProfile);
}
- ///
- /// Gets the command to add a new profile.
- ///
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- ///
- /// Action to add a new profile.
- ///
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.IPScanner);
- }
-
- ///
- /// Checks if the profile modification commands can be executed.
- ///
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- ///
- /// Gets the command to edit the selected profile.
- ///
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- ///
- /// Action to edit the selected profile.
- ///
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to copy the selected profile as a new profile.
- ///
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- ///
- /// Action to copy the selected profile as a new profile.
- ///
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to delete the selected profile.
- ///
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- ///
- /// Action to delete the selected profile.
- ///
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- ///
- /// Gets the command to edit a profile group.
- ///
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- ///
- /// Action to edit a profile group.
- ///
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- ///
- /// Gets the command to open the profile filter.
- ///
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- ///
- /// Action to open the profile filter.
- ///
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- ///
- /// Gets the command to apply the profile filter.
- ///
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- ///
- /// Action to apply the profile filter.
- ///
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to clear the profile filter.
- ///
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- ///
- /// Action to clear the profile filter.
- ///
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to expand all profile groups.
- ///
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- ///
- /// Action to expand all profile groups.
- ///
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- ///
- /// Gets the command to collapse all profile groups.
- ///
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- ///
- /// Action to collapse all profile groups.
- ///
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
///
/// Gets the callback for closing a tab item.
///
@@ -537,49 +147,6 @@ private static void CloseItemAction(ItemActionCallbackArgs args)
#region Methods
- ///
- /// Sets the IsExpanded property for all profile groups.
- ///
- /// The value to set.
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- ///
- /// Resizes the profile view.
- ///
- /// Indicates whether the resize is due to a size change.
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
///
/// Adds a new tab for the specified host or IP range.
///
@@ -603,129 +170,5 @@ private void AddTab(ProfileInfo profile)
AddTab(profile.IPScanner_HostOrIPRange);
}
- ///
- /// Called when the view becomes visible.
- ///
- public void OnViewVisible()
- {
- _isViewActive = true;
-
- RefreshProfiles();
- }
-
- ///
- /// Called when the view is hidden.
- ///
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- ///
- /// Creates the profile filter tags.
- ///
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.IPScanner_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- ///
- /// Sets the profiles view with the specified filter.
- ///
- /// The profile filter.
- /// The profile to select.
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.IPScanner_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.IPScanner_HostOrIPRange.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- ///
- /// Refreshes the profiles.
- ///
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
- #endregion
-
- #region Event
-
- ///
- /// Handles the OnProfilesUpdated event of the ProfileManager.
- ///
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- ///
- /// Handles the Tick event of the search dispatcher timer.
- ///
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/NetworkInterfaceViewModel.cs b/Source/NETworkManager/ViewModels/NetworkInterfaceViewModel.cs
index 8126e4992c..c3e1f1532c 100644
--- a/Source/NETworkManager/ViewModels/NetworkInterfaceViewModel.cs
+++ b/Source/NETworkManager/ViewModels/NetworkInterfaceViewModel.cs
@@ -1,4 +1,4 @@
-using LiveChartsCore;
+using LiveChartsCore;
using LiveChartsCore.Drawing;
using LiveChartsCore.Kernel;
using LiveChartsCore.SkiaSharpView;
@@ -7,7 +7,6 @@
using log4net;
using MahApps.Metro.Controls;
using MahApps.Metro.SimpleChildWindow;
-using NETworkManager.Controls;
using NETworkManager.Localization.Resources;
using NETworkManager.Models;
using NETworkManager.Models.EventSystem;
@@ -27,9 +26,7 @@
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
using NetworkInterface = NETworkManager.Models.Network.NetworkInterface;
namespace NETworkManager.ViewModels;
@@ -37,18 +34,15 @@ namespace NETworkManager.ViewModels;
///
/// ViewModel for the Network Interface feature, allowing management of network adapters.
///
-public class NetworkInterfaceViewModel : ViewModelBase, IProfileManager
+public class NetworkInterfaceViewModel : ProfileHostViewModelBase
{
#region Variables
private static readonly ILog Log = LogManager.GetLogger(typeof(NetworkInterfaceViewModel));
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
private BandwidthMeter _bandwidthMeter;
private readonly bool _isLoading;
- private bool _isViewActive = true;
///
/// Gets or sets a value indicating whether network interfaces are currently loading.
@@ -467,33 +461,15 @@ public string ConfigSecondaryDNSServer
#endregion
- #region Profiles
-
- ///
- /// Gets the collection of profiles.
- ///
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
///
- /// Gets or sets the selected profile.
+ /// Gets or sets the selected profile. Pre-fills the Config* fields from the profile.
///
- public ProfileInfo SelectedProfile
+ public override ProfileInfo SelectedProfile
{
- get;
+ get => base.SelectedProfile;
set
{
- if (value == field)
+ if (value == base.SelectedProfile)
return;
if (value != null)
@@ -509,184 +485,12 @@ public ProfileInfo SelectedProfile
ConfigSecondaryDNSServer = value.NetworkInterface_SecondaryDNSServer;
}
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- ///
- /// Gets or sets the search text.
- ///
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether a search is in progress.
- ///
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether the profile filter is open.
- ///
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the view for profile filter tags.
- ///
- public ICollectionView ProfileFilterTagsView { get; set; }
-
- ///
- /// Gets or sets the collection of profile filter tags.
- ///
- public ObservableCollection ProfileFilterTags { get; set; } = [];
-
- ///
- /// Gets or sets a value indicating whether to match any profile filter tag.
- ///
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- ///
- /// Gets or sets a value indicating whether to match all profile filter tags.
- ///
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether a profile filter is set.
- ///
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets the store for group expander states.
- ///
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- ///
- /// Gets or sets a value indicating whether to expand the profile view.
- ///
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.NetworkInterface_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the width of the profile view.
- ///
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.NetworkInterface_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
+ base.SelectedProfile = value;
}
}
#endregion
- #endregion
-
#region Constructor, LoadSettings, OnShutdown
///
@@ -703,19 +507,7 @@ public NetworkInterfaceViewModel()
_ = LoadNetworkInterfaces();
- // Profiles
- CreateTags();
-
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
-
- SetProfilesView(new ProfileFilterInfo());
-
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
-
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ InitializeProfileHost();
// Detect if network address or status changed...
NetworkChange.NetworkAvailabilityChanged += (_, _) => ReloadNetworkInterfaces();
@@ -724,8 +516,6 @@ public NetworkInterfaceViewModel()
// React to settings changes (e.g. the configurable bandwidth chart time window)
SettingsManager.Current.PropertyChanged += SettingsManager_PropertyChanged;
- LoadSettings();
-
_isLoading = false;
}
@@ -931,19 +721,16 @@ private async Task LoadNetworkInterfaces()
IsNetworkInterfaceLoading = false;
}
- ///
- /// Loads the settings.
- ///
- private void LoadSettings()
- {
- ExpandProfileView = SettingsManager.Current.NetworkInterface_ExpandProfileView;
+ #endregion
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.NetworkInterface_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
+ #region Profile host
- _tempProfileWidth = SettingsManager.Current.NetworkInterface_ProfileWidth;
- }
+ protected override ApplicationName ApplicationName => ApplicationName.NetworkInterface;
+
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.NetworkInterface_Enabled;
+
+ // Unlike other tools, profile search here only matches the profile name (no secondary field).
+ protected override string GetSearchableField(ProfileInfo profile) => string.Empty;
#endregion
@@ -1050,126 +837,6 @@ private void ApplyProfileAction()
_ = ApplyConfigurationFromProfile();
}
- ///
- /// Gets the command to add a new profile.
- ///
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.NetworkInterface);
- }
-
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- ///
- /// Gets the command to edit the selected profile.
- ///
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to copy the selected profile as a new profile.
- ///
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to delete the selected profile.
- ///
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- ///
- /// Gets the command to edit a profile group.
- ///
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- ///
- /// Gets the command to open the profile filter.
- ///
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- ///
- /// Gets the command to apply the profile filter.
- ///
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to clear the profile filter.
- ///
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to expand all profile groups.
- ///
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- ///
- /// Gets the command to collapse all profile groups.
- ///
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
#region Additional commands
private bool AdditionalCommands_CanExecute(object parameter)
@@ -1178,7 +845,7 @@ private bool AdditionalCommands_CanExecute(object parameter)
!((MetroWindow)Application.Current.MainWindow).IsAnyDialogOpen &&
!ConfigurationManager.Current.IsChildWindowOpen;
}
-
+
private bool ConfigureCommands_CanExecute(object parameter) => ConfigurationManager.Current.IsAdmin &&
Application.Current.MainWindow != null &&
!((MetroWindow)Application.Current.MainWindow).IsAnyDialogOpen &&
@@ -1391,7 +1058,7 @@ private async void ReloadNetworkInterfaces()
// Invoke on UI thread synchronously
Application.Current.Dispatcher.Invoke(() =>
{
- // Clear the list
+ // Clear the list
NetworkInterfaces.Clear();
// Add all network interfaces to the list
@@ -1693,41 +1360,6 @@ private async Task RemoveIPv4Address(string ipAddress)
}
}
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
private void ResetBandwidthChart()
{
if (_bandwidthReceivedValues == null)
@@ -1849,11 +1481,9 @@ private void StopBandwidthMeter()
///
/// Called when the view becomes visible.
///
- public void OnViewVisible()
+ public override void OnViewVisible()
{
- _isViewActive = true;
-
- RefreshProfiles();
+ base.OnViewVisible();
ResumeBandwidthMeter();
}
@@ -1861,101 +1491,17 @@ public void OnViewVisible()
///
/// Called when the view is hidden.
///
- public void OnViewHide()
+ public override void OnViewHide()
{
StopBandwidthMeter();
- _isViewActive = false;
- }
-
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.NetworkInterface_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.NetworkInterface_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
+ base.OnViewHide();
}
#endregion
#region Events
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
private void SettingsManager_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
@@ -2034,4 +1580,4 @@ private void BandwidthMeter_UpdateSpeed(object sender, BandwidthMeterSpeedArgs e
}
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/PingMonitorHostViewModel.cs b/Source/NETworkManager/ViewModels/PingMonitorHostViewModel.cs
index 11d3d3a83d..5244f1e1b3 100644
--- a/Source/NETworkManager/ViewModels/PingMonitorHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/PingMonitorHostViewModel.cs
@@ -1,5 +1,4 @@
-using MahApps.Metro.Controls;
-using NETworkManager.Controls;
+using MahApps.Metro.Controls;
using NETworkManager.Localization.Resources;
using NETworkManager.Models;
using NETworkManager.Models.Network;
@@ -18,25 +17,18 @@
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
namespace NETworkManager.ViewModels;
///
/// ViewModel for the Ping Monitor Host view.
///
-public class PingMonitorHostViewModel : ViewModelBase, IProfileManager
+public class PingMonitorHostViewModel : ProfileHostViewModelBase
{
#region Variables
private CancellationTokenSource _cancellationTokenSource;
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
-
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
private string _group = Strings.Hosts; // Default group name
///
@@ -144,208 +136,6 @@ public ObservableCollection Hosts
///
public ICollectionView HostsView { get; }
- #region Profiles
-
- ///
- /// Gets the view for the profiles.
- ///
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the selected profile.
- ///
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the search text.
- ///
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether a search is in progress.
- ///
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether the profile filter is open.
- ///
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets the view for the profile filter tags.
- ///
- public ICollectionView ProfileFilterTagsView { get; }
-
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- ///
- /// Gets or sets a value indicating whether to match any profile filter tag.
- ///
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- ///
- /// Gets or sets a value indicating whether to match all profile filter tags.
- ///
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether the profile filter is set.
- ///
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets the group expander state store.
- ///
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- ///
- /// Gets or sets a value indicating whether the profile view is expanded.
- ///
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.PingMonitor_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the width of the profile view.
- ///
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.PingMonitor_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
- #endregion
-
#endregion
#region Constructor, load settings
@@ -355,8 +145,6 @@ public GridLength ProfileWidth
///
public PingMonitorHostViewModel()
{
- _isLoading = true;
-
// Host history
HostHistoryView = CollectionViewSource.GetDefaultView(SettingsManager.Current.PingMonitor_HostHistory);
@@ -365,35 +153,18 @@ public PingMonitorHostViewModel()
HostsView.GroupDescriptions.Add(new PropertyGroupDescription(nameof(PingMonitorView.Group)));
HostsView.SortDescriptions.Add(new SortDescription(nameof(PingMonitorView.Group), ListSortDirection.Ascending));
- // Profiles
- CreateTags();
-
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
-
- SetProfilesView(new ProfileFilterInfo());
-
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
-
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ InitializeProfileHost();
+ }
- LoadSettings();
+ #endregion
- _isLoading = false;
- }
+ #region Profile host
- private void LoadSettings()
- {
- ExpandProfileView = SettingsManager.Current.PingMonitor_ExpandProfileView;
+ protected override ApplicationName ApplicationName => ApplicationName.PingMonitor;
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.PingMonitor_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.PingMonitor_Enabled;
- _tempProfileWidth = SettingsManager.Current.PingMonitor_ProfileWidth;
- }
+ protected override string GetSearchableField(ProfileInfo profile) => profile.PingMonitor_Host;
#endregion
@@ -445,125 +216,6 @@ private void CloseGroupAction(object group)
RemoveGroup(group.ToString());
}
- ///
- /// Gets the command to add a new profile.
- ///
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.PingMonitor);
- }
-
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- ///
- /// Gets the command to edit the selected profile.
- ///
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to copy the selected profile as a new profile.
- ///
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to delete the selected profile.
- ///
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- ///
- /// Gets the command to edit a group.
- ///
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- ///
- /// Gets the command to open the profile filter.
- ///
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- ///
- /// Gets the command to apply the profile filter.
- ///
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to clear the profile filter.
- ///
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to expand all profile groups.
- ///
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- ///
- /// Gets the command to collapse all profile groups.
- ///
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
#endregion
#region Methods
@@ -707,148 +359,10 @@ private void AddHostToHistory(string host)
list.ForEach(SettingsManager.Current.PingMonitor_HostHistory.Add);
}
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
- ///
- /// Called when the view becomes visible.
- ///
- public void OnViewVisible()
- {
- _isViewActive = true;
-
- RefreshProfiles();
- }
-
- ///
- /// Called when the view is hidden.
- ///
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.PingMonitor_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.PingMonitor_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.PingMonitor_Host.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
#endregion
#region Event
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
private void UserHasCanceled()
{
StatusMessage = Strings.CanceledByUserMessage;
@@ -859,4 +373,4 @@ private void UserHasCanceled()
}
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/PortScannerHostViewModel.cs b/Source/NETworkManager/ViewModels/PortScannerHostViewModel.cs
index 60414aae6a..d2b982af47 100644
--- a/Source/NETworkManager/ViewModels/PortScannerHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/PortScannerHostViewModel.cs
@@ -1,33 +1,23 @@
-using Dragablz;
+using Dragablz;
using NETworkManager.Controls;
using NETworkManager.Localization.Resources;
using NETworkManager.Models;
using NETworkManager.Profiles;
-using NETworkManager.Settings;
using NETworkManager.Utilities;
using NETworkManager.Views;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.Linq;
-using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
namespace NETworkManager.ViewModels;
///
/// The view model for the Port Scanner host, managing tabs and profiles.
///
-public class PortScannerHostViewModel : ViewModelBase, IProfileManager
+public class PortScannerHostViewModel : ProfileHostViewModelBase
{
#region Variables
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
-
///
/// Gets the InterTabClient for Dragablz.
///
@@ -54,9 +44,6 @@ public string InterTabPartition
///
public ObservableCollection TabItems { get; }
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
///
/// Gets or sets the index of the selected tab.
///
@@ -73,219 +60,15 @@ public int SelectedTabIndex
}
}
- #region Profiles
-
- ///
- /// Gets the collection of filtered profiles.
- ///
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the selected profile.
- ///
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- ///
- /// Gets or sets the search query for filtering profiles.
- ///
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether a search is currently active.
- ///
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether the profile filter flyout is open.
- ///
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets the collection view for profile filter tags.
- ///
- public ICollectionView ProfileFilterTagsView { get; }
-
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- ///
- /// Gets or sets a value indicating whether to match any selected tag in the filter.
- ///
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- ///
- /// Gets or sets a value indicating whether to match all selected tags in the filter.
- ///
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether a profile filter is currently applied.
- ///
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets the store for group expander states.
- ///
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- ///
- /// Gets or sets a value indicating whether the profile view is expanded.
- ///
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.PortScanner_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets the width of the profile view.
- ///
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.PortScanner_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
#endregion
- #endregion
-
- #region Constructor, load settings
+ #region Constructor
///
/// Initializes a new instance of the class.
///
public PortScannerHostViewModel()
{
- _isLoading = true;
-
InterTabClient = new DragablzInterTabClient(ApplicationName.PortScanner);
InterTabPartition = nameof(ApplicationName.PortScanner);
@@ -296,35 +79,18 @@ public PortScannerHostViewModel()
new DragablzTabItem(Strings.NewTab, new PortScannerView(tabId), tabId)
];
- // Profiles
- CreateTags();
-
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
-
- SetProfilesView(new ProfileFilterInfo());
-
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
+ InitializeProfileHost();
+ }
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ #endregion
- LoadSettings();
+ #region Profile host
- _isLoading = false;
- }
+ protected override ApplicationName ApplicationName => ApplicationName.PortScanner;
- private void LoadSettings()
- {
- ExpandProfileView = SettingsManager.Current.PortScanner_ExpandProfileView;
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.PortScanner_Enabled;
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.PortScanner_ProfileWidth)
- : new GridLength(40);
-
- _tempProfileWidth = SettingsManager.Current.PortScanner_ProfileWidth;
- }
+ protected override string GetSearchableField(ProfileInfo profile) => profile.PortScanner_Host;
#endregion
@@ -355,126 +121,6 @@ private void ScanProfileAction()
AddTab(SelectedProfile);
}
- ///
- /// Gets the command to add a new profile.
- ///
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.PortScanner);
- }
-
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- ///
- /// Gets the command to edit the selected profile.
- ///
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to copy the selected profile.
- ///
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to delete the selected profile.
- ///
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- ///
- /// Gets the command to edit a profile group.
- ///
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- ///
- /// Gets the command to open the profile filter.
- ///
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- ///
- /// Gets the command to apply the profile filter.
- ///
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to clear the profile filter.
- ///
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to expand all profile groups.
- ///
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- ///
- /// Gets the command to collapse all profile groups.
- ///
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
///
/// Gets the callback for closing a tab item.
///
@@ -489,41 +135,6 @@ private static void CloseItemAction(ItemActionCallbackArgs args)
#region Methods
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
///
/// Adds a new tab with the specified host and ports.
///
@@ -544,113 +155,5 @@ private void AddTab(ProfileInfo profile)
AddTab(profile.PortScanner_Host, profile.PortScanner_Ports);
}
- ///
- /// Called when the view becomes visible.
- ///
- public void OnViewVisible()
- {
- _isViewActive = true;
-
- RefreshProfiles();
- }
-
- ///
- /// Called when the view is hidden.
- ///
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.PortScanner_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.PortScanner_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.PortScanner_Host.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
-
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
- #endregion
-
- #region Event
-
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs b/Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs
index d5bc743ac2..95cedff324 100644
--- a/Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs
@@ -1,4 +1,4 @@
-using Dragablz;
+using Dragablz;
using log4net;
using MahApps.Metro.SimpleChildWindow;
using NETworkManager.Controls;
@@ -11,7 +11,6 @@
using NETworkManager.Utilities;
using NETworkManager.Views;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
@@ -19,20 +18,16 @@
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
using PowerShellProfile = NETworkManager.Profiles.Application.PowerShell;
namespace NETworkManager.ViewModels;
-public class PowerShellHostViewModel : ViewModelBase, IProfileManager
+public class PowerShellHostViewModel : ProfileHostViewModelBase
{
#region Variables
private static readonly ILog Log = LogManager.GetLogger(typeof(PowerShellHostViewModel));
- private readonly DispatcherTimer _searchDispatcherTimer = new();
-
public IInterTabClient InterTabClient { get; }
public string InterTabPartition
@@ -50,9 +45,6 @@ public string InterTabPartition
public ObservableCollection TabItems { get; }
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
public bool IsExecutableConfigured
{
get;
@@ -92,169 +84,13 @@ public bool HeaderContextMenuIsOpen
}
}
- #region Profiles
-
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- IsSearching = true;
- _searchDispatcherTimer.Start();
-
- OnPropertyChanged();
- }
- }
-
private bool _textBoxSearchIsFocused;
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ICollectionView ProfileFilterTagsView { get; }
-
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.PowerShell_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.PowerShell_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
+ ///
+ /// Gets or sets a value indicating whether the profile context menu is open. Bound to
+ /// so
+ /// can avoid stealing focus while it is open.
+ ///
public bool ProfileContextMenuIsOpen
{
get;
@@ -270,14 +106,10 @@ public bool ProfileContextMenuIsOpen
#endregion
- #endregion
-
#region Constructor, load settings
public PowerShellHostViewModel()
{
- _isLoading = true;
-
// Check if PowerShell executable is configured
CheckExecutable();
@@ -293,35 +125,53 @@ public PowerShellHostViewModel()
TabItems = [];
- // Profiles
- CreateTags();
+ InitializeProfileHost();
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name), ListSortDirection.Ascending));
+ SettingsManager.Current.PropertyChanged += SettingsManager_PropertyChanged;
+ }
- SetProfilesView(new ProfileFilterInfo());
+ #endregion
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
+ #region Profile host
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ protected override ApplicationName ApplicationName => ApplicationName.PowerShell;
- LoadSettings();
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.PowerShell_Enabled;
- SettingsManager.Current.PropertyChanged += SettingsManager_PropertyChanged;
+ protected override string GetSearchableField(ProfileInfo profile) => profile.PowerShell_Host;
- _isLoading = false;
+ ///
+ /// Also mirrors the popup state into so the main window can suppress
+ /// global focus-stealing behavior (e.g. re-focusing the embedded terminal) while the filter popup is open.
+ ///
+ public new ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
+
+ private void OpenProfileFilterAction()
+ {
+ ConfigurationManager.Current.IsProfileFilterPopupOpen = true;
+
+ ProfileFilterIsOpen = true;
}
- private void LoadSettings()
+ ///
+ /// Called when the tag-filter popup closes (including an implicit close, e.g. clicking away), to keep
+ /// in sync.
+ ///
+ public ICommand ProfileFilterPopupClosedCommand => new RelayCommand(_ => OnProfileFilterClosed());
+
+ public void OnProfileFilterClosed()
{
- ExpandProfileView = SettingsManager.Current.PowerShell_ExpandProfileView;
+ ConfigurationManager.Current.IsProfileFilterPopupOpen = false;
+ }
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.PowerShell_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
+ public void OnProfileManagerDialogOpen()
+ {
+ ConfigurationManager.OnDialogOpen();
+ }
- _tempProfileWidth = SettingsManager.Current.PowerShell_ProfileWidth;
+ public void OnProfileManagerDialogClose()
+ {
+ ConfigurationManager.OnDialogClose();
}
#endregion
@@ -393,48 +243,6 @@ private void ConnectProfileExternalAction()
ConnectProfileExternal();
}
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.PowerShell);
- }
-
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager.ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
public ICommand TextBoxSearchGotFocusCommand
{
get { return new RelayCommand(_ => _textBoxSearchIsFocused = true); }
@@ -452,52 +260,6 @@ private void ClearSearchAction()
Search = string.Empty;
}
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- private void OpenProfileFilterAction()
- {
- ConfigurationManager.Current.IsProfileFilterPopupOpen = true;
-
- ProfileFilterIsOpen = true;
- }
-
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- IsProfileFilterSet = true;
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- private void ClearProfileFilterAction()
- {
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
public ICommand OpenSettingsCommand => new RelayCommand(_ => OpenSettingsAction());
private static void OpenSettingsAction()
@@ -562,14 +324,14 @@ private void TryFindExecutable()
///
/// Resolves the actual installation path of a PowerShell executable that was installed via the
/// Microsoft Store / WindowsApps and therefore appears as a proxy stub in the user's AppData.
- ///
+ ///
/// Typical input is a path like:
/// C:\Users\{USERNAME}\AppData\Local\Microsoft\WindowsApps\pwsh.exe
- ///
+ ///
/// This helper attempts to locate the corresponding real executable under the Program Files
/// WindowsApps package layout, e.g.:
/// C:\Program Files\WindowsApps\Microsoft.PowerShell_7.*_8wekyb3d8bbwe\pwsh.exe.
- ///
+ ///
/// Workaround for: https://github.com/BornToBeRoot/NETworkManager/issues/3223
///
/// Path to the pwsh proxy stub, typically located under the current user's %LocalAppData%\Microsoft\WindowsApps\pwsh.exe.
@@ -716,41 +478,6 @@ private static void AddHostToHistory(string host)
SettingsManager.Current.General_HistoryListEntries));
}
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
public void FocusEmbeddedWindow()
{
/* Don't continue if
@@ -780,97 +507,13 @@ public void FocusEmbeddedWindow()
}
}
- public void OnViewVisible()
+ public override void OnViewVisible()
{
- _isViewActive = true;
-
- RefreshProfiles();
+ base.OnViewVisible();
FocusEmbeddedWindow();
}
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.PowerShell_Enabled).SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.PowerShell_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.PowerShell_Host.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any && filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All && filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- SetProfilesView(new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- }, SelectedProfile);
- }
-
- public void OnProfileFilterClosed()
- {
- ConfigurationManager.Current.IsProfileFilterPopupOpen = false;
- }
-
- public void OnProfileManagerDialogOpen()
- {
- ConfigurationManager.OnDialogOpen();
- }
-
- public void OnProfileManagerDialogClose()
- {
- ConfigurationManager.OnDialogClose();
- }
-
private void WriteDefaultProfileToRegistry()
{
if (!SettingsManager.Current.Appearance_PowerShellModifyGlobalProfile)
@@ -890,22 +533,6 @@ private void WriteDefaultProfileToRegistry()
#region Event
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
private void SettingsManager_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
@@ -922,4 +549,4 @@ private void SettingsManager_PropertyChanged(object sender, PropertyChangedEvent
}
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/ProfileHostViewModelBase.cs b/Source/NETworkManager/ViewModels/ProfileHostViewModelBase.cs
new file mode 100644
index 0000000000..4bf0d162e6
--- /dev/null
+++ b/Source/NETworkManager/ViewModels/ProfileHostViewModelBase.cs
@@ -0,0 +1,463 @@
+using NETworkManager.Controls;
+using NETworkManager.Models;
+using NETworkManager.Profiles;
+using NETworkManager.Settings;
+using NETworkManager.Utilities;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Linq;
+using System.Windows;
+using System.Windows.Data;
+using System.Windows.Input;
+using System.Windows.Threading;
+
+namespace NETworkManager.ViewModels;
+
+///
+/// Base class for view models that host the shared profile panel (search, tag filter, group list) next to a
+/// tool-specific view. Holds all profile-panel state/commands that are identical across tools; derived
+/// classes only need to describe how their tool's profiles are identified and searched.
+///
+public abstract class ProfileHostViewModelBase : ViewModelBase, IProfileHostViewModel
+{
+ #region Variables
+
+ private readonly DispatcherTimer _searchDispatcherTimer = new();
+ private bool _searchDisabled;
+ private bool _isViewActive = true;
+
+ ///
+ /// Gets the application name used for profile dialogs (add/edit/copy-as/delete) of this tool.
+ ///
+ protected abstract ApplicationName ApplicationName { get; }
+
+ ///
+ /// Determines whether the given profile is enabled for this tool.
+ ///
+ protected abstract bool IsProfileEnabled(ProfileInfo profile);
+
+ ///
+ /// Gets the tool-specific field of the given profile that should also be matched against the search text
+ /// (in addition to the profile name).
+ ///
+ protected abstract string GetSearchableField(ProfileInfo profile);
+
+ ///
+ /// Gets the view for the profiles.
+ ///
+ public ICollectionView Profiles
+ {
+ get;
+ private set
+ {
+ if (value == field)
+ return;
+
+ field = value;
+ OnPropertyChanged();
+ }
+ }
+
+ ///
+ /// Gets or sets the selected profile. Virtual so tools that need to react to a profile selection (e.g.
+ /// pre-filling other fields from the profile) can override it and still participate in the base class's
+ /// own internal re-selection logic (e.g. in ).
+ ///
+ public virtual ProfileInfo SelectedProfile
+ {
+ get;
+ set
+ {
+ if (value == field)
+ return;
+
+ field = value;
+ OnPropertyChanged();
+ }
+ }
+
+ ///
+ /// Gets or sets the search text.
+ ///
+ public string Search
+ {
+ get;
+ set
+ {
+ if (value == field)
+ return;
+
+ field = value;
+
+ // Start searching...
+ if (!_searchDisabled)
+ {
+ IsSearching = true;
+ _searchDispatcherTimer.Start();
+ }
+
+ OnPropertyChanged();
+ }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether a search is in progress.
+ ///
+ public bool IsSearching
+ {
+ get;
+ set
+ {
+ if (value == field)
+ return;
+
+ field = value;
+ OnPropertyChanged();
+ }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether the profile filter popup is open.
+ ///
+ public bool ProfileFilterIsOpen
+ {
+ get;
+ set
+ {
+ if (value == field)
+ return;
+
+ field = value;
+ OnPropertyChanged();
+ }
+ }
+
+ ///
+ /// Gets the view for the profile filter tags.
+ ///
+ public ICollectionView ProfileFilterTagsView { get; private set; }
+
+ private ObservableCollection ProfileFilterTags { get; } = [];
+
+ ///
+ /// Gets or sets a value indicating whether to match any profile filter tag.
+ ///
+ public bool ProfileFilterTagsMatchAny
+ {
+ get;
+ set
+ {
+ if (value == field)
+ return;
+
+ field = value;
+ OnPropertyChanged();
+ }
+ } = GlobalStaticConfiguration.Profile_TagsMatchAny;
+
+ ///
+ /// Gets or sets a value indicating whether to match all profile filter tags.
+ ///
+ public bool ProfileFilterTagsMatchAll
+ {
+ get;
+ set
+ {
+ if (value == field)
+ return;
+
+ field = value;
+ OnPropertyChanged();
+ }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether a profile filter is currently applied.
+ ///
+ public bool IsProfileFilterSet
+ {
+ get;
+ set
+ {
+ if (value == field)
+ return;
+
+ field = value;
+ OnPropertyChanged();
+ }
+ }
+
+ ///
+ /// Gets the group expander state store for the profile list.
+ ///
+ public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
+
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Initializes the shared profile-panel state. Must be called by derived constructors after their own
+ /// tool-specific initialization (and while _isLoading-equivalent guards, if any, are still active).
+ ///
+ protected void InitializeProfileHost()
+ {
+ CreateTags();
+
+ ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
+ ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
+ ListSortDirection.Ascending));
+
+ SetProfilesView(new ProfileFilterInfo());
+
+ ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
+
+ _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
+ _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ }
+
+ #endregion
+
+ #region ICommands & Actions
+
+ ///
+ /// Gets the command to add a new profile.
+ ///
+ public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
+
+ private void AddProfileAction()
+ {
+ _ = ProfileDialogManager
+ .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName);
+ }
+
+ private bool ModifyProfile_CanExecute(object obj)
+ {
+ return SelectedProfile is { IsDynamic: false };
+ }
+
+ ///
+ /// Gets the command to edit the selected profile.
+ ///
+ public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
+
+ private void EditProfileAction()
+ {
+ _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
+ }
+
+ ///
+ /// Gets the command to copy the selected profile as a new profile.
+ ///
+ public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
+
+ private void CopyAsProfileAction()
+ {
+ _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
+ }
+
+ ///
+ /// Gets the command to delete the selected profile.
+ ///
+ public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
+
+ private void DeleteProfileAction()
+ {
+ _ = ProfileDialogManager
+ .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
+ }
+
+ ///
+ /// Gets the command to edit a group.
+ ///
+ public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
+
+ private void EditGroupAction(object group)
+ {
+ _ = ProfileDialogManager
+ .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
+ }
+
+ ///
+ /// Gets the command to open the profile filter.
+ ///
+ public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
+
+ private void OpenProfileFilterAction()
+ {
+ ProfileFilterIsOpen = true;
+ }
+
+ ///
+ /// Gets the command to apply the profile filter.
+ ///
+ public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
+
+ private void ApplyProfileFilterAction()
+ {
+ RefreshProfiles();
+
+ ProfileFilterIsOpen = false;
+ }
+
+ ///
+ /// Gets the command to clear the profile filter.
+ ///
+ public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
+
+ private void ClearProfileFilterAction()
+ {
+ _searchDisabled = true;
+ Search = string.Empty;
+ _searchDisabled = false;
+
+ foreach (var tag in ProfileFilterTags)
+ tag.IsSelected = false;
+
+ RefreshProfiles();
+
+ IsProfileFilterSet = false;
+ ProfileFilterIsOpen = false;
+ }
+
+ ///
+ /// Gets the command to expand all profile groups.
+ ///
+ public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
+
+ private void ExpandAllProfileGroupsAction()
+ {
+ SetIsExpandedForAllProfileGroups(true);
+ }
+
+ ///
+ /// Gets the command to collapse all profile groups.
+ ///
+ public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
+
+ private void CollapseAllProfileGroupsAction()
+ {
+ SetIsExpandedForAllProfileGroups(false);
+ }
+
+ #endregion
+
+ #region Methods
+
+ private void SetIsExpandedForAllProfileGroups(bool isExpanded)
+ {
+ foreach (var group in Profiles.Groups.Cast())
+ GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
+ }
+
+ ///
+ /// Called when the view becomes visible.
+ ///
+ public virtual void OnViewVisible()
+ {
+ _isViewActive = true;
+
+ RefreshProfiles();
+ }
+
+ ///
+ /// Called when the view is hidden.
+ ///
+ public virtual void OnViewHide()
+ {
+ _isViewActive = false;
+ }
+
+ private void CreateTags()
+ {
+ var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(IsProfileEnabled)
+ .SelectMany(x => x.TagsCollection).Distinct().ToList();
+
+ var tagSet = new HashSet(tags);
+
+ for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
+ {
+ if (!tagSet.Contains(ProfileFilterTags[i].Name))
+ ProfileFilterTags.RemoveAt(i);
+ }
+
+ var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
+
+ foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
+ {
+ ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
+ }
+ }
+
+ private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
+ {
+ Profiles = new CollectionViewSource
+ {
+ Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => IsProfileEnabled(x) && (
+ string.IsNullOrEmpty(filter.Search) ||
+ x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
+ GetSearchableField(x).IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
+ // If no tags are selected, show all profiles
+ (!filter.Tags.Any()) ||
+ // Any tag can match
+ (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
+ filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
+ // All tags must match
+ (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
+ filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
+ ).OrderBy(x => x.Group).ThenBy(x => x.Name)
+ }.View;
+
+ Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
+
+ // Set specific profile or first if null
+ SelectedProfile = null;
+
+ if (profile != null)
+ SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
+ Profiles.Cast().FirstOrDefault();
+ else
+ SelectedProfile = Profiles.Cast().FirstOrDefault();
+ }
+
+ private void RefreshProfiles()
+ {
+ if (!_isViewActive)
+ return;
+
+ var filter = new ProfileFilterInfo
+ {
+ Search = Search,
+ Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
+ TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
+ };
+
+ SetProfilesView(filter, SelectedProfile);
+
+ IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
+ }
+
+ #endregion
+
+ #region Event
+
+ private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
+ {
+ CreateTags();
+
+ RefreshProfiles();
+ }
+
+ private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
+ {
+ _searchDispatcherTimer.Stop();
+
+ RefreshProfiles();
+
+ IsSearching = false;
+ }
+
+ #endregion
+}
diff --git a/Source/NETworkManager/ViewModels/PuTTYHostViewModel.cs b/Source/NETworkManager/ViewModels/PuTTYHostViewModel.cs
index cd18b020a6..67572a1d24 100644
--- a/Source/NETworkManager/ViewModels/PuTTYHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/PuTTYHostViewModel.cs
@@ -1,4 +1,4 @@
-using Dragablz;
+using Dragablz;
using log4net;
using MahApps.Metro.SimpleChildWindow;
using NETworkManager.Controls;
@@ -11,7 +11,6 @@
using NETworkManager.Utilities;
using NETworkManager.Views;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
@@ -19,22 +18,17 @@
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
using PuTTYProfile = NETworkManager.Settings.Application.PuTTY;
namespace NETworkManager.ViewModels;
-public class PuTTYHostViewModel : ViewModelBase, IProfileManager
+public class PuTTYHostViewModel : ProfileHostViewModelBase
{
#region Variables
private static readonly ILog Log = LogManager.GetLogger(typeof(PuTTYHostViewModel));
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
-
public IInterTabClient InterTabClient { get; }
public string InterTabPartition
@@ -52,9 +46,6 @@ public string InterTabPartition
public ObservableCollection TabItems { get; }
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
public bool IsExecutableConfigured
{
get;
@@ -94,172 +85,13 @@ public bool HeaderContextMenuIsOpen
}
}
- #region Profiles
-
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
private bool _textBoxSearchIsFocused;
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ICollectionView ProfileFilterTagsView { get; }
-
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.PuTTY_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.PuTTY_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
+ ///
+ /// Gets or sets a value indicating whether the profile context menu is open. Bound to
+ /// so
+ /// can avoid stealing focus while it is open.
+ ///
public bool ProfileContextMenuIsOpen
{
get;
@@ -275,14 +107,10 @@ public bool ProfileContextMenuIsOpen
#endregion
- #endregion
-
#region Constructor, load settings
public PuTTYHostViewModel()
{
- _isLoading = true;
-
// Check if PuTTY executable is configured
CheckExecutable();
@@ -297,36 +125,53 @@ public PuTTYHostViewModel()
TabItems = [];
- // Profiles
- CreateTags();
+ InitializeProfileHost();
+
+ SettingsManager.Current.PropertyChanged += SettingsManager_PropertyChanged;
+ }
+
+ #endregion
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
+ #region Profile host
- SetProfilesView(new ProfileFilterInfo());
+ protected override ApplicationName ApplicationName => ApplicationName.PuTTY;
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.PuTTY_Enabled;
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ protected override string GetSearchableField(ProfileInfo profile) => profile.PuTTY_HostOrSerialLine;
- LoadSettings();
+ ///
+ /// Also mirrors the popup state into so the main window can suppress
+ /// global focus-stealing behavior (e.g. re-focusing the embedded terminal) while the filter popup is open.
+ ///
+ public new ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
- SettingsManager.Current.PropertyChanged += SettingsManager_PropertyChanged;
+ private void OpenProfileFilterAction()
+ {
+ ConfigurationManager.Current.IsProfileFilterPopupOpen = true;
- _isLoading = false;
+ ProfileFilterIsOpen = true;
}
- private void LoadSettings()
+ ///
+ /// Called when the tag-filter popup closes (including an implicit close, e.g. clicking away), to keep
+ /// in sync.
+ ///
+ public ICommand ProfileFilterPopupClosedCommand => new RelayCommand(_ => OnProfileFilterClosed());
+
+ public void OnProfileFilterClosed()
{
- ExpandProfileView = SettingsManager.Current.PuTTY_ExpandProfileView;
+ ConfigurationManager.Current.IsProfileFilterPopupOpen = false;
+ }
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.PuTTY_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
+ public void OnProfileManagerDialogOpen()
+ {
+ ConfigurationManager.OnDialogOpen();
+ }
- _tempProfileWidth = SettingsManager.Current.PuTTY_ProfileWidth;
+ public void OnProfileManagerDialogClose()
+ {
+ ConfigurationManager.OnDialogClose();
}
#endregion
@@ -406,49 +251,6 @@ private void ConnectProfileExternalAction()
ConnectProfileExternal();
}
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.PuTTY);
- }
-
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
public ICommand TextBoxSearchGotFocusCommand
{
get { return new RelayCommand(_ => _textBoxSearchIsFocused = true); }
@@ -459,55 +261,6 @@ public ICommand TextBoxSearchLostFocusCommand
get { return new RelayCommand(_ => _textBoxSearchIsFocused = false); }
}
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- private void OpenProfileFilterAction()
- {
- ConfigurationManager.Current.IsProfileFilterPopupOpen = true;
-
- ProfileFilterIsOpen = true;
- }
-
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
public ICommand OpenSettingsCommand => new RelayCommand(_ => OpenSettingsAction());
private static void OpenSettingsAction()
@@ -720,41 +473,6 @@ private static void AddProfileToHistory(string profile)
SettingsManager.Current.General_HistoryListEntries));
}
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
public void FocusEmbeddedWindow()
{
/* Don't continue if
@@ -784,104 +502,13 @@ public void FocusEmbeddedWindow()
}
}
- public void OnViewVisible()
+ public override void OnViewVisible()
{
- _isViewActive = true;
-
- RefreshProfiles();
+ base.OnViewVisible();
FocusEmbeddedWindow();
}
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.PuTTY_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.PuTTY_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.PuTTY_HostOrSerialLine.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
- public void OnProfileFilterClosed()
- {
- ConfigurationManager.Current.IsProfileFilterPopupOpen = false;
- }
-
- public void OnProfileManagerDialogOpen()
- {
- ConfigurationManager.OnDialogOpen();
- }
-
- public void OnProfileManagerDialogClose()
- {
- ConfigurationManager.OnDialogClose();
- }
-
private void WriteDefaultProfileToRegistry()
{
if (!IsExecutableConfigured)
@@ -909,21 +536,5 @@ private void SettingsManager_PropertyChanged(object sender, PropertyChangedEvent
}
}
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs b/Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs
index 22a6b4d159..ca67aba5b5 100644
--- a/Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs
@@ -1,4 +1,4 @@
-using Dragablz;
+using Dragablz;
using MahApps.Metro.SimpleChildWindow;
using NETworkManager.Controls;
using NETworkManager.Localization.Resources;
@@ -11,25 +11,19 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
using RemoteDesktop = NETworkManager.Profiles.Application.RemoteDesktop;
namespace NETworkManager.ViewModels;
-public class RemoteDesktopHostViewModel : ViewModelBase, IProfileManager
+public class RemoteDesktopHostViewModel : ProfileHostViewModelBase
{
#region Variables
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
-
public IInterTabClient InterTabClient { get; }
public string InterTabPartition
@@ -47,9 +41,6 @@ public string InterTabPartition
public ObservableCollection TabItems { get; }
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
public int SelectedTabIndex
{
get;
@@ -63,213 +54,38 @@ public int SelectedTabIndex
}
}
- #region Profiles
-
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ICollectionView ProfileFilterTagsView { get; }
-
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.RemoteDesktop_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.RemoteDesktop_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
#endregion
- #endregion
-
- #region Constructor, load settings
+ #region Constructor
public RemoteDesktopHostViewModel()
{
- _isLoading = true;
-
InterTabClient = new DragablzInterTabClient(ApplicationName.RemoteDesktop);
InterTabPartition = nameof(ApplicationName.RemoteDesktop);
TabItems = [];
- // Profiles
- CreateTags();
+ InitializeProfileHost();
+ }
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
+ #endregion
- SetProfilesView(new ProfileFilterInfo());
+ #region Profile host
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
+ protected override ApplicationName ApplicationName => ApplicationName.RemoteDesktop;
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.RemoteDesktop_Enabled;
- LoadSettings();
+ protected override string GetSearchableField(ProfileInfo profile) => profile.RemoteDesktop_Host;
- _isLoading = false;
+ public void OnProfileManagerDialogOpen()
+ {
+ ConfigurationManager.OnDialogOpen();
}
- private void LoadSettings()
+ public void OnProfileManagerDialogClose()
{
- ExpandProfileView = SettingsManager.Current.RemoteDesktop_ExpandProfileView;
-
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.RemoteDesktop_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
-
- _tempProfileWidth = SettingsManager.Current.RemoteDesktop_ProfileWidth;
+ ConfigurationManager.OnDialogClose();
}
#endregion
@@ -421,103 +237,6 @@ private void ConnectProfileExternalAction()
Process.Start("mstsc.exe", args);
}
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.RemoteDesktop);
- }
-
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
- public ItemActionCallback CloseItemCommand => CloseItemAction;
-
- private static void CloseItemAction(ItemActionCallbackArgs args)
- {
- ((args.DragablzItem.Content as DragablzTabItem)?.View as IDragablzTabItem)?.CloseTab();
- }
-
#endregion
#region Methods
@@ -678,151 +397,5 @@ private static void AddHostToHistory(string host)
SettingsManager.Current.General_HistoryListEntries));
}
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
- public void OnViewVisible()
- {
- _isViewActive = true;
-
- RefreshProfiles();
- }
-
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.RemoteDesktop_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.RemoteDesktop_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.RemoteDesktop_Host.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
- public void OnProfileManagerDialogOpen()
- {
- ConfigurationManager.OnDialogOpen();
- }
-
- public void OnProfileManagerDialogClose()
- {
- ConfigurationManager.OnDialogClose();
- }
-
- #endregion
-
- #region Event
-
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/SNMPHostViewModel.cs b/Source/NETworkManager/ViewModels/SNMPHostViewModel.cs
index d50abcb2d7..f73e4a0601 100644
--- a/Source/NETworkManager/ViewModels/SNMPHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/SNMPHostViewModel.cs
@@ -1,32 +1,22 @@
-using Dragablz;
+using Dragablz;
using NETworkManager.Controls;
using NETworkManager.Localization.Resources;
using NETworkManager.Models;
using NETworkManager.Models.Network;
using NETworkManager.Profiles;
using NETworkManager.Profiles.Application;
-using NETworkManager.Settings;
using NETworkManager.Utilities;
using NETworkManager.Views;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.Linq;
-using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
namespace NETworkManager.ViewModels;
-public class SNMPHostViewModel : ViewModelBase, IProfileManager
+public class SNMPHostViewModel : ProfileHostViewModelBase
{
#region Variables
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
-
public IInterTabClient InterTabClient { get; }
public string InterTabPartition
@@ -44,9 +34,6 @@ public string InterTabPartition
public ObservableCollection TabItems { get; }
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
public int SelectedTabIndex
{
get;
@@ -60,215 +47,30 @@ public int SelectedTabIndex
}
}
- #region Profiles
-
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ICollectionView ProfileFilterTagsView { get; }
-
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.SNMP_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.SNMP_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
- #endregion
-
#endregion
- #region Constructor, load settings
+ #region Constructor
public SNMPHostViewModel()
{
- _isLoading = true;
-
InterTabClient = new DragablzInterTabClient(ApplicationName.SNMP);
InterTabPartition = nameof(ApplicationName.SNMP);
TabItems = [];
AddTab();
- // Profiles
- CreateTags();
-
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
-
- SetProfilesView(new ProfileFilterInfo());
-
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
-
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ InitializeProfileHost();
+ }
- LoadSettings();
+ #endregion
- _isLoading = false;
- }
+ #region Profile host
- private void LoadSettings()
- {
- ExpandProfileView = SettingsManager.Current.SNMP_ExpandProfileView;
+ protected override ApplicationName ApplicationName => ApplicationName.SNMP;
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.SNMP_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.SNMP_Enabled;
- _tempProfileWidth = SettingsManager.Current.SNMP_ProfileWidth;
- }
+ protected override string GetSearchableField(ProfileInfo profile) => profile.SNMP_Host;
#endregion
@@ -293,96 +95,6 @@ private void AddTabProfileAction()
AddTab(SelectedProfile);
}
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.SNMP);
- }
-
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
public ItemActionCallback CloseItemCommand => CloseItemAction;
private static void CloseItemAction(ItemActionCallbackArgs args)
@@ -393,40 +105,6 @@ private static void CloseItemAction(ItemActionCallbackArgs args)
#endregion
#region Methods
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
private void AddTab(SNMPSessionInfo sessionInfo, string header = null)
{
@@ -461,106 +139,5 @@ private void AddTab(ProfileInfo profile)
AddTab(sessionInfo, profile.Name);
}
- public void OnViewVisible()
- {
- _isViewActive = true;
-
- RefreshProfiles();
- }
-
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.SNMP_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.SNMP_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.SNMP_Host.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
- #endregion
-
- #region Event
-
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/TigerVNCHostViewModel.cs b/Source/NETworkManager/ViewModels/TigerVNCHostViewModel.cs
index f06888b4cf..e049749fa0 100644
--- a/Source/NETworkManager/ViewModels/TigerVNCHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/TigerVNCHostViewModel.cs
@@ -1,4 +1,4 @@
-using Dragablz;
+using Dragablz;
using MahApps.Metro.SimpleChildWindow;
using NETworkManager.Controls;
using NETworkManager.Localization.Resources;
@@ -10,7 +10,6 @@
using NETworkManager.Utilities;
using NETworkManager.Views;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
@@ -18,18 +17,14 @@
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
using TigerVNC = NETworkManager.Profiles.Application.TigerVNC;
namespace NETworkManager.ViewModels;
-public class TigerVNCHostViewModel : ViewModelBase, IProfileManager
+public class TigerVNCHostViewModel : ProfileHostViewModelBase
{
#region Variables
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
public IInterTabClient InterTabClient { get; }
@@ -48,9 +43,6 @@ public string InterTabPartition
public ObservableCollection TabItems { get; }
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
public bool IsConfigured
{
get;
@@ -77,180 +69,12 @@ public int SelectedTabIndex
}
}
- #region Profiles
-
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ICollectionView ProfileFilterTagsView { get; }
-
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.TigerVNC_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.TigerVNC_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
- #endregion
-
#endregion
#region Constructor, load settings
public TigerVNCHostViewModel()
{
- _isLoading = true;
-
CheckSettings();
InterTabClient = new DragablzInterTabClient(ApplicationName.TigerVNC);
@@ -258,36 +82,29 @@ public TigerVNCHostViewModel()
TabItems = [];
- // Profiles
- CreateTags();
+ InitializeProfileHost();
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
+ SettingsManager.Current.PropertyChanged += SettingsManager_PropertyChanged;
+ }
- SetProfilesView(new ProfileFilterInfo());
+ #endregion
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
+ #region Profile host
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ protected override ApplicationName ApplicationName => ApplicationName.TigerVNC;
- LoadSettings();
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.TigerVNC_Enabled;
- SettingsManager.Current.PropertyChanged += SettingsManager_PropertyChanged;
+ protected override string GetSearchableField(ProfileInfo profile) => profile.TigerVNC_Host;
- _isLoading = false;
+ public void OnProfileManagerDialogOpen()
+ {
+ ConfigurationManager.OnDialogOpen();
}
- private void LoadSettings()
+ public void OnProfileManagerDialogClose()
{
- ExpandProfileView = SettingsManager.Current.TigerVNC_ExpandProfileView;
-
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.TigerVNC_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
-
- _tempProfileWidth = SettingsManager.Current.TigerVNC_ProfileWidth;
+ ConfigurationManager.OnDialogClose();
}
#endregion
@@ -343,96 +160,6 @@ private void ConnectProfileExternalAction()
ConnectProfileExternal();
}
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.TigerVNC);
- }
-
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
public ICommand OpenSettingsCommand => new RelayCommand(_ => OpenSettingsAction());
private static void OpenSettingsAction()
@@ -549,152 +276,10 @@ private static void AddPortToHistory(int port)
SettingsManager.Current.General_HistoryListEntries));
}
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
- public void OnViewVisible()
- {
- _isViewActive = true;
-
- RefreshProfiles();
- }
-
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.TigerVNC_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.TigerVNC_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.TigerVNC_Host.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
- public void OnProfileManagerDialogOpen()
- {
- ConfigurationManager.OnDialogOpen();
- }
-
- public void OnProfileManagerDialogClose()
- {
- ConfigurationManager.OnDialogClose();
- }
-
#endregion
#region Event
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
private void SettingsManager_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(SettingsInfo.TigerVNC_ApplicationFilePath))
@@ -702,4 +287,4 @@ private void SettingsManager_PropertyChanged(object sender, PropertyChangedEvent
}
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/TracerouteHostViewModel.cs b/Source/NETworkManager/ViewModels/TracerouteHostViewModel.cs
index 4f404b8e2a..40407b6d5f 100644
--- a/Source/NETworkManager/ViewModels/TracerouteHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/TracerouteHostViewModel.cs
@@ -1,30 +1,20 @@
-using Dragablz;
+using Dragablz;
using NETworkManager.Controls;
using NETworkManager.Localization.Resources;
using NETworkManager.Models;
using NETworkManager.Profiles;
-using NETworkManager.Settings;
using NETworkManager.Utilities;
using NETworkManager.Views;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.Linq;
-using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
namespace NETworkManager.ViewModels;
-public class TracerouteHostViewModel : ViewModelBase, IProfileManager
+public class TracerouteHostViewModel : ProfileHostViewModelBase
{
#region Variables
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
-
public IInterTabClient InterTabClient { get; }
public string InterTabPartition
@@ -42,9 +32,6 @@ public string InterTabPartition
public ObservableCollection TabItems { get; }
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
public int SelectedTabIndex
{
get;
@@ -58,180 +45,12 @@ public int SelectedTabIndex
}
}
- #region Profiles
-
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ICollectionView ProfileFilterTagsView { get; }
-
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.Traceroute_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.Traceroute_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
- #endregion
-
#endregion
- #region Constructor, load settings
+ #region Constructor
public TracerouteHostViewModel()
{
- _isLoading = true;
-
InterTabClient = new DragablzInterTabClient(ApplicationName.Traceroute);
InterTabPartition = nameof(ApplicationName.Traceroute);
@@ -242,35 +61,18 @@ public TracerouteHostViewModel()
new DragablzTabItem(Strings.NewTab, new TracerouteView(tabId), tabId)
];
- // Profiles
- CreateTags();
-
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
-
- SetProfilesView(new ProfileFilterInfo());
-
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
-
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ InitializeProfileHost();
+ }
- LoadSettings();
+ #endregion
- _isLoading = false;
- }
+ #region Profile host
- private void LoadSettings()
- {
- ExpandProfileView = SettingsManager.Current.Traceroute_ExpandProfileView;
+ protected override ApplicationName ApplicationName => ApplicationName.Traceroute;
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.Traceroute_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.Traceroute_Enabled;
- _tempProfileWidth = SettingsManager.Current.Traceroute_ProfileWidth;
- }
+ protected override string GetSearchableField(ProfileInfo profile) => profile.Traceroute_Host;
#endregion
@@ -295,96 +97,6 @@ private void TraceProfileAction()
AddTab(SelectedProfile);
}
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.Traceroute);
- }
-
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
public ItemActionCallback CloseItemCommand => CloseItemAction;
private void CloseItemAction(ItemActionCallbackArgs args)
@@ -396,41 +108,6 @@ private void CloseItemAction(ItemActionCallbackArgs args)
#region Methods
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
public void AddTab(string host = null)
{
var tabId = Guid.NewGuid();
@@ -446,106 +123,5 @@ public void AddTab(ProfileInfo profile)
AddTab(profile.Traceroute_Host);
}
- public void OnViewVisible()
- {
- _isViewActive = true;
-
- RefreshProfiles();
- }
-
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.Traceroute_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.Traceroute_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.Traceroute_Host.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
- #endregion
-
- #region Event
-
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/WakeOnLANViewModel.cs b/Source/NETworkManager/ViewModels/WakeOnLANViewModel.cs
index 7b122efc71..335d64d2f8 100644
--- a/Source/NETworkManager/ViewModels/WakeOnLANViewModel.cs
+++ b/Source/NETworkManager/ViewModels/WakeOnLANViewModel.cs
@@ -1,4 +1,4 @@
-using MahApps.Metro.Controls;
+using MahApps.Metro.Controls;
using NETworkManager.Localization.Resources;
using NETworkManager.Models;
using NETworkManager.Models.Network;
@@ -6,7 +6,6 @@
using NETworkManager.Settings;
using NETworkManager.Utilities;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
@@ -15,24 +14,16 @@
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
-using NETworkManager.Controls;
namespace NETworkManager.ViewModels;
///
/// ViewModel for the Wake on LAN feature.
///
-public class WakeOnLANViewModel : ViewModelBase, IProfileManager
+public class WakeOnLANViewModel : ProfileHostViewModelBase
{
#region Variables
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
-
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
///
/// Gets or sets a value indicating whether the Wake on LAN operation is running.
///
@@ -123,33 +114,16 @@ private set
}
}
- #region Profiles
-
- ///
- /// Gets the collection view for the profiles.
- ///
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
///
- /// Gets or sets the currently selected profile.
+ /// Gets or sets the currently selected profile. Pre-fills /
+ /// from the profile, unless a wake-up is currently running.
///
- public ProfileInfo SelectedProfile
+ public override ProfileInfo SelectedProfile
{
- get;
+ get => base.SelectedProfile;
set
{
- if (value == field)
+ if (value == base.SelectedProfile)
return;
if (value != null && !IsRunning)
@@ -158,205 +132,35 @@ public ProfileInfo SelectedProfile
Broadcast = value.WakeOnLAN_Broadcast;
}
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- ///
- /// Gets or sets the search text for filtering profiles.
- ///
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether a search operation is in progress.
- ///
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets or sets a value indicating whether the profile filter flyout is open.
- ///
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- ///
- /// Gets the collection view for the profile filter tags.
- ///
- public ICollectionView ProfileFilterTagsView { get; }
-
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.WakeOnLAN_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.WakeOnLAN_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
+ base.SelectedProfile = value;
}
}
#endregion
- #endregion
-
- #region Constructor, load settings
+ #region Constructor
///
/// Initializes a new instance of the class.
///
public WakeOnLANViewModel()
{
- _isLoading = true;
-
MACAddressHistoryView =
CollectionViewSource.GetDefaultView(SettingsManager.Current.WakeOnLan_MACAddressHistory);
BroadcastHistoryView = CollectionViewSource.GetDefaultView(SettingsManager.Current.WakeOnLan_BroadcastHistory);
- // Profiles
- CreateTags();
-
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
-
- SetProfilesView(new ProfileFilterInfo());
+ InitializeProfileHost();
+ }
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
+ #endregion
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ #region Profile host
- LoadSettings();
+ protected override ApplicationName ApplicationName => ApplicationName.WakeOnLAN;
- _isLoading = false;
- }
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.WakeOnLAN_Enabled;
- private void LoadSettings()
- {
- ExpandProfileView = SettingsManager.Current.WakeOnLAN_ExpandProfileView;
-
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.WakeOnLAN_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
-
- _tempProfileWidth = SettingsManager.Current.WakeOnLAN_ProfileWidth;
- }
+ protected override string GetSearchableField(ProfileInfo profile) => profile.WakeOnLAN_MACAddress;
#endregion
@@ -399,125 +203,6 @@ private void WakeUpProfileAction()
_ = WakeUp(NETworkManager.Profiles.Application.WakeOnLAN.CreateInfo(SelectedProfile));
}
- ///
- /// Gets the command to add a new profile.
- ///
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.WakeOnLAN);
- }
-
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- ///
- /// Gets the command to edit the selected profile.
- ///
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to copy the selected profile as a new profile.
- ///
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- ///
- /// Gets the command to delete the selected profile.
- ///
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- ///
- /// Gets the command to edit a profile group.
- ///
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- ///
- /// Gets the command to open the profile filter flyout.
- ///
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- ///
- /// Gets the command to apply the profile filter.
- ///
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to clear the profile filter.
- ///
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- ///
- /// Gets the command to expand all profile groups.
- ///
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- ///
- /// Gets the command to collapse all profile groups.
- ///
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
#endregion
#region Methods
@@ -574,141 +259,5 @@ private void AddBroadcastToHistory(string broadcast)
list.ForEach(x => SettingsManager.Current.WakeOnLan_BroadcastHistory.Add(x));
}
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
- public void OnViewVisible()
- {
- _isViewActive = true;
-
- RefreshProfiles();
- }
-
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.WakeOnLAN_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.WakeOnLAN_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.WakeOnLAN_MACAddress.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
- #endregion
-
- #region Event
-
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/WebConsoleHostViewModel.cs b/Source/NETworkManager/ViewModels/WebConsoleHostViewModel.cs
index e2457f8543..8b33ce0697 100644
--- a/Source/NETworkManager/ViewModels/WebConsoleHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/WebConsoleHostViewModel.cs
@@ -1,4 +1,4 @@
-using Dragablz;
+using Dragablz;
using MahApps.Metro.SimpleChildWindow;
using Microsoft.Web.WebView2.Core;
using NETworkManager.Controls;
@@ -12,25 +12,18 @@
using NETworkManager.Utilities;
using NETworkManager.Views;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
namespace NETworkManager.ViewModels;
-public class WebConsoleHostViewModel : ViewModelBase, IProfileManager
+public class WebConsoleHostViewModel : ProfileHostViewModelBase
{
#region Variables
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
-
public IInterTabClient InterTabClient { get; }
public string InterTabPartition
@@ -48,9 +41,6 @@ public string InterTabPartition
public ObservableCollection TabItems { get; }
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
///
/// Variable indicates if the Edge WebView2 runtime is available.
///
@@ -80,180 +70,12 @@ public int SelectedTabIndex
}
}
- #region Profiles
-
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ICollectionView ProfileFilterTagsView { get; }
-
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.WebConsole_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.WebConsole_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
#endregion
- #endregion
-
- #region Constructor, load settings
+ #region Constructor
public WebConsoleHostViewModel()
{
- _isLoading = true;
-
try
{
CoreWebView2Environment.GetAvailableBrowserVersionString();
@@ -269,34 +91,27 @@ public WebConsoleHostViewModel()
TabItems = [];
- // Profiles
- CreateTags();
+ InitializeProfileHost();
+ }
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
+ #endregion
- SetProfilesView(new ProfileFilterInfo());
+ #region Profile host
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
+ protected override ApplicationName ApplicationName => ApplicationName.WebConsole;
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.WebConsole_Enabled;
- LoadSettings();
+ protected override string GetSearchableField(ProfileInfo profile) => profile.WebConsole_Url;
- _isLoading = false;
+ public void OnProfileManagerDialogOpen()
+ {
+ ConfigurationManager.OnDialogOpen();
}
- private void LoadSettings()
+ public void OnProfileManagerDialogClose()
{
- ExpandProfileView = SettingsManager.Current.WebConsole_ExpandProfileView;
-
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.WebConsole_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
-
- _tempProfileWidth = SettingsManager.Current.WebConsole_ProfileWidth;
+ ConfigurationManager.OnDialogClose();
}
#endregion
@@ -338,96 +153,6 @@ private void ConnectProfileAction()
ConnectProfile();
}
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.WebConsole);
- }
-
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
public ICommand OpenSettingsCommand => new RelayCommand(_ => OpenSettingsAction());
private static void OpenSettingsAction()
@@ -514,151 +239,5 @@ private static void AddUrlToHistory(string url)
SettingsManager.Current.General_HistoryListEntries));
}
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
-
- public void OnViewVisible()
- {
- _isViewActive = true;
-
- RefreshProfiles();
- }
-
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.WebConsole_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.WebConsole_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.WebConsole_Url.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
- public void OnProfileManagerDialogOpen()
- {
- ConfigurationManager.OnDialogOpen();
- }
-
- public void OnProfileManagerDialogClose()
- {
- ConfigurationManager.OnDialogClose();
- }
-
- #endregion
-
- #region Event
-
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/ViewModels/WhoisHostViewModel.cs b/Source/NETworkManager/ViewModels/WhoisHostViewModel.cs
index 86e8074257..6a1ecd6199 100644
--- a/Source/NETworkManager/ViewModels/WhoisHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/WhoisHostViewModel.cs
@@ -1,30 +1,20 @@
-using Dragablz;
+using Dragablz;
using NETworkManager.Controls;
using NETworkManager.Localization.Resources;
using NETworkManager.Models;
using NETworkManager.Profiles;
-using NETworkManager.Settings;
using NETworkManager.Utilities;
using NETworkManager.Views;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.Linq;
-using System.Windows;
-using System.Windows.Data;
using System.Windows.Input;
-using System.Windows.Threading;
namespace NETworkManager.ViewModels;
-public class WhoisHostViewModel : ViewModelBase, IProfileManager
+public class WhoisHostViewModel : ProfileHostViewModelBase
{
#region Variables
- private readonly DispatcherTimer _searchDispatcherTimer = new();
- private bool _searchDisabled;
-
public IInterTabClient InterTabClient { get; }
public string InterTabPartition
@@ -42,9 +32,6 @@ public string InterTabPartition
public ObservableCollection TabItems { get; }
- private readonly bool _isLoading;
- private bool _isViewActive = true;
-
public int SelectedTabIndex
{
get;
@@ -58,180 +45,12 @@ public int SelectedTabIndex
}
}
- #region Profiles
-
- public ICollectionView Profiles
- {
- get;
- private set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ProfileInfo SelectedProfile
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = new();
-
- public string Search
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
-
- // Start searching...
- if (!_searchDisabled)
- {
- IsSearching = true;
- _searchDispatcherTimer.Start();
- }
-
- OnPropertyChanged();
- }
- }
-
- public bool IsSearching
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool ProfileFilterIsOpen
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public ICollectionView ProfileFilterTagsView { get; }
-
- private ObservableCollection ProfileFilterTags { get; } = [];
-
- public bool ProfileFilterTagsMatchAny
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- } = GlobalStaticConfiguration.Profile_TagsMatchAny;
-
- public bool ProfileFilterTagsMatchAll
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public bool IsProfileFilterSet
- {
- get;
- set
- {
- if (value == field)
- return;
-
- field = value;
- OnPropertyChanged();
- }
- }
-
- public GroupExpanderStateStore GroupExpanderStateStore { get; } = new();
-
- private bool _canProfileWidthChange = true;
- private double _tempProfileWidth;
-
- public bool ExpandProfileView
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading)
- SettingsManager.Current.Whois_ExpandProfileView = value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(false);
-
- OnPropertyChanged();
- }
- }
-
- public GridLength ProfileWidth
- {
- get;
- set
- {
- if (value == field)
- return;
-
- if (!_isLoading && Math.Abs(value.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix) // Do not save the size when collapsed
- SettingsManager.Current.Whois_ProfileWidth = value.Value;
-
- field = value;
-
- if (_canProfileWidthChange)
- ResizeProfile(true);
-
- OnPropertyChanged();
- }
- }
-
- #endregion
-
#endregion
#region Constructor
public WhoisHostViewModel()
{
- _isLoading = true;
-
InterTabClient = new DragablzInterTabClient(ApplicationName.Whois);
InterTabPartition = nameof(ApplicationName.Whois);
@@ -242,35 +61,18 @@ public WhoisHostViewModel()
new DragablzTabItem(Strings.NewTab, new WhoisView(tabId), tabId)
];
- // Profiles
- CreateTags();
-
- ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
- ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name),
- ListSortDirection.Ascending));
-
- SetProfilesView(new ProfileFilterInfo());
-
- ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
-
- _searchDispatcherTimer.Interval = GlobalStaticConfiguration.SearchDispatcherTimerTimeSpan;
- _searchDispatcherTimer.Tick += SearchDispatcherTimer_Tick;
+ InitializeProfileHost();
+ }
- LoadSettings();
+ #endregion
- _isLoading = false;
- }
+ #region Profile host
- private void LoadSettings()
- {
- ExpandProfileView = SettingsManager.Current.Whois_ExpandProfileView;
+ protected override ApplicationName ApplicationName => ApplicationName.Whois;
- ProfileWidth = ExpandProfileView
- ? new GridLength(SettingsManager.Current.Whois_ProfileWidth)
- : new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
+ protected override bool IsProfileEnabled(ProfileInfo profile) => profile.Whois_Enabled;
- _tempProfileWidth = SettingsManager.Current.Whois_ProfileWidth;
- }
+ protected override string GetSearchableField(ProfileInfo profile) => profile.Whois_Domain;
#endregion
@@ -295,96 +97,6 @@ private void QueryProfileAction()
AddTab(SelectedProfile.Whois_Domain);
}
- public ICommand AddProfileCommand => new RelayCommand(_ => AddProfileAction());
-
- private void AddProfileAction()
- {
- _ = ProfileDialogManager
- .ShowAddProfileDialog(Application.Current.MainWindow, this, null, null, ApplicationName.Whois);
- }
-
- private bool ModifyProfile_CanExecute(object obj)
- {
- return SelectedProfile is { IsDynamic: false };
- }
-
- public ICommand EditProfileCommand => new RelayCommand(_ => EditProfileAction(), ModifyProfile_CanExecute);
-
- private void EditProfileAction()
- {
- _ = ProfileDialogManager.ShowEditProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand CopyAsProfileCommand => new RelayCommand(_ => CopyAsProfileAction(), ModifyProfile_CanExecute);
-
- private void CopyAsProfileAction()
- {
- _ = ProfileDialogManager.ShowCopyAsProfileDialog(Application.Current.MainWindow, this, SelectedProfile);
- }
-
- public ICommand DeleteProfileCommand => new RelayCommand(_ => DeleteProfileAction(), ModifyProfile_CanExecute);
-
- private void DeleteProfileAction()
- {
- _ = ProfileDialogManager
- .ShowDeleteProfileDialog(Application.Current.MainWindow, this, new List { SelectedProfile });
- }
-
- public ICommand EditGroupCommand => new RelayCommand(EditGroupAction);
-
- private void EditGroupAction(object group)
- {
- _ = ProfileDialogManager
- .ShowEditGroupDialog(Application.Current.MainWindow, this, ProfileManager.GetGroupByName($"{group}"));
- }
-
- public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
-
- private void OpenProfileFilterAction()
- {
- ProfileFilterIsOpen = true;
- }
-
- public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
-
- private void ApplyProfileFilterAction()
- {
- RefreshProfiles();
-
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
-
- private void ClearProfileFilterAction()
- {
- _searchDisabled = true;
- Search = string.Empty;
- _searchDisabled = false;
-
- foreach (var tag in ProfileFilterTags)
- tag.IsSelected = false;
-
- RefreshProfiles();
-
- IsProfileFilterSet = false;
- ProfileFilterIsOpen = false;
- }
-
- public ICommand ExpandAllProfileGroupsCommand => new RelayCommand(_ => ExpandAllProfileGroupsAction());
-
- private void ExpandAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(true);
- }
-
- public ICommand CollapseAllProfileGroupsCommand => new RelayCommand(_ => CollapseAllProfileGroupsAction());
-
- private void CollapseAllProfileGroupsAction()
- {
- SetIsExpandedForAllProfileGroups(false);
- }
-
public ItemActionCallback CloseItemCommand => CloseItemAction;
private static void CloseItemAction(ItemActionCallbackArgs args)
@@ -395,40 +107,6 @@ private static void CloseItemAction(ItemActionCallbackArgs args)
#endregion
#region Methods
- private void SetIsExpandedForAllProfileGroups(bool isExpanded)
- {
- foreach (var group in Profiles.Groups.Cast())
- GroupExpanderStateStore[group.Name.ToString()] = isExpanded;
- }
-
- private void ResizeProfile(bool dueToChangedSize)
- {
- _canProfileWidthChange = false;
-
- if (dueToChangedSize)
- {
- ExpandProfileView = Math.Abs(ProfileWidth.Value - GlobalStaticConfiguration.Profile_WidthCollapsed) >
- GlobalStaticConfiguration.FloatPointFix;
- }
- else
- {
- if (ExpandProfileView)
- {
- ProfileWidth =
- Math.Abs(_tempProfileWidth - GlobalStaticConfiguration.Profile_WidthCollapsed) <
- GlobalStaticConfiguration.FloatPointFix
- ? new GridLength(GlobalStaticConfiguration.Profile_DefaultWidthExpanded)
- : new GridLength(_tempProfileWidth);
- }
- else
- {
- _tempProfileWidth = ProfileWidth.Value;
- ProfileWidth = new GridLength(GlobalStaticConfiguration.Profile_WidthCollapsed);
- }
- }
-
- _canProfileWidthChange = true;
- }
private void AddTab(string domain = null)
{
@@ -440,106 +118,5 @@ private void AddTab(string domain = null)
SelectedTabIndex = TabItems.Count - 1;
}
- public void OnViewVisible()
- {
- _isViewActive = true;
-
- RefreshProfiles();
- }
-
- public void OnViewHide()
- {
- _isViewActive = false;
- }
-
- private void CreateTags()
- {
- var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.Whois_Enabled)
- .SelectMany(x => x.TagsCollection).Distinct().ToList();
-
- var tagSet = new HashSet(tags);
-
- for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
- {
- if (!tagSet.Contains(ProfileFilterTags[i].Name))
- ProfileFilterTags.RemoveAt(i);
- }
-
- var existingTagNames = new HashSet(ProfileFilterTags.Select(ft => ft.Name));
-
- foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
- {
- ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
- }
- }
-
- private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
- {
- Profiles = new CollectionViewSource
- {
- Source = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(x => x.Whois_Enabled && (
- string.IsNullOrEmpty(filter.Search) ||
- x.Name.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1 ||
- x.Whois_Domain.IndexOf(filter.Search, StringComparison.OrdinalIgnoreCase) > -1) && (
- // If no tags are selected, show all profiles
- (!filter.Tags.Any()) ||
- // Any tag can match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.Any &&
- filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
- // All tags must match
- (filter.TagsFilterMatch == ProfileFilterTagsMatch.All &&
- filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
- ).OrderBy(x => x.Group).ThenBy(x => x.Name)
- }.View;
-
- Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
-
- // Set specific profile or first if null
- SelectedProfile = null;
-
- if (profile != null)
- SelectedProfile = Profiles.Cast().FirstOrDefault(x => x.Equals(profile)) ??
- Profiles.Cast().FirstOrDefault();
- else
- SelectedProfile = Profiles.Cast().FirstOrDefault();
- }
-
- private void RefreshProfiles()
- {
- if (!_isViewActive)
- return;
-
- var filter = new ProfileFilterInfo
- {
- Search = Search,
- Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
- TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
- };
-
- SetProfilesView(filter, SelectedProfile);
-
- IsProfileFilterSet = !string.IsNullOrEmpty(filter.Search) || filter.Tags.Any();
- }
-
- #endregion
-
- #region Event
-
- private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
- {
- CreateTags();
-
- RefreshProfiles();
- }
-
- private void SearchDispatcherTimer_Tick(object sender, EventArgs e)
- {
- _searchDispatcherTimer.Stop();
-
- RefreshProfiles();
-
- IsSearching = false;
- }
-
#endregion
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/Controls/ProfileExpanderPanel.xaml b/Source/NETworkManager/Views/Controls/ProfileExpanderPanel.xaml
new file mode 100644
index 0000000000..a5955d852f
--- /dev/null
+++ b/Source/NETworkManager/Views/Controls/ProfileExpanderPanel.xaml
@@ -0,0 +1,625 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/NETworkManager/Views/Controls/ProfileExpanderPanel.xaml.cs b/Source/NETworkManager/Views/Controls/ProfileExpanderPanel.xaml.cs
new file mode 100644
index 0000000000..5ea10c8ba2
--- /dev/null
+++ b/Source/NETworkManager/Views/Controls/ProfileExpanderPanel.xaml.cs
@@ -0,0 +1,132 @@
+using System;
+using System.Collections;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+
+namespace NETworkManager.Views.Controls;
+
+///
+/// Reusable profile panel (search, tag filter, group list) shared by every tool view that hosts profiles.
+/// Tool-specific parts (context menu, item tooltip, "run" action) are supplied by the host view through
+/// dependency properties; everything else is identical across tools.
+///
+public partial class ProfileExpanderPanel
+{
+ public static readonly DependencyProperty ProfileItemTemplateProperty = DependencyProperty.Register(
+ nameof(ProfileItemTemplate), typeof(DataTemplate), typeof(ProfileExpanderPanel));
+
+ ///
+ /// Gets or sets the item template used for a profile in the list (defines the tool-specific tooltip).
+ ///
+ public DataTemplate ProfileItemTemplate
+ {
+ get => (DataTemplate)GetValue(ProfileItemTemplateProperty);
+ set => SetValue(ProfileItemTemplateProperty, value);
+ }
+
+ public static readonly DependencyProperty ProfileContextMenuExtraItemsProperty = DependencyProperty.Register(
+ nameof(ProfileContextMenuExtraItems), typeof(IEnumerable), typeof(ProfileExpanderPanel));
+
+ ///
+ /// Gets or sets the tool-specific menu items (commands/icons) shown at the top of the profile context
+ /// menu, before the always-present "Edit", "Copy as", and "Delete" items.
+ ///
+ public IEnumerable ProfileContextMenuExtraItems
+ {
+ get => (IEnumerable)GetValue(ProfileContextMenuExtraItemsProperty);
+ set => SetValue(ProfileContextMenuExtraItemsProperty, value);
+ }
+
+ private void ContextMenu_Opened(object sender, RoutedEventArgs e)
+ {
+ // The context menu is a separate visual root (popup) and does not inherit the DataContext of the
+ // ListBoxItem it was opened from - fix it up here so its command bindings resolve against the
+ // tool's view model, same as the panel's own DataContext.
+ if (sender is ContextMenu menu)
+ menu.DataContext = DataContext;
+ }
+
+ public static readonly DependencyProperty RunProfileCommandProperty = DependencyProperty.Register(
+ nameof(RunProfileCommand), typeof(ICommand), typeof(ProfileExpanderPanel));
+
+ ///
+ /// Gets or sets the command executed when a profile is activated (Enter key or double-click). Optional -
+ /// tools without a "run" action for profiles leave this unset.
+ ///
+ public ICommand RunProfileCommand
+ {
+ get => (ICommand)GetValue(RunProfileCommandProperty);
+ set => SetValue(RunProfileCommandProperty, value);
+ }
+
+ public static readonly DependencyProperty TextBoxSearchGotFocusCommandProperty = DependencyProperty.Register(
+ nameof(TextBoxSearchGotFocusCommand), typeof(ICommand), typeof(ProfileExpanderPanel));
+
+ ///
+ /// Gets or sets the command executed when the search box receives focus. Optional - only used by tools
+ /// that pause background refreshes while the user is searching.
+ ///
+ public ICommand TextBoxSearchGotFocusCommand
+ {
+ get => (ICommand)GetValue(TextBoxSearchGotFocusCommandProperty);
+ set => SetValue(TextBoxSearchGotFocusCommandProperty, value);
+ }
+
+ public static readonly DependencyProperty TextBoxSearchLostFocusCommandProperty = DependencyProperty.Register(
+ nameof(TextBoxSearchLostFocusCommand), typeof(ICommand), typeof(ProfileExpanderPanel));
+
+ ///
+ /// Gets or sets the command executed when the search box loses focus. Optional - only used by tools
+ /// that pause background refreshes while the user is searching.
+ ///
+ public ICommand TextBoxSearchLostFocusCommand
+ {
+ get => (ICommand)GetValue(TextBoxSearchLostFocusCommandProperty);
+ set => SetValue(TextBoxSearchLostFocusCommandProperty, value);
+ }
+
+ public static readonly DependencyProperty ProfileContextMenuIsOpenProperty = DependencyProperty.Register(
+ nameof(ProfileContextMenuIsOpen), typeof(bool), typeof(ProfileExpanderPanel),
+ new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
+
+ ///
+ /// Gets or sets a value indicating whether the profile context menu is open. Optional - only used by
+ /// tools that need to suppress other behavior (e.g. auto-focusing an embedded window) while the menu is
+ /// open.
+ ///
+ public bool ProfileContextMenuIsOpen
+ {
+ get => (bool)GetValue(ProfileContextMenuIsOpenProperty);
+ set => SetValue(ProfileContextMenuIsOpenProperty, value);
+ }
+
+ public static readonly DependencyProperty ProfileFilterPopupClosedCommandProperty = DependencyProperty.Register(
+ nameof(ProfileFilterPopupClosedCommand), typeof(ICommand), typeof(ProfileExpanderPanel));
+
+ ///
+ /// Gets or sets the command executed when the tag-filter popup closes (including an implicit close, e.g.
+ /// clicking away). Optional - only used by tools that mirror the popup's open state into global state.
+ ///
+ public ICommand ProfileFilterPopupClosedCommand
+ {
+ get => (ICommand)GetValue(ProfileFilterPopupClosedCommandProperty);
+ set => SetValue(ProfileFilterPopupClosedCommandProperty, value);
+ }
+
+ public ProfileExpanderPanel()
+ {
+ InitializeComponent();
+ }
+
+ private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
+ {
+ if (e.ChangedButton == MouseButton.Left)
+ RunProfileCommand?.Execute(null);
+ }
+
+ private void PopupProfileFilter_Closed(object sender, EventArgs e)
+ {
+ ProfileFilterPopupClosedCommand?.Execute(null);
+ }
+}
diff --git a/Source/NETworkManager/Views/DNSLookupHostView.xaml b/Source/NETworkManager/Views/DNSLookupHostView.xaml
index 1e4810b387..6f9e4776e3 100644
--- a/Source/NETworkManager/Views/DNSLookupHostView.xaml
+++ b/Source/NETworkManager/Views/DNSLookupHostView.xaml
@@ -15,6 +15,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:DNSLookupHostViewModel}">
@@ -23,6 +24,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -32,7 +64,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Source/NETworkManager/Views/DNSLookupHostView.xaml.cs b/Source/NETworkManager/Views/DNSLookupHostView.xaml.cs
index 36a497a3a8..fc6e032285 100644
--- a/Source/NETworkManager/Views/DNSLookupHostView.xaml.cs
+++ b/Source/NETworkManager/Views/DNSLookupHostView.xaml.cs
@@ -1,6 +1,3 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
using NETworkManager.ViewModels;
namespace NETworkManager.Views;
@@ -15,18 +12,6 @@ public DNSLookupHostView()
DataContext = _viewModel;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.LookupProfileCommand.Execute(null);
- }
-
public void AddTab(string host)
{
_viewModel.AddTab(host);
@@ -41,4 +26,4 @@ public void OnViewVisible()
{
_viewModel.OnViewVisible();
}
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/IPGeolocationHostView.xaml b/Source/NETworkManager/Views/IPGeolocationHostView.xaml
index 27f68ee132..182ce67b35 100644
--- a/Source/NETworkManager/Views/IPGeolocationHostView.xaml
+++ b/Source/NETworkManager/Views/IPGeolocationHostView.xaml
@@ -15,6 +15,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:IPGeolocationHostViewModel}">
@@ -22,6 +23,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -31,7 +63,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Source/NETworkManager/Views/IPGeolocationHostView.xaml.cs b/Source/NETworkManager/Views/IPGeolocationHostView.xaml.cs
index f24002f50d..4f8813acd3 100644
--- a/Source/NETworkManager/Views/IPGeolocationHostView.xaml.cs
+++ b/Source/NETworkManager/Views/IPGeolocationHostView.xaml.cs
@@ -1,6 +1,3 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
using NETworkManager.ViewModels;
namespace NETworkManager.Views;
@@ -15,18 +12,6 @@ public IPGeolocationHostView()
DataContext = _viewModel;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.QueryProfileCommand.Execute(null);
- }
-
public void OnViewHide()
{
_viewModel.OnViewHide();
@@ -36,4 +21,4 @@ public void OnViewVisible()
{
_viewModel.OnViewVisible();
}
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/IPScannerHostView.xaml b/Source/NETworkManager/Views/IPScannerHostView.xaml
index 7936d245c7..b888d10ef1 100644
--- a/Source/NETworkManager/Views/IPScannerHostView.xaml
+++ b/Source/NETworkManager/Views/IPScannerHostView.xaml
@@ -15,6 +15,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:IPScannerHostViewModel}">
@@ -22,6 +23,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -31,7 +62,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Source/NETworkManager/Views/IPScannerHostView.xaml.cs b/Source/NETworkManager/Views/IPScannerHostView.xaml.cs
index 3d1b1434a4..25d1d3a18d 100644
--- a/Source/NETworkManager/Views/IPScannerHostView.xaml.cs
+++ b/Source/NETworkManager/Views/IPScannerHostView.xaml.cs
@@ -1,6 +1,3 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
using NETworkManager.ViewModels;
namespace NETworkManager.Views;
@@ -15,18 +12,6 @@ public IPScannerHostView()
DataContext = _viewModel;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.ScanProfileCommand.Execute(null);
- }
-
public void AddTab(string host)
{
_viewModel.AddTab(host);
@@ -41,4 +26,4 @@ public void OnViewVisible()
{
_viewModel.OnViewVisible();
}
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/NetworkInterfaceView.xaml b/Source/NETworkManager/Views/NetworkInterfaceView.xaml
index 4e8efb5e9b..aa1da2d67a 100644
--- a/Source/NETworkManager/Views/NetworkInterfaceView.xaml
+++ b/Source/NETworkManager/Views/NetworkInterfaceView.xaml
@@ -18,6 +18,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:NetworkInterfaceViewModel}">
@@ -42,6 +43,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1470,601 +1503,9 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -24,14 +25,43 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -244,606 +274,9 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs b/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs
index 9d89c54450..14ef172187 100644
--- a/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs
+++ b/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs
@@ -1,7 +1,4 @@
-using NETworkManager.ViewModels;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
+using NETworkManager.ViewModels;
namespace NETworkManager.Views;
@@ -15,18 +12,6 @@ public PingMonitorHostView()
DataContext = _viewModel;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.PingProfileCommand.Execute(null);
- }
-
public void AddHost(string host)
{
if (_viewModel.SetHost(host))
@@ -42,4 +27,4 @@ public void OnViewVisible()
{
_viewModel.OnViewVisible();
}
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/PortScannerHostView.xaml b/Source/NETworkManager/Views/PortScannerHostView.xaml
index 8a478d35a5..8a820e112a 100644
--- a/Source/NETworkManager/Views/PortScannerHostView.xaml
+++ b/Source/NETworkManager/Views/PortScannerHostView.xaml
@@ -15,6 +15,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:PortScannerHostViewModel}">
@@ -23,6 +24,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -32,7 +69,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Source/NETworkManager/Views/PortScannerHostView.xaml.cs b/Source/NETworkManager/Views/PortScannerHostView.xaml.cs
index 2b115f44cf..30e612a289 100644
--- a/Source/NETworkManager/Views/PortScannerHostView.xaml.cs
+++ b/Source/NETworkManager/Views/PortScannerHostView.xaml.cs
@@ -1,6 +1,3 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
using NETworkManager.ViewModels;
namespace NETworkManager.Views;
@@ -15,18 +12,6 @@ public PortScannerHostView()
DataContext = _viewModel;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.ScanProfileCommand.Execute(null);
- }
-
public void AddTab(string host)
{
_viewModel.AddTab(host);
@@ -41,4 +26,4 @@ public void OnViewVisible()
{
_viewModel.OnViewVisible();
}
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/PowerShellHostView.xaml b/Source/NETworkManager/Views/PowerShellHostView.xaml
index 542b612821..4b402065b6 100644
--- a/Source/NETworkManager/Views/PowerShellHostView.xaml
+++ b/Source/NETworkManager/Views/PowerShellHostView.xaml
@@ -17,6 +17,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
Loaded="UserControl_Loaded"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:PowerShellHostViewModel}">
@@ -26,6 +27,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -45,7 +90,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/Source/NETworkManager/Views/PowerShellHostView.xaml.cs b/Source/NETworkManager/Views/PowerShellHostView.xaml.cs
index 1edb19d556..9c80c79016 100644
--- a/Source/NETworkManager/Views/PowerShellHostView.xaml.cs
+++ b/Source/NETworkManager/Views/PowerShellHostView.xaml.cs
@@ -1,8 +1,6 @@
-using NETworkManager.ViewModels;
+using NETworkManager.ViewModels;
using System.Threading.Tasks;
using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
namespace NETworkManager.Views;
@@ -23,22 +21,10 @@ private void UserControl_Loaded(object sender, RoutedEventArgs e)
_loaded = true;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.ConnectProfileCommand.Execute(null);
- }
-
public async void AddTab(string host)
{
- // Wait for the interface to load, before displaying the dialog to connect a new profile...
- // MahApps will throw an exception...
+ // Wait for the interface to load, before displaying the dialog to connect a new profile...
+ // MahApps will throw an exception...
while (!_loaded)
await Task.Delay(250);
@@ -60,9 +46,4 @@ public void FocusEmbeddedWindow()
{
_viewModel.FocusEmbeddedWindow();
}
-
- private void PopupProfileFilter_Closed(object sender, System.EventArgs e)
- {
- _viewModel.OnProfileFilterClosed();
- }
}
diff --git a/Source/NETworkManager/Views/PuTTYHostView.xaml b/Source/NETworkManager/Views/PuTTYHostView.xaml
index 515de19a10..f158446330 100644
--- a/Source/NETworkManager/Views/PuTTYHostView.xaml
+++ b/Source/NETworkManager/Views/PuTTYHostView.xaml
@@ -17,6 +17,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
Loaded="UserControl_Loaded"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:PuTTYHostViewModel}">
@@ -26,6 +27,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -45,7 +89,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/Source/NETworkManager/Views/PuTTYHostView.xaml.cs b/Source/NETworkManager/Views/PuTTYHostView.xaml.cs
index e9a52605f4..819d3310cb 100644
--- a/Source/NETworkManager/Views/PuTTYHostView.xaml.cs
+++ b/Source/NETworkManager/Views/PuTTYHostView.xaml.cs
@@ -1,9 +1,6 @@
-using System;
+using NETworkManager.ViewModels;
using System.Threading.Tasks;
using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
-using NETworkManager.ViewModels;
namespace NETworkManager.Views;
@@ -24,22 +21,10 @@ private void UserControl_Loaded(object sender, RoutedEventArgs e)
_loaded = true;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.ConnectProfileCommand.Execute(null);
- }
-
public async void AddTab(string host)
{
- // Wait for the interface to load, before displaying the dialog to connect a new profile...
- // MahApps will throw an exception...
+ // Wait for the interface to load, before displaying the dialog to connect a new profile...
+ // MahApps will throw an exception...
while (!_loaded)
await Task.Delay(250);
@@ -61,9 +46,4 @@ public void FocusEmbeddedWindow()
{
_viewModel.FocusEmbeddedWindow();
}
-
- private void PopupProfileFilter_Closed(object sender, EventArgs e)
- {
- _viewModel.OnProfileFilterClosed();
- }
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/RemoteDesktopHostView.xaml b/Source/NETworkManager/Views/RemoteDesktopHostView.xaml
index ac90f0a81f..a47620e7b8 100644
--- a/Source/NETworkManager/Views/RemoteDesktopHostView.xaml
+++ b/Source/NETworkManager/Views/RemoteDesktopHostView.xaml
@@ -16,6 +16,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
Loaded="UserControl_Loaded"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:RemoteDesktopHostViewModel}">
@@ -25,6 +26,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -34,7 +87,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Source/NETworkManager/Views/RemoteDesktopHostView.xaml.cs b/Source/NETworkManager/Views/RemoteDesktopHostView.xaml.cs
index 3e38844ea4..d33633292b 100644
--- a/Source/NETworkManager/Views/RemoteDesktopHostView.xaml.cs
+++ b/Source/NETworkManager/Views/RemoteDesktopHostView.xaml.cs
@@ -1,8 +1,6 @@
-using NETworkManager.ViewModels;
+using NETworkManager.ViewModels;
using System.Threading.Tasks;
using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
namespace NETworkManager.Views;
@@ -23,21 +21,10 @@ private void UserControl_Loaded(object sender, RoutedEventArgs e)
_loaded = true;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu) menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.ConnectProfileCommand.Execute(null);
- }
-
public async void AddTab(string host)
{
- // Wait for the interface to load, before displaying the dialog to connect a new Profile...
- // MahApps will throw an exception...
+ // Wait for the interface to load, before displaying the dialog to connect a new Profile...
+ // MahApps will throw an exception...
while (!_loaded)
await Task.Delay(250);
@@ -53,4 +40,4 @@ public void OnViewVisible()
{
_viewModel.OnViewVisible();
}
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/SNMPHostView.xaml b/Source/NETworkManager/Views/SNMPHostView.xaml
index df326f7b1e..003dd4dfd5 100644
--- a/Source/NETworkManager/Views/SNMPHostView.xaml
+++ b/Source/NETworkManager/Views/SNMPHostView.xaml
@@ -15,6 +15,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:SNMPHostViewModel}">
@@ -22,6 +23,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -31,7 +62,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Source/NETworkManager/Views/SNMPHostView.xaml.cs b/Source/NETworkManager/Views/SNMPHostView.xaml.cs
index afb45a4eb6..fb7a33a8b7 100644
--- a/Source/NETworkManager/Views/SNMPHostView.xaml.cs
+++ b/Source/NETworkManager/Views/SNMPHostView.xaml.cs
@@ -1,6 +1,3 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
using NETworkManager.ViewModels;
namespace NETworkManager.Views;
@@ -15,18 +12,6 @@ public SNMPHostView()
DataContext = _viewModel;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.AddTabProfileCommand.Execute(null);
- }
-
public void AddTab(string host)
{
_viewModel.AddTab(host);
@@ -41,4 +26,4 @@ public void OnViewVisible()
{
_viewModel.OnViewVisible();
}
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/TigerVNCHostView.xaml b/Source/NETworkManager/Views/TigerVNCHostView.xaml
index 006ff0358d..228da7c123 100644
--- a/Source/NETworkManager/Views/TigerVNCHostView.xaml
+++ b/Source/NETworkManager/Views/TigerVNCHostView.xaml
@@ -16,6 +16,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
Loaded="UserControl_Loaded"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:TigerVNCHostViewModel}">
@@ -25,6 +26,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -44,7 +88,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/Source/NETworkManager/Views/TigerVNCHostView.xaml.cs b/Source/NETworkManager/Views/TigerVNCHostView.xaml.cs
index 409a56b999..d556299387 100644
--- a/Source/NETworkManager/Views/TigerVNCHostView.xaml.cs
+++ b/Source/NETworkManager/Views/TigerVNCHostView.xaml.cs
@@ -1,8 +1,6 @@
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
using NETworkManager.ViewModels;
+using System.Threading.Tasks;
+using System.Windows;
namespace NETworkManager.Views;
@@ -23,22 +21,10 @@ private void UserControl_Loaded(object sender, RoutedEventArgs e)
_loaded = true;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.ConnectProfileCommand.Execute(null);
- }
-
public async void AddTab(string host)
{
- // Wait for the interface to load, before displaying the dialog to connect a new profile...
- // MahApps will throw an exception...
+ // Wait for the interface to load, before displaying the dialog to connect a new profile...
+ // MahApps will throw an exception...
while (!_loaded)
await Task.Delay(250);
@@ -55,4 +41,4 @@ public void OnViewVisible()
{
_viewModel.OnViewVisible();
}
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/TracerouteHostView.xaml b/Source/NETworkManager/Views/TracerouteHostView.xaml
index acc4550b82..e4818e536d 100644
--- a/Source/NETworkManager/Views/TracerouteHostView.xaml
+++ b/Source/NETworkManager/Views/TracerouteHostView.xaml
@@ -15,6 +15,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:TracerouteHostViewModel}">
@@ -23,6 +24,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -32,7 +63,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Source/NETworkManager/Views/TracerouteHostView.xaml.cs b/Source/NETworkManager/Views/TracerouteHostView.xaml.cs
index 4e91e5791b..2805de869b 100644
--- a/Source/NETworkManager/Views/TracerouteHostView.xaml.cs
+++ b/Source/NETworkManager/Views/TracerouteHostView.xaml.cs
@@ -1,6 +1,3 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
using NETworkManager.Profiles;
using NETworkManager.ViewModels;
@@ -16,18 +13,6 @@ public TracerouteHostView()
DataContext = _viewModel;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.TraceProfileCommand.Execute(null);
- }
-
public void AddTab(string host)
{
_viewModel.AddTab(host);
@@ -47,4 +32,4 @@ public void OnViewVisible()
{
_viewModel.OnViewVisible();
}
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/WakeOnLANView.xaml b/Source/NETworkManager/Views/WakeOnLANView.xaml
index 6aebbc2b6b..29f5d6f368 100644
--- a/Source/NETworkManager/Views/WakeOnLANView.xaml
+++ b/Source/NETworkManager/Views/WakeOnLANView.xaml
@@ -15,6 +15,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:WakeOnLANViewModel}">
@@ -23,13 +24,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -151,579 +182,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Source/NETworkManager/Views/WakeOnLANView.xaml.cs b/Source/NETworkManager/Views/WakeOnLANView.xaml.cs
index 225e7f6819..07e67ab28d 100644
--- a/Source/NETworkManager/Views/WakeOnLANView.xaml.cs
+++ b/Source/NETworkManager/Views/WakeOnLANView.xaml.cs
@@ -1,5 +1,3 @@
-using System.Windows;
-using System.Windows.Controls;
using NETworkManager.ViewModels;
namespace NETworkManager.Views;
@@ -14,12 +12,6 @@ public WakeOnLANView()
DataContext = _viewModel;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
public void OnViewHide()
{
_viewModel.OnViewHide();
@@ -29,4 +21,4 @@ public void OnViewVisible()
{
_viewModel.OnViewVisible();
}
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/WebConsoleHostView.xaml b/Source/NETworkManager/Views/WebConsoleHostView.xaml
index 806528792f..3febe5c8b3 100644
--- a/Source/NETworkManager/Views/WebConsoleHostView.xaml
+++ b/Source/NETworkManager/Views/WebConsoleHostView.xaml
@@ -17,6 +17,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:WebConsoleHostViewModel}">
@@ -24,6 +25,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -43,7 +75,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/Source/NETworkManager/Views/WebConsoleHostView.xaml.cs b/Source/NETworkManager/Views/WebConsoleHostView.xaml.cs
index 510ed18104..2f5f3c937c 100644
--- a/Source/NETworkManager/Views/WebConsoleHostView.xaml.cs
+++ b/Source/NETworkManager/Views/WebConsoleHostView.xaml.cs
@@ -1,6 +1,3 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
using NETworkManager.ViewModels;
namespace NETworkManager.Views;
@@ -15,18 +12,6 @@ public WebConsoleHostView()
DataContext = _viewModel;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.ConnectProfileCommand.Execute(null);
- }
-
public void OnViewHide()
{
_viewModel.OnViewHide();
@@ -36,4 +21,4 @@ public void OnViewVisible()
{
_viewModel.OnViewVisible();
}
-}
\ No newline at end of file
+}
diff --git a/Source/NETworkManager/Views/WhoisHostView.xaml b/Source/NETworkManager/Views/WhoisHostView.xaml
index 8dc0c38efb..7f46fbba6f 100644
--- a/Source/NETworkManager/Views/WhoisHostView.xaml
+++ b/Source/NETworkManager/Views/WhoisHostView.xaml
@@ -15,6 +15,7 @@
xmlns:profiles="clr-namespace:NETworkManager.Profiles;assembly=NETworkManager.Profiles"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
xmlns:networkManager="clr-namespace:NETworkManager"
+ xmlns:hostControls="clr-namespace:NETworkManager.Views.Controls"
mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:WhoisHostViewModel}">
@@ -22,6 +23,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -31,7 +63,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Source/NETworkManager/Views/WhoisHostView.xaml.cs b/Source/NETworkManager/Views/WhoisHostView.xaml.cs
index f598e20724..dfda536745 100644
--- a/Source/NETworkManager/Views/WhoisHostView.xaml.cs
+++ b/Source/NETworkManager/Views/WhoisHostView.xaml.cs
@@ -1,6 +1,3 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
using NETworkManager.ViewModels;
namespace NETworkManager.Views;
@@ -15,18 +12,6 @@ public WhoisHostView()
DataContext = _viewModel;
}
- private void ContextMenu_Opened(object sender, RoutedEventArgs e)
- {
- if (sender is ContextMenu menu)
- menu.DataContext = _viewModel;
- }
-
- private void ListBoxItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- _viewModel.QueryProfileCommand.Execute(null);
- }
-
public void OnViewHide()
{
_viewModel.OnViewHide();
@@ -36,4 +21,4 @@ public void OnViewVisible()
{
_viewModel.OnViewVisible();
}
-}
\ No newline at end of file
+}
From ed5d64163318cc4d4d26c68b553f59fe98bc2d7d Mon Sep 17 00:00:00 2001
From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
Date: Sat, 18 Jul 2026 23:48:11 +0200
Subject: [PATCH 2/3] Update next-release.md
---
Website/docs/changelog/next-release.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md
index 4106e6b524..2df41043a1 100644
--- a/Website/docs/changelog/next-release.md
+++ b/Website/docs/changelog/next-release.md
@@ -32,5 +32,6 @@ Release date: **xx.xx.2026**
## Dependencies, Refactoring & Documentation
- Code cleanup & refactoring
+- Consolidated the duplicated **Profiles** side panel (search, tag filter, grouped list, context menu, add/edit/copy/delete) used across 15 tool views into a single shared control, reducing code duplication. As part of this, the profile panel's expanded/width state is now shared across all tools instead of being tracked per tool. [#3537](https://github.com/BornToBeRoot/NETworkManager/pull/3537)
- Language files updated via [#transifex](https://github.com/BornToBeRoot/NETworkManager/pulls?q=author%3Aapp%2Ftransifex-integration)
- Dependencies updated via [#dependabot](https://github.com/BornToBeRoot/NETworkManager/pulls?q=author%3Aapp%2Fdependabot)
From 4250486e53006bca3078673e16daf53bc3f9e6ba Mon Sep 17 00:00:00 2001
From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
Date: Sun, 19 Jul 2026 01:02:57 +0200
Subject: [PATCH 3/3] Fix: Copilot feedback
---
.../ViewModels/PowerShellHostViewModel.cs | 4 ++--
.../ViewModels/ProfileHostViewModelBase.cs | 16 ++++++++++++++++
.../ViewModels/PuTTYHostViewModel.cs | 4 ++--
.../ViewModels/RemoteDesktopHostViewModel.cs | 11 +++++++++--
.../ViewModels/TigerVNCHostViewModel.cs | 4 ++--
.../ViewModels/WebConsoleHostViewModel.cs | 4 ++--
6 files changed, 33 insertions(+), 10 deletions(-)
diff --git a/Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs b/Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs
index 95cedff324..2f3607b342 100644
--- a/Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs
@@ -164,12 +164,12 @@ public void OnProfileFilterClosed()
ConfigurationManager.Current.IsProfileFilterPopupOpen = false;
}
- public void OnProfileManagerDialogOpen()
+ public override void OnProfileManagerDialogOpen()
{
ConfigurationManager.OnDialogOpen();
}
- public void OnProfileManagerDialogClose()
+ public override void OnProfileManagerDialogClose()
{
ConfigurationManager.OnDialogClose();
}
diff --git a/Source/NETworkManager/ViewModels/ProfileHostViewModelBase.cs b/Source/NETworkManager/ViewModels/ProfileHostViewModelBase.cs
index 4bf0d162e6..1a55ab14df 100644
--- a/Source/NETworkManager/ViewModels/ProfileHostViewModelBase.cs
+++ b/Source/NETworkManager/ViewModels/ProfileHostViewModelBase.cs
@@ -370,6 +370,22 @@ public virtual void OnViewHide()
_isViewActive = false;
}
+ ///
+ /// Called when a dialog in the is opened. Virtual so tools with an
+ /// embedded native window (e.g. PowerShell, PuTTY, RemoteDesktop, TigerVNC, WebConsole) can override it to
+ /// enable while the dialog is shown.
+ ///
+ public virtual void OnProfileManagerDialogOpen()
+ {
+ }
+
+ ///
+ /// Called when a dialog in the is closed.
+ ///
+ public virtual void OnProfileManagerDialogClose()
+ {
+ }
+
private void CreateTags()
{
var tags = ProfileManager.LoadedProfileFileData.Groups.SelectMany(x => x.Profiles).Where(IsProfileEnabled)
diff --git a/Source/NETworkManager/ViewModels/PuTTYHostViewModel.cs b/Source/NETworkManager/ViewModels/PuTTYHostViewModel.cs
index 67572a1d24..9ffc59c06d 100644
--- a/Source/NETworkManager/ViewModels/PuTTYHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/PuTTYHostViewModel.cs
@@ -164,12 +164,12 @@ public void OnProfileFilterClosed()
ConfigurationManager.Current.IsProfileFilterPopupOpen = false;
}
- public void OnProfileManagerDialogOpen()
+ public override void OnProfileManagerDialogOpen()
{
ConfigurationManager.OnDialogOpen();
}
- public void OnProfileManagerDialogClose()
+ public override void OnProfileManagerDialogClose()
{
ConfigurationManager.OnDialogClose();
}
diff --git a/Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs b/Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs
index ca67aba5b5..1de5001b77 100644
--- a/Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/RemoteDesktopHostViewModel.cs
@@ -78,12 +78,12 @@ public RemoteDesktopHostViewModel()
protected override string GetSearchableField(ProfileInfo profile) => profile.RemoteDesktop_Host;
- public void OnProfileManagerDialogOpen()
+ public override void OnProfileManagerDialogOpen()
{
ConfigurationManager.OnDialogOpen();
}
- public void OnProfileManagerDialogClose()
+ public override void OnProfileManagerDialogClose()
{
ConfigurationManager.OnDialogClose();
}
@@ -237,6 +237,13 @@ private void ConnectProfileExternalAction()
Process.Start("mstsc.exe", args);
}
+ public ItemActionCallback CloseItemCommand => CloseItemAction;
+
+ private static void CloseItemAction(ItemActionCallbackArgs args)
+ {
+ ((args.DragablzItem.Content as DragablzTabItem)?.View as IDragablzTabItem)?.CloseTab();
+ }
+
#endregion
#region Methods
diff --git a/Source/NETworkManager/ViewModels/TigerVNCHostViewModel.cs b/Source/NETworkManager/ViewModels/TigerVNCHostViewModel.cs
index e049749fa0..e9f47e675d 100644
--- a/Source/NETworkManager/ViewModels/TigerVNCHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/TigerVNCHostViewModel.cs
@@ -97,12 +97,12 @@ public TigerVNCHostViewModel()
protected override string GetSearchableField(ProfileInfo profile) => profile.TigerVNC_Host;
- public void OnProfileManagerDialogOpen()
+ public override void OnProfileManagerDialogOpen()
{
ConfigurationManager.OnDialogOpen();
}
- public void OnProfileManagerDialogClose()
+ public override void OnProfileManagerDialogClose()
{
ConfigurationManager.OnDialogClose();
}
diff --git a/Source/NETworkManager/ViewModels/WebConsoleHostViewModel.cs b/Source/NETworkManager/ViewModels/WebConsoleHostViewModel.cs
index 8b33ce0697..951174d9eb 100644
--- a/Source/NETworkManager/ViewModels/WebConsoleHostViewModel.cs
+++ b/Source/NETworkManager/ViewModels/WebConsoleHostViewModel.cs
@@ -104,12 +104,12 @@ public WebConsoleHostViewModel()
protected override string GetSearchableField(ProfileInfo profile) => profile.WebConsole_Url;
- public void OnProfileManagerDialogOpen()
+ public override void OnProfileManagerDialogOpen()
{
ConfigurationManager.OnDialogOpen();
}
- public void OnProfileManagerDialogClose()
+ public override void OnProfileManagerDialogClose()
{
ConfigurationManager.OnDialogClose();
}