diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6aaa47c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,219 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_property = false + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members + +# Expression-level preferences +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true +dotnet_style_explicit_tuple_names = true +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true +dotnet_style_object_initializer = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true +dotnet_style_prefer_compound_assignment = true +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_style_prefer_conditional_expression_over_return = true +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true + +# Parameter preferences +dotnet_code_quality_unused_parameters = all + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +# New line preferences +dotnet_style_allow_multiple_blank_lines_experimental = true +dotnet_style_allow_statement_immediately_after_block_experimental = true + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = false + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true +csharp_style_expression_bodied_constructors = false +csharp_style_expression_bodied_indexers = true +csharp_style_expression_bodied_lambdas = true +csharp_style_expression_bodied_local_functions = false +csharp_style_expression_bodied_methods = false +csharp_style_expression_bodied_operators = false +csharp_style_expression_bodied_properties = true + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_not_pattern = true +csharp_style_prefer_pattern_matching = true +csharp_style_prefer_switch_expression = true + +# Null-checking preferences +csharp_style_conditional_delegate_call = true + +# Modifier preferences +csharp_prefer_static_local_function = true +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async + +# Code-block preferences +csharp_prefer_braces = true +csharp_prefer_simple_using_statement = true +csharp_style_namespace_declarations = block_scoped + +# Expression-level preferences +csharp_prefer_simple_default_expression = true +csharp_style_deconstructed_variable_declaration = true +csharp_style_implicit_object_creation_when_type_is_apparent = true +csharp_style_inlined_variable_declaration = true +csharp_style_pattern_local_over_anonymous_function = true +csharp_style_prefer_index_operator = true +csharp_style_prefer_null_check_over_type_check = true +csharp_style_prefer_range_operator = true +csharp_style_throw_expression = true +csharp_style_unused_value_assignment_preference = discard_variable +csharp_style_unused_value_expression_statement_preference = discard_variable + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true +csharp_style_allow_embedded_statements_on_same_line_experimental = true + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = none +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast =true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case diff --git a/FunctionalFun.UI.Behaviours/FunctionalFun.UI.Behaviors.csproj b/FunctionalFun.UI.Behaviours/FunctionalFun.UI.Behaviors.csproj index 1f356bd..8391385 100644 --- a/FunctionalFun.UI.Behaviours/FunctionalFun.UI.Behaviors.csproj +++ b/FunctionalFun.UI.Behaviours/FunctionalFun.UI.Behaviors.csproj @@ -1,94 +1,48 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {7DA5A107-B474-4AC0-B861-63A489DB0C02} - Library - Properties - FunctionalFun.UI.Behaviors - FunctionalFun.UI.Behaviors - v4.6.2 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - - - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - - - - - - 3.5 - - - - - - - - - Code - - - - - - - False - .NET Framework 3.5 SP1 - true - - - - + + + net5.0-windows + Library + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + false + true + true + + + + + + + 3.5 + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + all + + + \ No newline at end of file diff --git a/NtfsReader/NtfsReader.csproj b/NtfsReader/NtfsReader.csproj index 6a7b6dd..d8ec209 100644 --- a/NtfsReader/NtfsReader.csproj +++ b/NtfsReader/NtfsReader.csproj @@ -1,106 +1,54 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {DBACEFC5-0234-4317-B096-F212ECAE1DD1} - Library - Properties - NtfsReader - NtfsReader - v4.6.1 - 512 - - - true - NtfsReader.snk - - - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - true - false - - - - - - - - - - - - - - NtfsReader.cs - - - NtfsReader.cs - - - NtfsReader.cs - - - - - - - - - - - - - False - .NET Framework 3.5 SP1 - true - - - - + + + netstandard2.0 + Library + + + true + NtfsReader.snk + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + false + true + + + + NtfsReader.cs + + + NtfsReader.cs + + + NtfsReader.cs + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + all + + \ No newline at end of file diff --git a/WinDirStat.Net.Base/Model/Drives/DriveItem.cs b/WinDirStat.Net.Base/Model/Drives/DriveItem.cs deleted file mode 100644 index 647a29a..0000000 --- a/WinDirStat.Net.Base/Model/Drives/DriveItem.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Model.Drives { - /// An item containing basic information on a drive. - [Serializable] - public class DriveItem : IComparable, IComparable { - - #region Fields - - /// Gets the name/path of the drive. - public string Name { get; } - /// Gets the total size of the drive. - public long TotalSize { get; } - /// Gets the freespace on the drive in bytes. - public long FreeSpace { get; } - /// Gets the type of the drive. - public DriveType DriveType { get; } - /// Gets the partition format of the drive. - public string DriveFormat { get; } - - #endregion - - #region Constructors - - /// Constructs a using the . - /// - /// The information about the drive. - public DriveItem(DriveInfo info) { - Name = info.Name; - TotalSize = info.TotalSize; - FreeSpace = info.TotalFreeSpace; - DriveType = info.DriveType; - DriveFormat = info.DriveFormat; - } - - #endregion - - #region Properties - - /// Gets the used space on the drive in bytes. - public long UsedSpace => Math.Max(0L, TotalSize - FreeSpace); - - /// Gets the used percentage of the drive. - public double Percent => (double) UsedSpace / TotalSize; - - #endregion - - #region IComparable Implementation - - /// Compares this drive to another based on name in ascending order. - /// - /// The other drive to compare to. - /// The comparison result. - public int CompareTo(DriveItem other) { - int diff = other.TotalSize.CompareTo(TotalSize); - if (diff == 0) - return string.Compare(Name, other.Name, true); - return diff; - } - - /// Compares this drive to another based on name in ascending order. - /// - /// The other drive to compare to. - /// The comparison result. - int IComparable.CompareTo(object obj) { - return CompareTo((DriveItem) obj); - } - - #endregion - - #region ToString/DebuggerDisplay - - /// Gets the string representation of this item. - public override sealed string ToString() => Name; - - /// Gets the string used to represent the file in the debugger. - private string DebuggerDisplay => Name; - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Model/Drives/DriveItems.cs b/WinDirStat.Net.Base/Model/Drives/DriveItems.cs deleted file mode 100644 index 8fd961d..0000000 --- a/WinDirStat.Net.Base/Model/Drives/DriveItems.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services; -using WinDirStat.Net.Utils; - -namespace WinDirStat.Net.Model.Drives { - /// A collection of see s. - public class DriveItems : ObservablePropertyCollectionObject, IReadOnlyList { - - #region Fields - - /// The scanning service that contains this collection. - private readonly ScanningService scanning; - /// The collection of drives. - private readonly List drives; - - #endregion - - #region Constructors - - /// Constructs the list. - public DriveItems(ScanningService scanning) { - this.scanning = scanning; - drives = new List(); - } - - #endregion - - #region Refresh - - /// Refreshes the drive list. - public void Refresh() { - if (drives.Count > 0) { - List oldItems = drives.GetFullRange(); - drives.Clear(); - RaisePropertyChanged(nameof(Count)); - RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, oldItems, 0); - } - drives.AddRange(scanning.ScanDrives()); - drives.Sort(); - RaiseCollectionChanged(NotifyCollectionChangedAction.Add, drives.GetFullRange(), 0); - } - - #endregion - - #region Properties - - /// Gets the number of drives in the list. - public int Count => drives.Count; - - /// Gets the drive item at the specified index in the list. - public DriveItem this[int index] => drives[index]; - - #endregion - - #region IEnumerator Implementation - - /// Gets the enumerator for the drive items. - IEnumerator IEnumerable.GetEnumerator() { - return drives.GetEnumerator(); - } - /// Gets the enumerator for the drive items. - IEnumerator IEnumerable.GetEnumerator() { - return drives.GetEnumerator(); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Model/Drives/Misc/DriveSelectMode.cs b/WinDirStat.Net.Base/Model/Drives/Misc/DriveSelectMode.cs deleted file mode 100644 index d499a57..0000000 --- a/WinDirStat.Net.Base/Model/Drives/Misc/DriveSelectMode.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Model.Drives { - /// The selection mode for drives. - [Serializable] - public enum DriveSelectMode { - /// All local drives are scanned. - [Description("All Local Drives")] - All, - /// Selected drives are scanned. - [Description("Individual Drives")] - Individual, - /// A folder path is scanned. - [Description("A Folder")] - Folder, - } -} diff --git a/WinDirStat.Net.Base/Model/Drives/Misc/DriveSelectResult.cs b/WinDirStat.Net.Base/Model/Drives/Misc/DriveSelectResult.cs deleted file mode 100644 index 81c2887..0000000 --- a/WinDirStat.Net.Base/Model/Drives/Misc/DriveSelectResult.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using WinDirStat.Net.Services; - -namespace WinDirStat.Net.Model.Drives { - /// The result returned from the drive select dialog. - public class DriveSelectResult { - - #region Fields - - /// The scanning service that contains this collection. - private readonly ScanningService scanning; - /// - /// The constant selected paths. Null when Mode is . - /// - private readonly string[] selectedPaths; - - /// The selection mode of the drive select result. - public DriveSelectMode Mode { get; } - - #endregion - - #region Constructors - - /// Constructs the . - public DriveSelectResult(ScanningService scanning, - DriveSelectMode mode, - string[] selectedDrives, - string folderPath) - { - this.scanning = scanning; - Mode = mode; - if (mode == DriveSelectMode.Individual) { - if (selectedDrives == null) - throw new ArgumentNullException(nameof(selectedDrives)); - selectedPaths = selectedDrives; - } - else if (mode == DriveSelectMode.Folder) { - selectedPaths = new[] { - folderPath ?? throw new ArgumentNullException(nameof(folderPath)), - }; - } - } - - #endregion - - #region Accessors - - /// Gets the result path of the drive select operation. - /// - /// Returns the paths of the result. - public string[] GetResultPaths() { - if (Mode == DriveSelectMode.All) { - return scanning.ScanDriveNames(); - } - else { - return selectedPaths; - } - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Model/Extensions/ExtensionItem.cs b/WinDirStat.Net.Base/Model/Extensions/ExtensionItem.cs deleted file mode 100644 index f2b1eff..0000000 --- a/WinDirStat.Net.Base/Model/Extensions/ExtensionItem.cs +++ /dev/null @@ -1,277 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Structures; - -namespace WinDirStat.Net.Model.Extensions { - /// A container for information about a file extension. - [Serializable] - [DebuggerDisplay("{DebuggerDisplay,nq}")] - public class ExtensionItem : IComparable, IComparable { - - #region Constants - - /// The used for file tree items that are not files. - public static readonly ExtensionItem NotAFile = new ExtensionItem(); - - /// The string used to represent an empty extension. - public const string EmptyExtension = "*"; - - #endregion - - #region Fields - - /// The collection containing this extension. - private readonly ExtensionItems extensions; - - /// Gets the name of the extension with the dot. - public string Extension { get; } - /// Gets the total size of all the files that use this extension. - public long Size { get; private set; } - /// Gets the number of files that use this extension. - public int FileCount { get; private set; } - /// Gets the color to use in the treemap for files with this extension. - private Rgb24Color color; - - #endregion - - #region Constructors - - /// Constructs the not-a-file extension. - private ExtensionItem() { - extensions = null; - Extension = string.Empty; - color = Rgb24Color.Black; - } - - /// Constructs an with the specified extension. - /// - /// The collection containing this extension. - /// The pre-normalized extension for this item. - internal ExtensionItem(ExtensionItems extensions, string normalizedExtension) { - this.extensions = extensions; - Extension = normalizedExtension; - color = new Rgb24Color(150, 150, 150); - } - - #endregion - - #region ViewModel Events - - /// Notifies any view models watching this item of important changes to the item. - [field: NonSerialized] - public event ExtensionItemEventHandler Changed; - - /// Gets if the item is being watched by a view model. - public bool IsWatched => Changed != null; - - protected void RaiseChanged(ExtensionItemEventArgs e) { - Changed?.Invoke(this, e); - } - protected void RaiseChanged(ExtensionItemAction action) { - Changed?.Invoke(this, new ExtensionItemEventArgs(action)); - } - protected void RaiseChanged(ExtensionItemAction action, int index) { - Changed?.Invoke(this, new ExtensionItemEventArgs(action, index)); - } - - public object GetViewModel() { - ExtensionItemEventArgs e = new ExtensionItemEventArgs(ExtensionItemAction.GetViewModel); - RaiseChanged(e); - return e.ViewModel; - } - - public TViewModel GetViewModel() where TViewModel : class { - ExtensionItemEventArgs e = new ExtensionItemEventArgs(ExtensionItemAction.GetViewModel); - RaiseChanged(e); - return e.ViewModel as TViewModel; - } - - #endregion - - #region Properties - - /// Gets the color to use in the treemap for files with this extension. - public Rgb24Color Color { - get => color; - /*internal set { - color = value; - RaiseChanged(ExtensionItemAction.ColorChanged); - }*/ - } - - /// Gets this extension's size relative to the total used space. - public double Percent { - get => (double) Size / extensions.TotalSize; - } - - /// Gets if this extension is the empty extension with nothing after the dot. - public bool IsEmptyExtension { - get => Extension == EmptyExtension; - } - - #endregion - - #region Color - - /// Sets the new color of the extension item. - /// - /// The new color. - /// The index of the extension in the sorted list. - internal void SetColor(Rgb24Color color, int index) { - this.color = color; - RaiseChanged(ExtensionItemAction.ColorChanged, index); - } - - #endregion - - #region Files - - /// Adds the file to the extension data. - /// - /// The size of the file to add. - internal void AddFile(long size) { - FileCount++; - Size += size; - extensions.TotalSize += size; - extensions.TotalFileCount++; - } - - /// Refreshes the file size with the extension. - /// - /// The new size of the file to refresh. - /// The old size of the file to refresh. - internal void RefreshFile(long size, long oldSize) { - long diff = size - oldSize; - Size += diff; - extensions.TotalSize += diff; - } - - /// Removes the file from the extension data. - /// - /// The size of the file to remove. - internal void RemoveFile(long size) { - Debug.Assert(FileCount > 0); - FileCount--; - Size -= size; - extensions.TotalSize -= size; - extensions.TotalFileCount--; - if (FileCount == 0) - extensions.Remove(this); - } - - /// - /// Removes all files associated with this extension.. - /// - internal void ClearFiles() { - extensions.TotalSize -= Size; - extensions.TotalFileCount -= FileCount; - Size = 0; - FileCount = 0; - extensions.Remove(this); - } - - /// - /// Removes all files associated with this extension. Only call this during . - /// - internal void ClearFilesMinimal() { - Size = 0; - FileCount = 0; - } - - #endregion - - #region IComparable Implementation - - /// Compares this extension to another based on size in descending order. - /// - /// The other extension to compare to. - /// The comparison result. - public int CompareTo(ExtensionItem other) { - int diff = other.Size.CompareTo(Size); - if (diff == 0) - return string.Compare(Extension, other.Extension, true); - return diff; - } - - /// Compares this extension to another based on size in descending order. - /// - /// The other extension to compare to. - /// The comparison result. - int IComparable.CompareTo(object obj) { - return CompareTo((ExtensionItem) obj); - } - - #endregion - - #region ToString/DebuggerDisplay - - /// Gets the string representation of this item. - public override sealed string ToString() => $"[{FileCount:N0}]: {Extension}"; - - /// Gets the string used to represent the file in the debugger. - private string DebuggerDisplay => $"[{FileCount:N0}]: {Extension}"; - - #endregion - - #region Static Methods - - /// Normalizes the extension for consistency. - /// - /// The extension to normalize. - /// A normalized extension. - public static string NormalizeExtension(string extension) { - int length = extension.Length; - if (length > 0) { - if (extension[0] == '.') { - if (length > 1) - return extension.ToLower(); - else // '.' is equivilant to an empty extension - return EmptyExtension; - } - else if (extension[0] != '*' || length > 1) { - // Needs a dot - return "." + extension.ToLower(); - } - } - // Empty string, empty extension - return EmptyExtension; - } - - /// Normalizes the extension for consistency. - /// - /// The extension to normalize. - public static void NormalizeExtension(ref string extension) { - extension = NormalizeExtension(extension); - } - - /// Gets the extension from the file path and normalizes it. - /// - /// The file path to normalize the extension of. - /// A normalized extension. - public static string GetAndNormalizeExtension(string path) { - // Code modified from Path.cs: Path.GetExtension(string) - int length = path.Length; - for (int i = length; --i >= 0;) { - char ch = path[i]; - if (ch == '.') { - if (i != length - 1) - return path.Substring(i, length - i).ToLower(); - else - return EmptyExtension; - } - if (ch == Path.DirectorySeparatorChar || ch == Path.AltDirectorySeparatorChar) - break; - } - return EmptyExtension; - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Model/Extensions/ExtensionItems.cs b/WinDirStat.Net.Base/Model/Extensions/ExtensionItems.cs deleted file mode 100644 index 42bc93b..0000000 --- a/WinDirStat.Net.Base/Model/Extensions/ExtensionItems.cs +++ /dev/null @@ -1,230 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Utils; -using static WinDirStat.Net.Model.Extensions.ExtensionItem; - -namespace WinDirStat.Net.Model.Extensions { - /// - /// A collection that maintains information about all extensions encountered while scanning the file - /// tree. - /// - public class ExtensionItems : ObservablePropertyCollectionObject, IReadOnlyList { - - #region Fields - - /// The scanning service that contains this collection. - private readonly ScanningService scanning; - /// The program settings service. - private readonly SettingsService settings; - /// The map of in-use extensions. - private readonly Dictionary extensions; - /// The map of unused extensions. - private readonly Dictionary unusedExtensions; - /// The list of extensions sorted by size descending after the scan. - private readonly List sortedExtensions; - - /// the Total size of all files in the file tree. - private long totalSize; - /// The total number of files in the file tree. - private long totalFileCount; - - #endregion - - #region Constructors - - /// Constructs the list. - public ExtensionItems(ScanningService scanning, - SettingsService settings) - { - this.scanning = scanning; - this.settings = settings; - extensions = new Dictionary(); - unusedExtensions = new Dictionary(); - sortedExtensions = new List(); - - scanning.PropertyChanged += OnScanningPropertyChanged; - settings.PropertyChanged += OnSettingsPropertyChanged; - } - - #endregion - - #region Event Handlers - - private void OnScanningPropertyChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - case nameof(ScanningService.ProgressState): - if (scanning.ProgressState == ScanProgressState.Ended && !scanning.IsRefreshing) - Validate(); - break; - case nameof(ScanningService.IsRefreshing): - if (!scanning.IsScanning) - Validate(); - break; - } - } - - private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - case nameof(SettingsService.FilePalette): - if (!scanning.IsScanning && !scanning.IsRefreshing) - RefreshPalette(); - break; - } - } - - #endregion - - #region Properties - - /// Gets the total size of all files in the file tree. - public long TotalSize { - get => totalSize; - internal set => Set(ref totalSize, value); - } - /// Gets the total number of files in the file tree. - public long TotalFileCount { - get => totalFileCount; - internal set => Set(ref totalFileCount, value); - } - - /// Gets the number of extensions in the file tree. - public int Count => sortedExtensions.Count; - /// Gets the number of unused extensions in the file tree. - public int UnusedCount => unusedExtensions.Count; - - /// Gets the extension item at the specified index (in the list ordered by size). - public ExtensionItem this[int index] => sortedExtensions[index]; - /// Gets the existing extension item of the specified extension. - public ExtensionItem this[string extension] => extensions[NormalizeExtension(extension)]; - - #endregion - - #region Collection - - /// Gets the existing extension item or creates one and adds it to the list. - /// - /// The extension to get or add an item for. - /// The extension item with the specified extension. - public ExtensionItem GetOrAdd(string extension) { - NormalizeExtension(ref extension); - if (!extensions.TryGetValue(extension, out ExtensionItem item)) { - bool unusedFound = unusedExtensions.TryGetValue(extension, out item); - if (unusedFound) - unusedExtensions.Remove(extension); - else - item = new ExtensionItem(this, extension); - Debug.Assert(item != null); - extensions.Add(extension, item); - sortedExtensions.Add(item); - if (unusedFound) - RaisePropertyChanged(nameof(UnusedCount)); - RaisePropertyChanged(nameof(Count)); - RaiseCollectionChanged(NotifyCollectionChangedAction.Add, item, sortedExtensions.Count - 1); - } - return item; - } - - /// Gets the existing extension item or creates one and adds it to the list. - /// - /// The path to get the extension from. - /// The extension item with the specified extension. - public ExtensionItem GetOrAddFromPath(string path) { - return GetOrAdd(GetAndNormalizeExtension(path)); - } - - /// Removes the extension item from the list. - /// - /// The extension item to remove - /// True if the extension item was contained in the list and removed. - internal bool Remove(ExtensionItem item) { - if (extensions.Remove(item.Extension)) { - int index = sortedExtensions.IndexOf(item); - sortedExtensions.RemoveAt(index); - unusedExtensions.Add(item.Extension, item); - RaisePropertyChanged(nameof(Count)); - RaisePropertyChanged(nameof(UnusedCount)); - RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, item, index); - return true; - } - return false; - } - - /// Removes the specified item with the specified extension from the list. - /// - /// The extension of the item to remove - /// True if the extension was contained in the list and removed. - internal bool Remove(string extension) { - NormalizeExtension(ref extension); - if (extensions.TryGetValue(extension, out ExtensionItem item)) { - unusedExtensions.Add(extension, item); - extensions.Remove(extension); - int index = sortedExtensions.IndexOf(item); - sortedExtensions.RemoveAt(index); - RaisePropertyChanged(nameof(Count)); - RaisePropertyChanged(nameof(UnusedCount)); - RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, item, index); - return true; - } - return false; - } - - /// Removes all extensions from the list. - internal void Clear() { - List oldItems = sortedExtensions.GetFullRange(); - sortedExtensions.Clear(); - foreach (ExtensionItem item in oldItems) { - item.ClearFilesMinimal(); - unusedExtensions.Add(item.Extension, item); - } - extensions.Clear(); - TotalSize = 0; - TotalFileCount = 0; - RaisePropertyChanged(nameof(Count)); - RaisePropertyChanged(nameof(UnusedCount)); - RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, oldItems, 0); - } - - #endregion - - #region Validation - - /// Validates the extensions and sorts them in size descending order. - private void Validate() { - sortedExtensions.Sort(); - RefreshPalette(); - //RaiseCollectionChanged(NotifyCollectionChangedAction.Reset); - } - - /// Refreshes the extensions file palette. - private void RefreshPalette() { - int count = sortedExtensions.Count; - for (int i = 0; i < count; i++) { - sortedExtensions[i].SetColor(settings.GetFilePaletteColor(i), i); - } - } - - #endregion - - #region IEnumerator Implementation - - /// Gets the enumerator for the extension items. - IEnumerator IEnumerable.GetEnumerator() { - return sortedExtensions.GetEnumerator(); - } - /// Gets the enumerator for the extension items. - IEnumerator IEnumerable.GetEnumerator() { - return sortedExtensions.GetEnumerator(); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Model/Extensions/Misc/ExtensionItemEvents.cs b/WinDirStat.Net.Base/Model/Extensions/Misc/ExtensionItemEvents.cs deleted file mode 100644 index b36e453..0000000 --- a/WinDirStat.Net.Base/Model/Extensions/Misc/ExtensionItemEvents.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Model.Extensions { - /// The event action type for . - public enum ExtensionItemAction { - // State - /// The preview color of the extension changed. - ColorChanged, - - // Accessors - /// Requests the view watching this node to show itself. - GetViewModel, - } - - /// The event arguments for . - public class ExtensionItemEventArgs { - /// The action to notify the view model of. - public ExtensionItemAction Action { get; } - /// Gets the index of the extension item in the sorted list. - public int Index { get; } - /// - /// The view model if is . - /// - public object ViewModel { get; set; } - - /// - /// Constructs the that just require an action. - /// - public ExtensionItemEventArgs(ExtensionItemAction action) { - Action = action; - Index = -1; - } - - /// - /// Constructs the that require an action and index. - /// - public ExtensionItemEventArgs(ExtensionItemAction action, int index) { - Action = action; - Index = index; - } - } - - /// The event handler for . - /// - /// The that sent this changed event. - /// The for this changed event. - public delegate void ExtensionItemEventHandler(ExtensionItem sender, ExtensionItemEventArgs e); -} diff --git a/WinDirStat.Net.Base/Model/Files/FileItem.cs b/WinDirStat.Net.Base/Model/Files/FileItem.cs deleted file mode 100644 index c75e6c2..0000000 --- a/WinDirStat.Net.Base/Model/Files/FileItem.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Model.Extensions; -using WinDirStat.Net.Services; - -namespace WinDirStat.Net.Model.Files { - /// The file tree item that identifies an actual file. - [Serializable] - public class FileItem : FileItemBase { - - #region Fields - - /// Gets the extension item of the file. - public override sealed ExtensionItem ExtensionItem { get; } - - #endregion - - #region Constructors - - /// Constructs the with a . - /// - /// The file information. - /// The extension information. - public FileItem(FileSystemInfo info, ExtensionItem extension) - : base(info, FileItemType.File, FileItemFlags.FileType) - { - Debug.Assert(extension != null); - ExtensionItem = extension; - } - - /// Constructs the with a . - /// - /// The file information. - /// The extension information. - public FileItem(IScanFileInfo info, ExtensionItem extension) - : base(info, FileItemType.File, FileItemFlags.FileType) - { - Debug.Assert(extension != null); - ExtensionItem = extension; - } - - #endregion - - #region FileItemBase Overrides - - /// - /// Gets the extension of the file. Empty extensions are always returned with a '.'. - /// - public override sealed string Extension => ExtensionItem.Extension; - - #endregion - - #region FileItemBase Override Methods - - /// Refreshes the file. Returns true if it still exists. - /// - /// True if the file still exists. - public override sealed bool Refresh() { - FileInfo info = new FileInfo(FullName); - if (info.Exists && !info.Attributes.HasFlag(FileAttributes.Directory)) { - Attributes = info.Attributes; - - long oldSize = Size; - if (!info.Attributes.HasFlag(FileAttributes.ReparsePoint)) - Size = info.Length; - else - Size = 0L; - ExtensionItem.RefreshFile(Size, oldSize); - - LastWriteTimeUtc = info.LastWriteTimeUtc; - - return RefreshFinal(true); - } - ExtensionItem.RemoveFile(Size); - return RefreshFinal(false); - } - - /// Checks if the file still exists. - /// - /// True if the file exists. - public override sealed bool CheckExists() => CheckExistsFinal(File.Exists(FullName)); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Model/Files/FileItemBase.cs b/WinDirStat.Net.Base/Model/Files/FileItemBase.cs deleted file mode 100644 index 34bcbdd..0000000 --- a/WinDirStat.Net.Base/Model/Files/FileItemBase.cs +++ /dev/null @@ -1,596 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Runtime.CompilerServices; -using System.Text; - -using WinDirStat.Net.Model.Extensions; -using WinDirStat.Net.Rendering; -using WinDirStat.Net.Structures; -using WinDirStat.Net.Utils; - -namespace WinDirStat.Net.Model.Files { - /// The abstract base class for all file tree items. - [Serializable] - [DebuggerDisplay("{DebuggerDisplay,nq}")] - public abstract class FileItemBase : IComparable, IComparable, ITreemapItem { - - #region Constants - - /// - /// The static list of empty children to use for empty lists. This should never be modified. - /// - private protected static readonly List EmptyChildren = new List(); - - #endregion - - #region Fields - - // Fields and property fields are both stored here to keep track of memory usage - // ViewModel Events also has one event that will take up space - - /// Gets the type of this file item. - public FileItemType Type { get; } - /// The volatile state of the file. - private protected FileItemStates state; - /// The constant flags of the file. - private protected FileItemFlags flags; - - /// Gets the parent containing this file. - public FolderItem Parent { get; internal set; } - /// - /// Gets the UTC time of when the file was last written to. - /// If this is a container, it returns the most recent time of all children. - /// - public DateTime LastWriteTimeUtc { get; private protected set; } - /// Gets the name of the file. - public string Name { get; } - /// Gets the total size of the file and all of its children. - public long Size { get; private protected set; } - /// Gets the rectangle of the file for drawing in the treemap. - public Rectangle2S Rectangle { get; set; } - - #endregion - - #region Constructors - - /// Constructs the without any file info. - /// - /// The name of the item. - /// The type of the item. - /// The flags for the item (except ). - private protected FileItemBase(string name, FileItemType type, FileItemFlags flags) { - if (flags != FileItemFlags.None) - this.flags |= (flags & FileItemFlags.TypeFlagsMask); - if (type == FileItemType.Volume) - name = PathUtils.AddDirectorySeparator(name); - - Name = name; - Type = type; - state |= FileItemStates.Exists; - } - - /// Constructs the with a . - /// - /// The file information. - /// The type of the item. - /// The flags for the item (except ). - private protected FileItemBase(FileSystemInfo info, FileItemType type, FileItemFlags flags) - : this(info.Name, type, flags) - { - LastWriteTimeUtc = info.LastWriteTimeUtc; - Attributes = info.Attributes; - - if (!info.Attributes.HasFlag(FileAttributes.Directory) && - !info.Attributes.HasFlag(FileAttributes.ReparsePoint) && - info is FileInfo fileInfo) - Size = fileInfo.Length; - - if (!info.Exists) { - state &= ~FileItemStates.Exists; - Attributes = 0; - LastWriteTimeUtc = DateTime.MinValue; - } - } - - /// Constructs the with a . - /// - /// The file information. - /// The type of the item. - /// The flags for the item (except ). - private protected FileItemBase(IScanFileInfo info, FileItemType type, FileItemFlags flags) - : this(info.Name, type, flags) - { - LastWriteTimeUtc = info.LastWriteTimeUtc; - Attributes = info.Attributes; - - if (!info.IsDirectory && !info.IsSymbolicLink) - Size = info.Size; - } - - #endregion - - #region ViewModel Events - - // TODO: Eventually determine if we can move this to FolderItem - - /// Notifies any view models watching this item of important changes to the file. - [field: NonSerialized] - public event FileItemEventHandler Changed; - - /// Gets if the file is being watched by a view model. - public bool IsWatched => Changed != null; - - protected void RaiseChanged(FileItemEventArgs e) { - Changed?.Invoke(this, e); - } - protected void RaiseChanged(FileItemAction action) { - Changed?.Invoke(this, new FileItemEventArgs(action)); - } - protected void RaiseChanged(FileItemAction action, int index) { - Changed?.Invoke(this, new FileItemEventArgs(action, index)); - } - protected void RaiseChanged(FileItemAction action, List children, int index) { - Changed?.Invoke(this, new FileItemEventArgs(action, children, index)); - } - protected void RaiseChanged(FileItemAction action, IEnumerable children, int index) { - Changed?.Invoke(this, new FileItemEventArgs(action, children, index)); - } - protected void RaiseChanged(FileItemAction action, FileItemBase child, int index) { - Changed?.Invoke(this, new FileItemEventArgs(action, child, index)); - } - - public object GetViewModel() { - FileItemEventArgs e = new FileItemEventArgs(FileItemAction.GetViewModel); - RaiseChanged(e); - return e.ViewModel; - } - - public TViewModel GetViewModel() where TViewModel : class { - FileItemEventArgs e = new FileItemEventArgs(FileItemAction.GetViewModel); - RaiseChanged(e); - return e.ViewModel as TViewModel; - } - - #endregion - - #region Virtual Methods - - /// Refreshes the file. Returns true if it still exists. - /// - /// True if the file still exists. - public virtual bool Refresh() => true; - - /// Checks if the file still exists. - /// - /// True if the file exists. - public virtual bool CheckExists() => true; - - /// - /// Must be called at the end of in order to raise a Refresh change. - /// For file types only. - /// - /// - /// True if the file exists. - /// The passed parameter. - protected bool RefreshFinal(bool existsNew) { - Exists = existsNew; - if (IsWatched) - RaiseChanged(FileItemAction.Refreshed); - return existsNew; - } - - /// - /// Must be called at the end of in order to raise a Exists change. - /// For file types only. - /// - /// - /// True if the file exists. - /// The passed parameter. - protected bool CheckExistsFinal(bool existsNew) { - if (Exists != existsNew) { - Exists = existsNew; - if (IsWatched) - RaiseChanged(FileItemAction.Exists); - } - return existsNew; - } - - #endregion - - #region Virtual Properties - - /// Returns true if this folder has any children. - public virtual bool HasChildren => false; - /// - /// Gets the list of children for this folder. - /// This list is only for fast access and should never be modified. - /// - internal virtual List Children => EmptyChildren; - - /// - /// Gets the number of files and directories this folder contains. Returns -1 if this is not a - /// container. - /// - public virtual int ItemCount => -1; - /// - /// Gets the number of files this folder contains. Returns -1 if this is not a container. - /// - public virtual int FileCount { - get => -1; - protected set => throw InvalidSet(); - } - /// - /// Gets the number of directories this folder contains. Returns -1 if this is not a container. - /// - public virtual int SubdirCount { - get => -1; - protected set => throw InvalidSet(); - } - - /// - /// Gets the extension item of the file. - /// Returns if this is not a file. - /// - public virtual ExtensionItem ExtensionItem => ExtensionItem.NotAFile; - /// - /// Gets the extension of the file. Empty file extensions are always returned with a '.'. - /// Returns if this is not a file. - /// - public virtual string Extension => string.Empty; - - #endregion - - #region Properties - - /// Finds the absolute root node. - public RootItem Root { - get { - if (IsAbsoluteRootType) - return (RootItem) this; - else - return Parent.Root; - } - } - - /// Gets the file root node - public FolderItem FileRoot { - get { - if (IsFileRootType) - return (RootItem) this; - else - return Parent.Root; - } - } - - /// - /// Gets the folder/drive parent of the node. - /// This is used to skip FileCollection containers. - /// - public FolderItem FileParent { - get { - if (Parent != null && Parent.Type == FileItemType.FileCollection) - return Parent.Parent; - return Parent; - } - } - - /// - /// Gets the local time of when the file was last written to. - /// If this is a container, it returns the most recent time of all children. - /// - public DateTime LastWriteTime => LastWriteTimeUtc.ToLocalTime(); - - /// Gets the visible level of the item in the tree. - public int VisibleLevel => Parent != null ? Parent.VisibleLevel + 1 : 0; - - /// Gets the file level of the item in the tree. - public int FileLevel => Parent != null ? (Parent.FileLevel + (Parent.IsFileType ? 1 : 0)) : 0; - - /// Gets the path of the file. - public string FullName { - get { - if (IsFileRootType) - return ((RootItem) this).RootPath; - else if (IsFileType) - return PathUtils.CombineNoChecks(Parent.FullName, Name); - else if (Type != FileItemType.Computer) - return Parent.FullName; - else - return "::{20d04fe0-3aea-1069-a2d8-08002b30309d}";// Environment.GetFolderPath(Environment.SpecialFolder.MyComputer); - } - } - - /// Gets this file's size relative to the parent's size. - public double Percent { - get { - if (IsAbsoluteRootType) - return 1d; - else if (Parent.Size == 0) - return 0d; - else - return (double) Size / Parent.Size; - } - } - - /// Gets if the file has a size of zero. - public bool IsEmptySize => Size == 0; - - /// Gets if this file is a shortcut. - public bool IsShortcut => IsReparsePointFile || (Extension == ".lnk"); - - /// Gets the attributes for this file. - public FileAttributes Attributes { - get { - FileAttributes attr = 0; - if (IsReadOnlyFile) attr |= FileAttributes.ReadOnly; - if (IsHiddenFile) attr |= FileAttributes.Hidden; - if (IsSystemFile) attr |= FileAttributes.System; - if (IsArchiveFile) attr |= FileAttributes.Archive; - if (IsCompressedFile) attr |= FileAttributes.Compressed; - if (IsEncryptedFile) attr |= FileAttributes.Encrypted; - if (IsReparsePointFile) attr |= FileAttributes.ReparsePoint; - if (IsTemporaryFile) attr |= FileAttributes.Temporary; - return attr; - } - private protected set { - IsReadOnlyFile = value.HasFlag(FileAttributes.ReadOnly); - IsHiddenFile = value.HasFlag(FileAttributes.Hidden); - IsSystemFile = value.HasFlag(FileAttributes.System); - IsArchiveFile = value.HasFlag(FileAttributes.Archive); - IsCompressedFile = value.HasFlag(FileAttributes.Compressed); - IsEncryptedFile = value.HasFlag(FileAttributes.Encrypted); - IsReparsePointFile = value.HasFlag(FileAttributes.ReparsePoint); - IsTemporaryFile = value.HasFlag(FileAttributes.Temporary); - } - } - /// Gets the file attributes as a displayable string. - public string AttributesString { - get { - StringBuilder str = new StringBuilder(); - if (IsReadOnlyFile) str.Append('R'); - if (IsHiddenFile) str.Append('H'); - if (IsSystemFile) str.Append('S'); - if (IsArchiveFile) str.Append('A'); - if (IsCompressedFile) str.Append('C'); - if (IsEncryptedFile) str.Append('E'); - return str.ToString(); - } - } - /// Gets the file attributes as an integer to use for sorting. - public short SortAttributes => unchecked((short) (flags & FileItemFlags.SortAttributesMask)); - - #endregion - - #region Constant Flags - - /// This file has the attribute. - public bool IsReadOnlyFile { - get => flags.HasFlag(FileItemFlags.ReadOnly); - private set => flags = flags.SetFlag(FileItemFlags.ReadOnly, value); - } - /// This file has the attribute. - public bool IsHiddenFile { - get => flags.HasFlag(FileItemFlags.Hidden); - private set => flags = flags.SetFlag(FileItemFlags.Hidden, value); - } - /// This file has the attribute. - public bool IsSystemFile { - get => flags.HasFlag(FileItemFlags.System); - private set => flags = flags.SetFlag(FileItemFlags.System, value); - } - /// This file has the attribute. - public bool IsArchiveFile { - get => flags.HasFlag(FileItemFlags.Archive); - private set => flags = flags.SetFlag(FileItemFlags.Archive, value); - } - /// This file has the attribute. - public bool IsCompressedFile { - get => flags.HasFlag(FileItemFlags.Compressed); - private set => flags = flags.SetFlag(FileItemFlags.Compressed, value); - } - /// This file has the attribute. - public bool IsEncryptedFile { - get => flags.HasFlag(FileItemFlags.Encrypted); - private set => flags = flags.SetFlag(FileItemFlags.Encrypted, value); - } - /// This file has the attribute. - public bool IsReparsePointFile { - get => flags.HasFlag(FileItemFlags.ReparsePoint); - private set => flags = flags.SetFlag(FileItemFlags.ReparsePoint, value); - } - /// This file has the attribute. - public bool IsTemporaryFile { - get => flags.HasFlag(FileItemFlags.Temporary); - private set => flags = flags.SetFlag(FileItemFlags.Temporary, value); - } - - /// True if this directory is case sensitive. - public bool CaseSensitive { - get => flags.HasFlag(FileItemFlags.CaseSensitive); - private protected set => flags = flags.SetFlag(FileItemFlags.CaseSensitive, value); - } - /// True if this type can contain other nodes. - public bool IsContainerType { - get => flags.HasFlag(FileItemFlags.ContainerType); - private set => flags = flags.SetFlag(FileItemFlags.ContainerType, value); - } - /// True if this is a real file system node. - public bool IsFileType { - get => flags.HasFlag(FileItemFlags.FileType); - private set => flags = flags.SetFlag(FileItemFlags.FileType, value); - } - /// True if this node contains the root path for the file tree. - public bool IsFileRootType { - get => flags.HasFlag(FileItemFlags.FileRootType); - private set => flags = flags.SetFlag(FileItemFlags.FileRootType, value); - } - /// True if this node never has a parent. A computer node is always of this type. - public bool IsAbsoluteRootType { - get => flags.HasFlag(FileItemFlags.AbsoluteRootType); - private set => flags = flags.SetFlag(FileItemFlags.AbsoluteRootType, value); - } - /// True if this node is an absolute or file root. - public bool IsAnyRootType { - get => (flags & (FileItemFlags.FileRootType | FileItemFlags.AbsoluteRootType)) != 0; - } - - #endregion - - #region State Flags - - /// - /// This lock is static because these values are not accessed often and only within two threads. - /// (mostly in just the async thread) - /// - private static readonly object stateLock = new object(); - - /// Gets if the folder and all its children have been fully scanned. - public bool IsDone { - get { - lock (stateLock) - return state.HasFlag(FileItemStates.Done); - } - private protected set { - lock (stateLock) - state = state.SetFlag(FileItemStates.Done, value); - } - } - /// Gets if the folder needs to be validated. - public bool IsInvalidated { - get { - lock (stateLock) - return state.HasFlag(FileItemStates.Invalidated); - } - private protected set { - lock (stateLock) { - // Perform two operations in the same lock - if (value) - state &= ~FileItemStates.Done; - state = state.SetFlag(FileItemStates.Invalidated, value); - } - } - } - /// Gets if the folder is currently validating. - public bool IsValidating { - get { - lock (stateLock) - return state.HasFlag(FileItemStates.Validating); - } - private protected set { - lock (stateLock) { - // Perform two operations in the same lock - if (value) - state &= ~FileItemStates.Invalidated; - state = state.SetFlag(FileItemStates.Validating, value); - } - } - } - /// Gets if the file exists in the system. - public bool Exists { - get { - lock (stateLock) - return state.HasFlag(FileItemStates.Exists); - } - private protected set { - bool changed = false; - lock (stateLock) { - changed = value != Exists; - state = state.SetFlag(FileItemStates.Exists, value); - } - if (changed && IsWatched) - RaiseChanged(FileItemAction.Exists); - } - } - - #endregion - - #region ITreemapItem Implementation - - /// Gets if this treemap item is a leaf that should be drawn. - public bool IsLeaf => !IsContainerType; - - /// Gets the color of this treemap item leaf. - public Rgb24Color Color { - get { - switch (Type) { - case FileItemType.File: return ExtensionItem.Color; - case FileItemType.FreeSpace: return new Rgb24Color(100, 100, 100); - case FileItemType.Unknown: return new Rgb24Color(255, 255, 0); - default: return Rgb24Color.Black; - } - } - } - - /// Gets the number of children in this treemap item. - public virtual int ChildCount => 0; - - /// Gets the child at the specified index in the treemap item. - public virtual FileItemBase this[int index] => throw InvalidCall(); - /// Gets the child at the specified index in the treemap item. - ITreemapItem ITreemapItem.this[int index] => this[index]; - - /// Gets the number of children in this treemap item. - Rectangle2I ITreemapItem.Rectangle { - get => Rectangle; - set => Rectangle = (Rectangle2S) value; - } - - #endregion - - #region Exception Helpers - - /// - /// Throws an stating the calling method cannot be called due - /// to lack of support from this class. - /// - private Exception InvalidCall([CallerMemberName] string name = null) { - return new InvalidOperationException($"{name} cannot be called because this item does not " + - $"support it!"); - } - /// - /// Throws an stating the calling property cannot be set due - /// to lack of support from this class. - /// - private Exception InvalidSet([CallerMemberName] string name = null) { - return new InvalidOperationException($"{name} cannot be set because this item does not " + - $"support it!"); - } - - #endregion - - #region IComparable Implementation - - /// Compares this file to another based on size in descending order. - /// - /// The other file to compare to. - /// The comparison result. - public int CompareTo(FileItemBase other) { - int diff = other.Size.CompareTo(Size); - if (diff == 0) - return string.Compare(Name, other.Name, true); - return diff; - } - - /// Compares this file to another based on size in descending order. - /// - /// The other file to compare to. - /// The comparison result. - int IComparable.CompareTo(object obj) { - return CompareTo((FileItemBase) obj); - } - - #endregion - - #region ToString/DebuggerDisplay - - /// Gets the string representation of this item. - public override string ToString() => $"{Type}: {Name}"; - - /// Gets the string used to represent the file in the debugger. - private string DebuggerDisplay => Name; - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Model/Files/FolderItem.cs b/WinDirStat.Net.Base/Model/Files/FolderItem.cs deleted file mode 100644 index ae23b18..0000000 --- a/WinDirStat.Net.Base/Model/Files/FolderItem.cs +++ /dev/null @@ -1,1142 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using WinDirStat.Net.Utils; - -namespace WinDirStat.Net.Model.Files { - /// The base class for containing all other file items. - /// - /// Rules for Folder structure: - /// Folders/Volumes can store files in 3 possible ways: - /// A) 0-1 files, unlimited containers - /// B) unlimited files, 0 containers - /// C) 1 file collection (with 2+ files), 1+ containers - /// If more than one file is found then we know containers are not being stored. - /// - [Serializable] - [DebuggerDisplay("{DebuggerDisplay,nq}")] - public class FolderItem : FileItemBase { - - #region Fields - - /// - /// The list of children in the folder. - /// Always use the list modification methods to add or remove from the list. This is important - /// because they account for if is being used. - /// - protected volatile List children = EmptyChildren; - - /// Gets the number of files this folder contains. - public override sealed int FileCount { get; protected set; } - /// Gets the number of directories this folder contains. - public override sealed int SubdirCount { get; protected set; } - - #endregion - - #region Constructors - - /// Constructs a file collection . - private FolderItem() - : base(StringConstants.FileCollectionName, FileItemType.FileCollection, - FileItemFlags.ContainerType) - { - // File collections are only created when adding children to them - EnsureChildren(); - } - - /// Constructs the without any file info. - /// - /// The name of the item. - /// The type of the item. - /// The flags for the item (except ). - private protected FolderItem(string name, FileItemType type, FileItemFlags flags) - : base(name, type, flags) - { - } - - /// Constructs the with a . - /// - /// The file information. - /// The type of the item. - /// The flags for the item (except ). - private protected FolderItem(FileSystemInfo info, FileItemType type, FileItemFlags flags) - : base(info, type, flags) - { - //CaseSensitive = DirectoryCaseSensitivity.IsCaseSensitive(info.FullName); - } - - /// Constructs the with a . - /// - /// The file information. - /// The type of the item. - /// The flags for the item (except ). - private protected FolderItem(IScanFileInfo info, FileItemType type, FileItemFlags flags) - : base(info, type, flags) - { - //CaseSensitive = DirectoryCaseSensitivity.IsCaseSensitive(info.FullName); - } - - /// - /// Constructs the directory with a . - /// - /// - /// The file information. - /// The type of the item. - /// The flags for the item (except ). - public FolderItem(FileSystemInfo info) - : base(info, FileItemType.Directory, FileItemFlags.ContainerType | FileItemFlags.FileType) - { - } - - /// - /// Constructs the directory with a . - /// - /// - /// The file information. - /// The type of the item. - /// The flags for the item (except ). - public FolderItem(IScanFileInfo info) - : base(info, FileItemType.Directory, FileItemFlags.ContainerType | FileItemFlags.FileType) - { - } - - #endregion - - #region ViewModel Events (Unused) - /* - // TODO: Eventually determine if we can move this to FolderItem - - /// Notifies any view models watching this item of important changes to the file. - [field: NonSerialized] - public event FileItemEventHandler Changed; - - /// Gets if the file is being watched by a view model. - public bool IsWatched { - get => Changed != null; - } - - protected void RaiseChanged(FileItemEventArgs e) { - Changed?.Invoke(this, e); - } - protected void RaiseChanged(FileItemAction action) { - Changed?.Invoke(this, new FileItemEventArgs(action)); - } - protected void RaiseChanged(FileItemAction action, int index) { - Changed?.Invoke(this, new FileItemEventArgs(action, index)); - } - protected void RaiseChanged(FileItemAction action, List children, int index) { - Changed?.Invoke(this, new FileItemEventArgs(action, children, index)); - } - protected void RaiseChanged(FileItemAction action, FileItemBase child, int index) { - Changed?.Invoke(this, new FileItemEventArgs(action, child, index)); - } - - public object GetViewModel() { - FileItemEventArgs e = new FileItemEventArgs(FileItemAction.GetView); - RaiseChanged(e); - return e.ViewModel; - } - - public TViewModel GetViewModel() { - FileItemEventArgs e = new FileItemEventArgs(FileItemAction.GetView); - RaiseChanged(e); - return (TViewModel) e.ViewModel; - } - */ - #endregion - - #region FileItemBase Overrides - - /// Returns true if this folder has any children. - public override sealed bool HasChildren => children.Count > 0; - /// Gets the list of children for this folder. - /// This list is only for fast access and should never be modified. - /// - internal override sealed List Children => children; - - /// Gets the number of fils and directories this folder contains. - public override sealed int ItemCount => FileCount + SubdirCount; - - #endregion - - #region ITreemapItem Overrides - - /// Gets the number of children in this container. - public override sealed int ChildCount => children.Count; - - /// Gets the child at the specified index in the container. - public override sealed FileItemBase this[int index] => children[index]; - - #endregion - - #region Helper Properties - - /// Returns true if the folder is storing at least 2 files and 0 containers. - private bool IsStoringMultipleFiles { - get { - // Always called from a File Folder, for a file folder. - // This is why the return strange. - if (Type == FileItemType.FileCollection) - return false; - // If true, another file means containers are not being stored. - bool fileFound = false; - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - if (!child.IsContainerType) { - if (child.Type == FileItemType.File) { - if (!fileFound) - fileFound = true; - else - return true; - } - } - else { - return false; - } - } - return false; - } - } - /// Returns true if the folder is storing any number of containers. - private bool IsStoringContainers { - get { - // Always called from a File Folder, for a file folder. - // This is why the return strange. - if (Type == FileItemType.FileCollection) - return true; - // If true, another file means containers are not being stored. - bool fileFound = false; - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - if (!child.IsContainerType) { - if (child.Type == FileItemType.File) { - if (!fileFound) - fileFound = true; - else - return false; - } - } - else { - return true; - } - } - return false; - } - } - - /// Returns true if the folder is storing more than 1 container. - private bool IsStoringMultipleContainers { - get { - // Always called from a File Folder, for a file folder. - // This is why the return strange. - if (Type == FileItemType.FileCollection) - return true; - // If true, another file means containers are not being stored. - bool fileFound = false; - bool containerFound = false; - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - if (!child.IsContainerType) { - if (child.Type == FileItemType.File) { - if (!fileFound) - fileFound = true; - else - return false; - } - } - else if (!containerFound) { - containerFound = true; - } - else { - return true; - } - } - return false; - } - } - - /// Returns true if the folder is storing just 1 container. - private bool IsStoringOneContainer { - get { - // Always called from a File Folder, for a file folder. - // This is why the return strange. - if (Type == FileItemType.FileCollection) - return true; - // If true, another file means containers are not being stored. - bool fileFound = false; - bool containerFound = false; - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - if (!child.IsContainerType) { - if (child.Type == FileItemType.File) { - if (!fileFound) - fileFound = true; - else - return false; - } - } - else if (!containerFound) { - containerFound = true; - } - else { - return false; - } - } - return containerFound; - } - } - - - /// - /// Gets if the folder is using for its list. - /// - internal protected bool IsEmpty => children == EmptyChildren; - - #endregion - - #region Item Finders - - /// Gets the file collection for this folder. - /// - /// The folder's file collection, or null if it does not exist. - public FolderItem GetFileCollection() { - if (Type == FileItemType.FileCollection) - return this; - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - if (child.Type == FileItemType.FileCollection) - return (FolderItem) child; - } - return null; - } - - /// Gets the first file in this folder. - /// - /// The folder's first file, or null if one does not exist. - public FileItem GetFirstFile() { - // Always called from a File Folder, for a file folder. - // This is why the return strange. - if (Type == FileItemType.FileCollection) - return null; - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - if (child.Type == FileItemType.File) - return (FileItem) child; - } - return null; - } - - /// Gets the first file in this folder and checks if there are multiple files. - /// - /// The output result of if there are multiple files. - /// The folder's only file, or null if there is not exactly one file. - public FileItem GetFirstFile(out bool multipleFiles) { - multipleFiles = false; - // Always called from a File Folder, for a file folder. - // This is why the return strange. - if (Type == FileItemType.FileCollection) - return null; - FileItem firstFile = null; - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - if (firstFile == null) { - if (child.Type == FileItemType.File) - firstFile = (FileItem) child; - } - else if (child.Type == FileItemType.File) { - // Multiple files encountered, we're not storing a single file - multipleFiles = true; - return firstFile; - } - else if (child.IsContainerType) { - // Container encountered, we must be storing a single file - return firstFile; - } - } - return firstFile; - } - - /*/// Gets the only file in this folder. - /// - /// The folder's only file, or null if there is not exactly one file. - public FileItem GetSingleFile() { - // Always called from a File Folder, for a file folder. - // This is why the return strange. - if (Type == FileItemType.FileCollection) - return null; - FileItem firstFile = null; - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - if (firstFile == null) { - if (child.Type == FileItemType.File) - firstFile = (FileItem) child; - } - else if (child.Type == FileItemType.File) { - // Multiple files encountered, we're not storing a single file - return null; - } - else if (child.IsContainerType) { - // Container encountered, we must be storing a single file - return firstFile; - } - } - return firstFile; - }*/ - - #endregion - - #region Add/Remove Item - - /// Adds the item to the container. - /// - /// The item to add. - public void AddItem(FileItemBase item) { - FolderItem fileCollection = null; - FileItem firstFile = null; - // Finding these items is not relevant when adding items like FreeSpace or Unknown - if (item.Type == FileItemType.File || (item.IsContainerType && !item.IsAnyRootType)) { - fileCollection = GetFileCollection(); - firstFile = GetFirstFile(); - } - AddItem(item, ref fileCollection, ref firstFile); - } - - /// - /// Adds the item to the container and keeps track of the file collection and single file. - /// - /// - /// The item to add. - /// - /// The container's file collection. Keep track of this when scanning this directory. - /// - /// - /// The container's first file. Keep track of this when scanning this directory. - /// - public void AddItem(FileItemBase item, ref FolderItem fileCollection, ref FileItem firstFile) { - if (Type == FileItemType.FileCollection) - throw new InvalidOperationException($"Cannot call {nameof(AddItem)} from a File Collection!"); - - // We know we're adding an item to children, make sure it's setup - EnsureChildren(); - - lock (children) { - if (item.Type == FileItemType.File) { - // Add the file to the extensions - item.ExtensionItem.AddFile(item.Size); - - if (fileCollection != null) { - fileCollection.Add(item); - fileCollection.Invalidate(); - // Item added to file collection, do not continue - Debug.Assert(IsInvalidated); - return; - } - else if (firstFile == null) { - // Our first file! Let's celebrate by keeping track of it. - // If more files are added then it will no longer be tracked. - firstFile = (FileItem) item; - } - else if (IsStoringContainers) { - // We've hit our limit of only one visible file when a - // folder is storing non-files. Move to FileCollection. - fileCollection = new FolderItem(); - Remove(firstFile); - Add(fileCollection); - fileCollection.Add(firstFile); - fileCollection.Add(item); - fileCollection.Invalidate(); - firstFile = null; - // Item added to file collection, do not continue - Debug.Assert(IsInvalidated); - return; - } - // Removed after file -> firstFile (and was unassigned when holding more files) - // file is only non-null when one file is being stored (with or without other files) - /*else { - bool storingContainers = IsStoringContainers; - //children.Count == 0 is wrong, I forgot about Free/Unknown Space - if (children.Count == 0 || (firstFile == null && storingContainers)) { - // Our first file! Let's celebrate by keeping track of it. - // If more files are added then it will no longer be tracked. - firstFile = (FileItem) item; - } - else if (firstFile != null) { - if (storingContainers) { - // We've hit our limit of only one visible file when a - // folder is storing non-files. Move to FileCollection. - fileCollection = new FolderItem(); - Remove(firstFile); - Add(fileCollection); - fileCollection.Add(firstFile); - fileCollection.Add(item); - fileCollection.Invalidate(); - firstFile = null; - // Item added to file collection, do not continue - return; - } - firstFile = null; - } - }*/ - } - else if (item.IsContainerType && IsStoringMultipleFiles) { - // Setup file collection if the folder needs to store a container item - Debug.Assert(fileCollection == null); - fileCollection = new FolderItem(); - List files = ClearAndGetFiles(); - Add(fileCollection); - fileCollection.AddRange(files); - fileCollection.Invalidate(); - firstFile = null; - } - - Add(item); - Invalidate(); - - Debug.Assert(IsInvalidated); - } - } - - /// Removes the item from the container. - /// - /// The item to remove. - public void RemoveItem(FileItemBase item) { - FolderItem fileCollection = null; - //FileItem firstFile = null; - // Finding these items is not relevant when adding items like FreeSpace or Unknown - if (item.Type == FileItemType.File || (item.IsContainerType && !item.IsAnyRootType)) { - fileCollection = GetFileCollection(); - //firstFile = GetFirstFile(); - } - RemoveItem(item, ref fileCollection/*, ref firstFile*/); - } - - /// - /// Removes the item from the container and keeps track of the file collection and single file. - /// - /// - /// The item to remove. - /// - /// The container's file collection. Keep track of this when scanning this directory. - /// - /// - /// The container's single file. Keep track of this when scanning this directory. - /// - public void RemoveItem(FileItemBase item, ref FolderItem fileCollection/*, ref FileItem firstFile*/) { - if (Type == FileItemType.FileCollection) - throw new InvalidOperationException($"Cannot call {nameof(AddItem)} from a File Collection!"); - - lock (children) { - if (item.Type == FileItemType.File) { - // Remove the file from the extensions - item.ExtensionItem.RemoveFile(item.Size); - - if (fileCollection != null) { - fileCollection.Remove(item); - if (fileCollection.children.Count == 1) { - // Once we go down to one file, we'll no longer need the file collection - //firstFile = (FileItem) fileCollection.children[0]; - FileItemBase firstFile = fileCollection.children[0]; - fileCollection.RemoveAt(0); - Remove(fileCollection); - Add(firstFile); - Invalidate(); - // It's dead Jim, remove the reference - fileCollection = null; - } - else { - // Standard procedure, no changes in structure - fileCollection.Invalidate(); - } - return; - } - } - else if (item.IsContainerType) { - // Recursively remove all of the container's children - ((FolderItem) item).RecurseClearChildren(); - - if (fileCollection != null && IsStoringContainers) { - // No more containers, open the gate for files to return back to folder. - // Also remember to remove the no-longer-in-use file collection. - Remove(item); - List files = fileCollection.ClearAndGetChildren(); - //firstFile = (FileItem) files[0]; - Remove(fileCollection); - AddRange(files); - Invalidate(); - // It's dead Jim, remove the reference - fileCollection = null; - return; - } - } - - Remove(item); - Invalidate(); - - // Set children back to EmptyChildren if we removed the last item - EnsureEmptyChildren(); - } - } - - /// - /// Recursively clears this folder's children from the file tree and any other associations. - /// - private protected void RecurseClearChildren() { - foreach (FileItemBase child in children) { - if (child is FolderItem subdir && !subdir.IsEmpty) - subdir.RecurseClearChildren(); - else if (child.Type == FileItemType.File) - child.ExtensionItem.RemoveFile(child.Size); - } - Clear(); - } - - /*/// - /// Removes this folder's files from the file tree and any other associations. - /// - /// Handles changes to the folder structure like normally removing an item. - /// - public void ClearFileItems() { - if (IsEmpty) - return; - - lock (children) { - FolderItem fileCollection = GetFileCollection(); - if (fileCollection != null) - ClearFileCollectionItems(fileCollection); - } - }*/ - - /// - /// Recursively removes this folder's children from the file tree and any other associations. - /// - /// Handles changes to the folder structure like normally removing an item. - /// - public void ClearItems() { - if (IsEmpty) - return; - - int count; - - List subdirs = new List(); - lock (children) { - count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - if (child is FolderItem subdir && child.Type != FileItemType.FileCollection) - subdirs.Add(subdir); - } - } - - // Clear all subdirectories outside of the children - // lock to prevent the UI from freezing. - count = subdirs.Count; - for (int i = 0; i < count; i++) { - subdirs[i].ClearItems(); - } - - lock (children) { - FolderItem fileCollection = null; - for (int i = 0; i < children.Count; i++) { - FileItemBase child = children[i]; - /*if (child is FolderItem subdir && !subdir.IsEmpty) { - if (subdir.Type == FileItemType.FileCollection) { - ClearFileCollectionItems(ref fileCollection); - continue; - } - else { - subdir.ClearItems(); - } - }*/ - // File Collections do not get removed - // through RemoveItem so let's continue - if (child.Type == FileItemType.FileCollection) - fileCollection = (FolderItem) child; - else if (child.Type == FileItemType.File) - child.ExtensionItem.RemoveFile(child.Size); - //RemoveAt(0); - //RemoveAt(i); - //RemoveItem(child, ref fileCollection); - //i--; - } - Clear(); - children = EmptyChildren; - fileCollection?.ClearFileCollectionItems(); - FileCount = 0; - SubdirCount = 0; - Size = 0; - } - } - - private void ClearFileCollectionItems() { - lock (children) { - for (int i = 0; i < children.Count; i++) { - FileItemBase child = children[i]; - child.ExtensionItem.RemoveFile(child.Size); - } - Clear(); - children = EmptyChildren; - } - } - - #endregion - - #region List Modification - - /// Adds the item to the container. - /// - /// The item to add. - protected void Add(FileItemBase item) { - //EnsureChildren(); - int index = children.Count; - children.Add(item); - item.Parent = this; - if (IsWatched) - RaiseChanged(FileItemAction.ChildrenAdded, item, index); - } - - /// Adds or removes the item from the container based on a conditional value. - /// - /// The item to add or remove. - /// The condition to add the item instead of removing it. - protected void AddOrRemove(FileItemBase item, bool addCondition) { - int index = children.IndexOf(item); - if (addCondition && index == -1) - Add(item); - else if (!addCondition && index != -1) - RemoveAt(index); - } - - /// Adds the items to the container. - /// - /// The items to add. - protected void AddRange(IEnumerable items) { - //EnsureChildren(); - int index = children.Count; - children.AddRange(items); - foreach (FileItemBase item in items) - item.Parent = this; - if (IsWatched) - RaiseChanged(FileItemAction.ChildrenAdded, items.ToList(), index); - } - - /// Removes the items from the container. - /// - /// The items to remove. - protected void RemoveRange(IEnumerable items) { - foreach (FileItemBase item in items) { - children.Remove(item); - item.Parent = null; - } - if (IsWatched) - RaiseChanged(FileItemAction.ChildrenRemoved, items.ToList(), -1); - } - - /// Removes the item from the container. - /// - /// The item to remove. - /// true if the item existed and was removed. - protected bool Remove(FileItemBase item) { - if (children.Remove(item)) { - item.Parent = null; - if (IsWatched) - RaiseChanged(FileItemAction.ChildrenRemoved, item, -1); - return true; - } - return false; - } - - /// Removes the item at the specified index in the container. - /// - /// The index of the item to remove. - protected void RemoveAt(int index) { - FileItemBase item = children[index]; - children.RemoveAt(index); - item.Parent = null; - if (IsWatched) - RaiseChanged(FileItemAction.ChildrenRemoved, item, index); - } - - /// Removes the items at the specified index in the container. - /// - /// The index of the items to remove. - /// The number of items to remove. - protected void RemoveRange(int index, int count) { - List items = children.GetRange(index, count); - children.RemoveRange(index, count); - for (int i = 0; i < count; i++) - items[i].Parent = null; - if (IsWatched) - RaiseChanged(FileItemAction.ChildrenRemoved, items.GetFullRange(), index); - } - - /// Clears the list. - protected void Clear() { - int count = children.Count; - if (count > 0) { - for (int i = 0; i < count; i++) - children[i].Parent = null; - if (IsWatched) { - List oldChildren = children.GetFullRange(); - children.Clear(); - //children = EmptyChildren; - RaiseChanged(FileItemAction.ChildrenRemoved, oldChildren, 0); - } - else { - children.Clear(); - //children = EmptyChildren; - } - } - } - - /// Clears the list and returns the range that was cleared. - private List ClearAndGetChildren() { - int count = children.Count; - if (count > 0) { - for (int i = 0; i < count; i++) - children[i].Parent = null; - List oldChildren = children.GetFullRange(); - children.Clear(); - if (IsWatched) - RaiseChanged(FileItemAction.ChildrenRemoved, oldChildren, 0); - return oldChildren; - } - return children;//EmptyChildren; - } - - /// Clears the list of files and returns the files that were cleared. - private List ClearAndGetFiles() { - int count = children.Count; - if (count > 0) { - List oldChildren = new List(); - for (int i = 0; i < children.Count; i++) { - FileItemBase child = children[i]; - if (child.Type == FileItemType.File) { - children[i].Parent = null; - oldChildren.Add(child); - children.RemoveAt(i); - i--; - } - } - if (IsWatched) - RaiseChanged(FileItemAction.ChildrenRemoved, oldChildren, -1); - return oldChildren; - } - return children;//EmptyChildren; - } - - /// Ensures the children are setup so that they can be locked. - protected void EnsureChildren() { - if (IsEmpty) - children = new List(4); - } - - /// Ensures the children are setup so that they can be locked. - /// - /// The capacity of the new list. - protected void EnsureChildren(int capacity) { - if (IsEmpty) - children = new List(capacity); - } - - /// - /// Ensures the children are assigned to if nothing is - /// contained in them. - /// - protected void EnsureEmptyChildren() { - if (!IsEmpty) { - lock (children) { - if (children.Count == 0) - children = EmptyChildren; - } - } - } - - #endregion - - #region Validation - - /// - /// Marks the folder as . Which means all subitems have been - /// scanned. - /// - public void Finish() { - IsDone = true; - if (IsWatched) - RaiseChanged(FileItemAction.Done); - } - - /// Fully validates the file item tree from this folder and above. - public void UpdwardsFullValidate() { - // Something to validate - if (!IsEmpty) { - ValidateImpl(true); - lock (children) { - children.Sort(); - children.Minimize(); - } - } - Parent?.FullValidateImpl(); - } - - /// - /// Upwards invalidates this folder and every ancestor and marks it as needing validation in the - /// future. - /// - protected void Invalidate() { - if (!IsInvalidated) { - // This is automatically set inside the same lock when IsInvalidated is set to true - //IsDone = false; - IsInvalidated = true; - if (IsWatched) - RaiseChanged(FileItemAction.Invalidated); - Parent?.Invalidate(); - } - } - - /// - /// Validates the container and all invalidated children. - /// For use when scanning is still underway, but the UI wants to be updated. - /// - private protected bool ValidateImpl(bool force) { - if (!IsInvalidated || (IsValidating && !force)) - return false; - while (IsValidating) - Thread.Sleep(1); - - // This is automatically set inside the same lock when IsValidating is set to true - //IsInvalidated = false; - IsValidating = true; - - if (IsEmpty) { - // If we're validating and empty, it means something was removed - Size = 0; - if (IsFileType) { - DirectoryInfo directoryInfo = new DirectoryInfo(FullName); - // Use the directory's LastWriteTime when empty - LastWriteTimeUtc = directoryInfo.LastWriteTimeUtc; - } - else { - LastWriteTimeUtc = DateTime.MinValue; - } - if (IsWatched) - RaiseChanged(FileItemAction.ValidatedSortOrder); - IsValidating = false; - return true; - } - - // True, if any of the sort orders that can change, have changed - bool sortOrderChanged = false; - long oldSize = Size; - DateTime oldLastChangeTime = LastWriteTimeUtc; - bool thisIsDone = IsDone; - bool isDone = true; - - lock (children) { - UnknownItem unknown = null; - FileItemBase freeSpace = null; - FileCount = 0; - SubdirCount = 0; - Size = 0; - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - if (child.Type == FileItemType.Unknown) { - // Don't count the size for this because it will - // be updated based on the remaining size. - unknown = (UnknownItem) child; - continue; - } - else if (child.Type == FileItemType.FreeSpace) { - // Don't count the size for this because it will - // be excluded when updating unknown's size. - freeSpace = child; - continue; - } - if (child is FolderItem childFolder) { - sortOrderChanged |= childFolder.ValidateImpl(force); - if (!thisIsDone && isDone) - isDone = childFolder.IsDone; - } - Size += child.Size; - //LastAccessTime = Max(LastAccessTime, child.LastAccessTime); - LastWriteTimeUtc = MaxDateTime(LastWriteTimeUtc, child.LastWriteTimeUtc); - if (child.Type == FileItemType.File || child.Type == FileItemType.FreeSpace) { - FileCount++; - } - else { - FileCount += child.FileCount; - SubdirCount += child.SubdirCount; - if (child.Type != FileItemType.FileCollection) { - SubdirCount++; - } - } - } - if (unknown != null) { - unknown.UpdateSize(Size); - Size += unknown.Size; - } - if (freeSpace != null) { - Size += freeSpace.Size; - } - sortOrderChanged |= (oldSize != Size); - - if (!thisIsDone && isDone) - Finish(); - } - - IsValidating = false; - if (IsWatched) { - if (sortOrderChanged) - RaiseChanged(FileItemAction.ValidatedSortOrder); - else - RaiseChanged(FileItemAction.Validated); - } - return sortOrderChanged || (oldLastChangeTime != LastWriteTimeUtc); - } - - /// Fully validates the file item tree and prepares it for use. - private protected void FullValidateImpl() { - // Nothing to validate - if (IsEmpty) - return; - - lock (children) { - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - if (child is FolderItem folder) - folder.FullValidateImpl(); - } - children.Sort(); - children.Minimize(); - } - } - - /// Gets the maximum of two s. - private static DateTime MaxDateTime(DateTime a, DateTime b) { - return (a > b ? a : b); - } - - #endregion - - #region ToString/DebuggerDisplay - - /// Gets the string representation of this item. - public override string ToString() { - if (Type == FileItemType.FileCollection) - return $"{Type}[{children.Count:N0}]"; - return $"{Type}[{children.Count:N0}]: {Name}"; - } - - /// Gets the string used to represent the file in the debugger. - private string DebuggerDisplay { - get { - if (Type == FileItemType.FileCollection) - return $"[{children.Count:N0}]: "; - return $"[{children.Count:N0}]: {Name}"; - } - } - - #endregion - - #region Override Methods - - /// Refreshes the file. Returns true if it still exists. - /// - /// True if the file still exists. - public override bool Refresh() { - DirectoryInfo info = new DirectoryInfo(FullName); - // Remove all of our children first, they will be repopulated - ClearItems(); - if (info.Exists && info.Attributes.HasFlag(FileAttributes.Directory)) { - //CaseSensitive = DirectoryCaseSensitivity.IsCaseSensitive(info.FullName); - Attributes = info.Attributes; - Size = 0L; - LastWriteTimeUtc = info.LastWriteTimeUtc; - - return RefreshFinal(true); - } - return RefreshFinal(false); - } - - /// Checks if the file still exists. - /// - /// True if the file exists. - public override bool CheckExists() { - if (Type == FileItemType.FileCollection) - return true; - - if (Directory.Exists(FullName)) { - return CheckExistsFinal(true); - } - RecurseClearChildren(); - return CheckExistsFinal(false); - } - - #endregion - - #region Static Helpers - - /// - /// Removes all files in the enumeration whose ancestors are also in the enumeration. - /// - /// - /// The enumeration with ancestor conflicts removed. - public static FileItemBase[] IsolateAncestores(IEnumerable files) { - // TODO: This can probably be optimized more - List fileList = files.ToList(); - for (int i = 0; i < fileList.Count; i++) { - FileItemBase file = fileList[i]; - bool hasAncestor = false; - FolderItem ancestor = file.FileParent; - while (ancestor != null && !hasAncestor) { - for (int j = 0; j < fileList.Count; j++) { - if (ancestor == fileList[j]) { - hasAncestor = true; - fileList.RemoveAt(i); - i--; - break; - } - } - ancestor = ancestor.FileParent; - } - } - return fileList.ToArray(); - } - - /*/// Gets if the file contains the specified ancestor. - /// - /// The file to check the ancestors of. - /// The ancestor to check with. - public bool ContainsAncestor(FileItemBase file, FolderItem ancestor) { - - }*/ - - /// Gets the ancestores for the file from bottom to top. - /// - /// The file to get the ancestores of. - /// The ancestors of the file. - public static IEnumerable GetAncestores(FileItemBase file) { - FolderItem parent = file.Parent; - while (parent != null) { - yield return parent; - parent = parent.Parent; - } - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Model/Files/FreeSpaceItem.cs b/WinDirStat.Net.Base/Model/Files/FreeSpaceItem.cs deleted file mode 100644 index e6953e9..0000000 --- a/WinDirStat.Net.Base/Model/Files/FreeSpaceItem.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Model.Files { - /// The file tree item that displays the amount of unused space in the drive. - [Serializable] - [DebuggerDisplay("{DebuggerDisplay,nq}")] - public sealed class FreeSpaceItem : FileItemBase { - - #region Fields - - /// The containing this space. - private readonly RootItem rootParent; - - #endregion - - #region Constructors - - /// Constructs the . - /// - /// The containing this space. - internal FreeSpaceItem(RootItem rootParent) - : base(StringConstants.FreeSpaceName, FileItemType.FreeSpace, FileItemFlags.None) - { - this.rootParent = rootParent; - LastWriteTimeUtc = DateTime.MinValue; - UpdateSize(); - } - - #endregion - - #region Helper Properties - - /// Gets the root path of . - private string VolumePath => rootParent.RootPath; - - #endregion - - #region Updating - - /// Updates the size of the free space. - internal void UpdateSize() { - if (rootParent.Type == FileItemType.Computer) { - Size = 0; - List children = rootParent.Children; - lock (children) { - int count = children.Count; - for (int i = 0; i < count; i++) { - if (children[i] is RootItem root && root.FreeSpace != null) { - root.FreeSpace.UpdateSize(); - Size += root.FreeSpace.Size; - } - } - } - } - else if (rootParent.Type == FileItemType.Volume) { - try { - DriveInfo driveInfo = new DriveInfo(VolumePath); - Size = driveInfo.TotalFreeSpace; - } - catch { - Size = 0; - } - } - } - - #endregion - - #region ToString/DebuggerDisplay - - /// Gets the string representation of this item. - public override string ToString() => ""; - - /// Gets the string used to represent the file in the debugger. - private string DebuggerDisplay => ""; - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Model/Files/Misc/FileItemEnums.cs b/WinDirStat.Net.Base/Model/Files/Misc/FileItemEnums.cs deleted file mode 100644 index 44afbf7..0000000 --- a/WinDirStat.Net.Base/Model/Files/Misc/FileItemEnums.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System; -using System.ComponentModel; -using System.IO; - -namespace WinDirStat.Net.Model.Files { - /// The different types of file tree items. - [Serializable] - public enum FileItemType : byte { - /// This item is the computer that stores all scanned volumes. - Computer = 0, - /// This item is a volume that contains the entire file tree. - Volume = 1, - /// - /// This item is a directory that stores its files and subdirs. It can also be a root type. - /// - Directory = 2, - /// This item is a normal file and is treated as a treemap leaf. - File = 3, - /// - /// This item is a container for files when a folder is storing files and folders. - /// See 's remarks for how files and folders are separated. - /// - FileCollection = 4, - /// This item is the free space for a root. This may optionally be hidden. - FreeSpace = 5, - /// This item is the unidentified space for a root. This may optionally be hidden. - Unknown = 6, - } - - /// The modifiable states of a file tree item. - [Serializable] - [Flags] - internal enum FileItemStates : byte { - /// No states are set. - None = 0, - - /// The container is done scanning all subdirs. - Done = (1 << 0), - /// - /// The container is invalidated and needs to have its size and other members validated when needed. - /// - Invalidated = (1 << 1), - /// - /// The container is in the process of validating, this prevents more than one validation operation - /// from occurring at the same time. - /// - Validating = (1 << 2), - /// The file still exists in the system. - Exists = (1 << 3), - } - - /// The constant flags of a file tree item. - [Serializable] - [Flags] - internal enum FileItemFlags : ushort { - /// No flags are set. - None = 0, - - // Sortable FileAttributes (Bit order is important here) - /// This file has the attribute. - Encrypted = (1 << 0), - /// This file has the attribute. - Compressed = (1 << 1), - /// This file has the attribute. - Archive = (1 << 2), - /// This file has the attribute. - System = (1 << 3), - /// This file has the attribute. - Hidden = (1 << 4), - /// This file has the attribute. - ReadOnly = (1 << 5), - - // Other FileAttributes - /// This file has the attribute. - ReparsePoint = (1 << 6), - /// This file has the attribute. - Temporary = (1 << 7), - - // Type Flags - /// The directory is case-sensitive. - CaseSensitive = (1 << 11), - /// The item can contain children. - ContainerType = (1 << 12), - /// The item is a real file, directory, or volume. - FileType = (1 << 13), - /// The item is a root and a volume or directory. - FileRootType = (1 << 14), - /// - /// The item is the top level root. This can be set at the same time as . - /// - AbsoluteRootType = (1 << 15), - - /// The mask for all type flags. - [Browsable(false)] - TypeFlagsMask = 0xF800, - /// The mask for all used in sorting. - [Browsable(false)] - SortAttributesMask = 0x003F, - /// The mask for all . - [Browsable(false)] - AttributesMask = 0x00FF, - } - - /// - /// Extensions for settings individual flags in and . - /// - internal static class FileItemFlagsExtensions { - /// Enables or disables the specified flag. - /// - /// The flags to modify - /// The flag(s) to set. - /// True if the flags should be set - /// The modified flags. - public static FileItemStates SetFlag(this FileItemStates flags, FileItemStates flag, bool value) { - if (value) - return flags | flag; - else - return flags & ~flag; - } - - /// Enables or disables the specified flag. - /// - /// The flags to modify - /// The flag(s) to set. - /// True if the flags should be set - /// The modified flags. - public static FileItemFlags SetFlag(this FileItemFlags flags, FileItemFlags flag, bool value) { - if (value) - return flags | flag; - else - return flags & ~flag; - } - } -} diff --git a/WinDirStat.Net.Base/Model/Files/Misc/FileItemEvent.cs b/WinDirStat.Net.Base/Model/Files/Misc/FileItemEvent.cs deleted file mode 100644 index 128f61a..0000000 --- a/WinDirStat.Net.Base/Model/Files/Misc/FileItemEvent.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Model.Files { - /// The event action type for . - public enum FileItemAction { - - // State - /// The node state has been marked is invalidated. - Invalidated, - /// The node state has been validated to reflect its children. - Validated, - /// Properties that require a visual resort have changed during validation. - ValidatedSortOrder, - /// The node and all children have been fully scanned. - Done, - /// The file's existance state has changed. - Exists, - /// The node was refreshed, and non-standard sort properties may have changed. - /// Exists may also have been changed when this action is received. - Refreshed, - - // Children - /// Children have been added to the node. - ChildrenAdded, - /// Children have been removed from the node. - ChildrenRemoved, - /// Children have been cleared. - ChildrenCleared, - - // Accessors - /// Requests the view model watching this node to show itself. - GetViewModel, - } - - /// The event arguments for . - public class FileItemEventArgs { - /// The action to notify the view model of. - public FileItemAction Action { get; } - /// The children that were introduced or removed. - public List Children { get; } - /// The index of the introduced children. - public int Index { get; } - /// - /// The view model if is . - /// - public object ViewModel { get; set; } - - /// Constructs the that just require an action. - public FileItemEventArgs(FileItemAction action) : this(action, -1) { - } - - /// - /// Constructs the that require an action and index. - /// - public FileItemEventArgs(FileItemAction action, int index) { - Action = action; - Index = index; - } - - /// - /// Constructs the that represent changes to children. - /// - public FileItemEventArgs(FileItemAction action, List children, int index = -1) - : this(action, index) - { - Children = children; - } - - /// - /// Constructs the that represent changes to children. - /// - public FileItemEventArgs(FileItemAction action, IEnumerable children, int index = -1) - : this(action, index) - { - Children = children.ToList(); - } - - /// - /// Constructs the that represent changes to a child. - /// - public FileItemEventArgs(FileItemAction action, FileItemBase child, int index = -1) - : this(action, index) - { - Children = new List { child }; - } - } - - /// The event handler for . - /// - /// The that sent this changed event. - /// The for this changed event. - public delegate void FileItemEventHandler(FileItemBase sender, FileItemEventArgs e); -} diff --git a/WinDirStat.Net.Base/Model/Files/Misc/IScanFileInfo.cs b/WinDirStat.Net.Base/Model/Files/Misc/IScanFileInfo.cs deleted file mode 100644 index 89c6c88..0000000 --- a/WinDirStat.Net.Base/Model/Files/Misc/IScanFileInfo.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Model.Files { - /// An interface revealing information needed to construct file tree items. - public interface IScanFileInfo { - - #region FileInfo Properties - - /// Gets the name of the file. - string Name { get; } - /// Gets the full path of the file. - string FullName { get; } - /// Gets the size of the file. - long Size { get; } -#if WINDOWS - /// Gets the attributes of the file. - FileAttributes Attributes { get; } -#endif - /// Gets the UTC creation time of the file. - DateTime CreationTimeUtc { get; } - /// Gets the UTC last access time of the file. - DateTime LastAccessTimeUtc { get; } - /// Gets the UTC last write time of the file. - DateTime LastWriteTimeUtc { get; } - - #endregion - - #region Helpers Properties - - /// Gets if the file is a directory. - bool IsDirectory { get; } - /// Gets if the file is a symbolic link. - bool IsSymbolicLink { get; } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Model/Files/RootItem.cs b/WinDirStat.Net.Base/Model/Files/RootItem.cs deleted file mode 100644 index 36b5dc9..0000000 --- a/WinDirStat.Net.Base/Model/Files/RootItem.cs +++ /dev/null @@ -1,230 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services; -using WinDirStat.Net.Utils; - -namespace WinDirStat.Net.Model.Files { - /// - /// A root file tree item that is either the absolute root, a file root (volume/folder), or both. - /// If this root is not a file root, it's children must all be s. - /// - [Serializable] - public class RootItem : FolderItem, IDisposable { - - #region Fields - - /// Gets the service used for scanning the file tree. - private readonly ScanningService scanning; - - /// Gets the root path of the container. This includes the name of the item. - public string RootPath { get; private set; } - /// Gets the free space item associated with this root. - public FreeSpaceItem FreeSpace { get; private set; } - /// Gets the unknown space item associated with this root. - public UnknownItem Unknown { get; private set; } - /// The cached total size of the drive. - public long CachedTotalSize { get; private set; } - /// The cached free space of the drive. - public long CachedFreeSpace { get; private set; } - - #endregion - - #region Constructors - - /// Constructs the as a Computer. - /// - /// The service used for scanning the file tree. - public RootItem(ScanningService scanning) - : base(StringConstants.ComputerName, FileItemType.Computer, - FileItemFlags.ContainerType | FileItemFlags.AbsoluteRootType) - { - this.scanning = scanning; - scanning.SpaceChanged += UpdateSpace; - SetupRoot(); - } - - /// Constructs the with a . - /// - /// The service used for scanning the file tree. - /// The file information. - /// True if there is no containing this. - public RootItem(ScanningService scanning, DirectoryInfo info, bool isAbsoluteRoot) - : base(info, GetType(info.FullName), GetFlags(isAbsoluteRoot)) - { - this.scanning = scanning; - if (isAbsoluteRoot) - scanning.SpaceChanged += UpdateSpace; - RootPath = Path.GetFullPath(info.FullName); - if (Type == FileItemType.Volume) - RootPath = PathUtils.AddDirectorySeparator(RootPath); - SetupRoot(); - } - - private void SetupRoot() { - if (Type == FileItemType.Volume || Type == FileItemType.Computer) { - FreeSpace = new FreeSpaceItem(this); - Unknown = new UnknownItem(this); - if (scanning.ShowFreeSpace) - Add(FreeSpace); - if (scanning.ShowUnknown) - Add(Unknown); - if (Type == FileItemType.Volume) { - DriveInfo driveInfo = new DriveInfo(RootPath); - CachedTotalSize = driveInfo.TotalSize; - CachedFreeSpace = driveInfo.TotalFreeSpace; - } - } - } - - private static FileItemType GetType(string path) { - return (PathUtils.IsPathRoot(path) ? FileItemType.Volume : FileItemType.Directory); - } - - private static FileItemFlags GetFlags(bool isAbsoluteRoot) { - return (isAbsoluteRoot ? FileItemFlags.AbsoluteRootType : FileItemFlags.None) | - FileItemFlags.FileRootType | FileItemFlags.FileType | FileItemFlags.ContainerType; - } - - #endregion - - #region Validation - - /// - /// Validates the file tree and all invalidated children. - /// For use when scanning is still underway, but the UI wants to be updated. - /// - public void BasicValidate() { - ValidateImpl(false); - } - - /// Fully validates the file item tree and prepares it for use. - public void FullValidate() { - ValidateImpl(true); - FullValidateImpl(); - } - - /// Validates changes to the roots only. For use when space display has been changed. - private void RootValidate() { - ValidateImpl(true); - if (IsEmpty) - return; - - lock (children) { - if (Type == FileItemType.Computer) { - int count = children.Count; - for (int i = 0; i < count; i++) { - if (children[i] is RootItem root) - root.RootValidate(); - } - } - children.Sort(); - children.Minimize(); - } - } - - #endregion - - public long GetUsedSize() { - long usedSize = 0; - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - if (child.Type != FileItemType.FreeSpace && child.Type != FileItemType.Unknown) - usedSize += child.Size; - } - return usedSize; - } - - private void UpdateSpace(object sender, EventArgs e) { - if (IsEmpty) - return; - - if (Type == FileItemType.Computer) { - int count = children.Count; - for (int i = 0; i < count; i++) { - if (children[i] is RootItem root) - root.UpdateSpace(sender, e); - } - } - - // ShowTotalSpace means only the absolute root will show space - // !ShowTotalSpace means only the file root will show space - // We do this check because absolute roots can also be file roots - bool baseShow = (IsAbsoluteRootType && scanning.ShowTotalSpace) || - (IsFileRootType && !scanning.ShowTotalSpace); - - // Create some children so we can lock things down - EnsureChildren(2); - - lock (children) { - AddOrRemove(FreeSpace, scanning.ShowFreeSpace && baseShow); - AddOrRemove(Unknown, scanning.ShowUnknown && baseShow); - - // If nothing was added or removed and children was created, - // children was never set back to empty. - EnsureEmptyChildren(); - - Invalidate(); - } - - if (IsAbsoluteRootType) - RootValidate(); - } - - #region Override Methods - - /// Refreshes the item. Returns true if it still exists. - /// - /// True if the file still exists. - /*public override bool Refresh() { - DirectoryInfo info = new DirectoryInfo(FullName); - if (info.Exists && !info.Attributes.HasFlag(FileAttributes.Directory)) { - Attributes = info.Attributes; - - long oldSize = Size; - if (!info.Attributes.HasFlag(FileAttributes.ReparsePoint)) - Size = info.Length; - else - Size = 0L; - ExtensionItem.RefreshFile(Size, oldSize); - - LastWriteTimeUtc = info.LastWriteTimeUtc; - - return true; - } - ExtensionItem.RemoveFile(Size); - return false; - - }*/ - - /// Checks if it still exists. - /// - /// True if the file exists. - public override sealed bool CheckExists() { - if (Type == FileItemType.Computer) - return true; - - if (Directory.Exists(FullName)) { - return (Exists = true); - } - RecurseClearChildren(); - return (Exists = false); - } - - #endregion - - #region IDisposable Implementation - - /// Disposes of the root node's hooked events. - public void Dispose() { - if (IsAbsoluteRootType) - scanning.SpaceChanged -= UpdateSpace; - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Model/Files/UnknownItem.cs b/WinDirStat.Net.Base/Model/Files/UnknownItem.cs deleted file mode 100644 index 7c97e60..0000000 --- a/WinDirStat.Net.Base/Model/Files/UnknownItem.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Model.Files { - /// The file tree item that displays the amount of unidentified space in the drive. - [Serializable] - [DebuggerDisplay("{DebuggerDisplay,nq}")] - public sealed class UnknownItem : FileItemBase { - - #region Fields - - /// The containing this space. - private readonly RootItem rootParent; - - #endregion - - #region Constructors - - /// Constructs the . - /// - /// The containing this space. - internal UnknownItem(RootItem rootParent) - : base(StringConstants.UnknownName, FileItemType.Unknown, FileItemFlags.None) - { - this.rootParent = rootParent; - LastWriteTimeUtc = DateTime.MinValue; - UpdateSize(0); - } - - #endregion - - #region Helper Properties - - /// Gets the root path of . - private string VolumePath => rootParent.RootPath; - - #endregion - - #region Updating - - /// - /// Updates the size of the unknown space based on the amount of used space. - /// - /// The space of the root item excluding free and unknown space. - internal void UpdateSize(long usedSpace) { - if (rootParent.Type == FileItemType.Computer) { - Size = 0; - List children = rootParent.Children; - lock (children) { - int count = children.Count; - for (int i = 0; i < count; i++) { - if (children[i] is RootItem root && root.Unknown != null) { - root.Unknown.UpdateSize(root.GetUsedSize()); - Size += root.Unknown.Size; - } - } - } - } - else if (rootParent.Type == FileItemType.Volume) { - try { - DriveInfo driveInfo = new DriveInfo(VolumePath); - Size = driveInfo.TotalSize - driveInfo.TotalFreeSpace - usedSpace; - // In the rare case that our used space is larger than the actual used space - if (Size < 0) - Size = 0; - } - catch { - Size = 0; - } - } - } - - #endregion - - #region ToString/DebuggerDisplay - - /// Gets the string representation of this item. - public override string ToString() => ""; - - /// Gets the string used to represent the file in the debugger. - private string DebuggerDisplay => ""; - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ObservableCollectionObject.cs b/WinDirStat.Net.Base/ObservableCollectionObject.cs deleted file mode 100644 index 636b1ed..0000000 --- a/WinDirStat.Net.Base/ObservableCollectionObject.cs +++ /dev/null @@ -1,230 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; - -namespace WinDirStat.Net { - /// A base class for objects of which the collection must be observable. - public abstract class ObservableCollectionObject : INotifyCollectionChanged { - - #region Fields - - /// True if the collection is raising a event. - protected bool IsRaisingEvent { get; set; } - - #endregion - - #region Events - - /// Occurs after the collection's items change. - public event NotifyCollectionChangedEventHandler CollectionChanged; - - #endregion - - #region RaiseCollectionChanged (EventArgs) - - /// Invokes the event. - /// - /// The arguments for the event. - protected void InvokeCollectionChanged(NotifyCollectionChangedEventArgs e) { - CollectionChanged?.Invoke(this, e); - } - - /// Raises a new event. - /// - /// The arguments for the event. - protected virtual void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e) { - //Debug.Assert(!isRaisingEvent); - ThrowOnReentrancy(); - IsRaisingEvent = true; - try { - CollectionChanged?.Invoke(this, e); - } - finally { - IsRaisingEvent = false; - } - } - - #endregion - - #region RaiseCollectionChanged (Reset) - - /// - /// Raises a new event that describes a change. - /// - /// - /// The action that caused the event (must be Reset). - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action) { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action)); - } - - #endregion - - #region RaiseCollectionChanged (Change) - - /// - /// Raises a new event that describes a one-item change. - /// - /// - /// - /// The action that caused the event; can only be Reset, Add or Remove action. - /// - /// The item affected by the change. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, object changedItem) { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItem)); - } - - /// - /// Raises a new event that describes a one-item change. - /// - /// - /// The action that caused the event. - /// The item affected by the change. - /// The index where the change occurred. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, object changedItem, - int index) { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItem, index)); - } - - /// - /// Raises a new event that describes a multi-item change. - /// - /// - /// The action that caused the event. - /// The items affected by the change. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, IList changedItems) { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItems)); - } - - /// - /// Raises a new event that describes a multi-item change. - /// - /// - /// The action that caused the event. - /// The items affected by the change. - /// The index where the change occurred. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, IList changedItems, - int startingIndex) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItems, startingIndex)); - } - - #endregion - - #region RaiseCollectionChanged (Replace) - - /// - /// Raises a new event that describes a one-item Replace event. - /// - /// - /// Can only be a Replace action. - /// The new item replacing the original item. - /// The original item that is replaced. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, object newItem, - object oldItem) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem)); - } - - /// - /// Raises a new event that describes a one-item Replace event. - /// - /// - /// Can only be a Replace action. - /// The new item replacing the original item. - /// The original item that is replaced. - /// The index of the item being replaced. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, object newItem, - object oldItem, int index) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index)); - } - - /// - /// Raises a new event that describes a multi-item Replace event. - /// - /// - /// Can only be a Replace action. - /// The new items replacing the original items. - /// The original items that are replaced. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, IList newItems, - IList oldItems) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItems, oldItems)); - } - - /// - /// Raises a new event that describes a multi-item Replace event. - /// - /// - /// Can only be a Replace action. - /// The new items replacing the original items. - /// The original items that are replaced. - /// The starting index of the items being replaced. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, IList newItems, - IList oldItems, int index) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItems, oldItems, index)); - } - - #endregion - - #region RaiseCollectionChanged (Move) - - /// - /// Raises a new event that describes a one-item Move event. - /// - /// - /// Can only be a Move action. - /// The item affected by the change. - /// The new index for the changed item. - /// The old index for the changed item. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, object changedItem, - int index, int oldIndex) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItem, index, oldIndex)); - } - - /// - /// Raises a new event that describes a multi-item Move event. - /// - /// - /// Can only be a Replace action. - /// The new items replacing the original items. - /// The original items that are replaced. - /// The starting index of the items being replaced. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, IList changedItems, - int index, int oldIndex) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItems, index, oldIndex)); - } - - #endregion - - #region ThrowOnReentrancy - - /// - /// Throws an exception if the user is attempting to modify the list during a event. - /// - /// - /// - /// The user is attempting to modify the list during a event. - /// - protected void ThrowOnReentrancy() { - if (IsRaisingEvent) - throw new InvalidOperationException($"Collection cannot be modified during a " + - $"{nameof(CollectionChanged)} event!"); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ObservableObjectEx.cs b/WinDirStat.Net.Base/ObservableObjectEx.cs deleted file mode 100644 index e25ddb3..0000000 --- a/WinDirStat.Net.Base/ObservableObjectEx.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; - -namespace WinDirStat.Net { - /// An observable object with extra raise property changed methods. - public class ObservableObjectEx : ObservableObject { - - /// Raises the property as changed if the condition is true. - /// - /// The condition for raising the changed event. - /// The name of the property. - /// True if the property was changed. - protected bool RaisePropertyChangedIf(bool condition, [CallerMemberName] string propertyName = null) { - RaisePropertyChanged(propertyName); - return condition; - } - } -} diff --git a/WinDirStat.Net.Base/ObservablePropertyCollectionObject.cs b/WinDirStat.Net.Base/ObservablePropertyCollectionObject.cs deleted file mode 100644 index 645f28a..0000000 --- a/WinDirStat.Net.Base/ObservablePropertyCollectionObject.cs +++ /dev/null @@ -1,223 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; - -namespace WinDirStat.Net { - /// A base class for objects of which the collection must be observable. - public abstract class ObservablePropertyCollectionObject : ObservableObject, INotifyCollectionChanged { - - #region Fields - - /// True if the collection is raising a event. - protected bool IsRaisingEvent { get; set; } - - #endregion - - #region Events - - /// Occurs after the collection's items change. - public event NotifyCollectionChangedEventHandler CollectionChanged; - - #endregion - - #region RaiseCollectionChanged (EventArgs) - - /// Raises a new event. - /// - /// The arguments for the event. - protected void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e) { - //Debug.Assert(!isRaisingEvent); - ThrowOnReentrancy(); - IsRaisingEvent = true; - try { - CollectionChanged?.Invoke(this, e); - } - finally { - IsRaisingEvent = false; - } - } - - #endregion - - #region RaiseCollectionChanged (Reset) - - /// - /// Raises a new event that describes a change. - /// - /// - /// The action that caused the event (must be Reset). - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action) { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action)); - } - - #endregion - - #region RaiseCollectionChanged (Change) - - /// - /// Raises a new event that describes a one-item change. - /// - /// - /// - /// The action that caused the event; can only be Reset, Add or Remove action. - /// - /// The item affected by the change. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, object changedItem) { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItem)); - } - - /// - /// Raises a new event that describes a one-item change. - /// - /// - /// The action that caused the event. - /// The item affected by the change. - /// The index where the change occurred. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, object changedItem, - int index) { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItem, index)); - } - - /// - /// Raises a new event that describes a multi-item change. - /// - /// - /// The action that caused the event. - /// The items affected by the change. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, IList changedItems) { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItems)); - } - - /// - /// Raises a new event that describes a multi-item change. - /// - /// - /// The action that caused the event. - /// The items affected by the change. - /// The index where the change occurred. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, IList changedItems, - int startingIndex) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItems, startingIndex)); - } - - #endregion - - #region RaiseCollectionChanged (Replace) - - /// - /// Raises a new event that describes a one-item Replace event. - /// - /// - /// Can only be a Replace action. - /// The new item replacing the original item. - /// The original item that is replaced. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, object newItem, - object oldItem) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem)); - } - - /// - /// Raises a new event that describes a one-item Replace event. - /// - /// - /// Can only be a Replace action. - /// The new item replacing the original item. - /// The original item that is replaced. - /// The index of the item being replaced. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, object newItem, - object oldItem, int index) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index)); - } - - /// - /// Raises a new event that describes a multi-item Replace event. - /// - /// - /// Can only be a Replace action. - /// The new items replacing the original items. - /// The original items that are replaced. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, IList newItems, - IList oldItems) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItems, oldItems)); - } - - /// - /// Raises a new event that describes a multi-item Replace event. - /// - /// - /// Can only be a Replace action. - /// The new items replacing the original items. - /// The original items that are replaced. - /// The starting index of the items being replaced. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, IList newItems, - IList oldItems, int index) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItems, oldItems, index)); - } - - #endregion - - #region RaiseCollectionChanged (Move) - - /// - /// Raises a new event that describes a one-item Move event. - /// - /// - /// Can only be a Move action. - /// The item affected by the change. - /// The new index for the changed item. - /// The old index for the changed item. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, object changedItem, - int index, int oldIndex) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItem, index, oldIndex)); - } - - /// - /// Raises a new event that describes a multi-item Move event. - /// - /// - /// Can only be a Replace action. - /// The new items replacing the original items. - /// The original items that are replaced. - /// The starting index of the items being replaced. - protected void RaiseCollectionChanged(NotifyCollectionChangedAction action, IList changedItems, - int index, int oldIndex) - { - RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(action, changedItems, index, oldIndex)); - } - - #endregion - - #region ThrowOnReentrancy - - /// - /// Throws an exception if the user is attempting to modify the list during a event. - /// - /// - /// - /// The user is attempting to modify the list during a event. - /// - protected void ThrowOnReentrancy() { - if (IsRaisingEvent) - throw new InvalidOperationException($"Collection cannot be modified during a " + - $"{nameof(CollectionChanged)} event!"); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ObservableVolatileObject.cs b/WinDirStat.Net.Base/ObservableVolatileObject.cs deleted file mode 100644 index a858af5..0000000 --- a/WinDirStat.Net.Base/ObservableVolatileObject.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net { - /// An observable object with volatile get and set. - public class ObservableVolatileObject : ObservableObjectEx { - - /// The lock for volatile properties. - protected readonly object volatileLock = new object(); - - /// Gets the property and ensures its under lock while accessing it. - /// - /// The type of the property. - /// The field to access. - /// The locked value of the field. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected T VolatileGet(ref T field) { - lock (volatileLock) - return field; - } - - /// Sets the property and ensures the property is not changed during the process. - /// - /// The type of the property. - /// The field of the property. - /// The new value of the property. - /// The name of the property. - /// True if the property was changed. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected bool VolatileSet(ref T field, T newValue, [CallerMemberName] string propertyName = null) { - lock (volatileLock) { - if (EqualityComparer.Default.Equals(field, newValue)) - return false; - field = newValue; - } - RaisePropertyChanged(propertyName); - return true; - } - - } -} diff --git a/WinDirStat.Net.Base/Rendering/BetterTreemapOptions.cs b/WinDirStat.Net.Base/Rendering/BetterTreemapOptions.cs deleted file mode 100644 index fd370c6..0000000 --- a/WinDirStat.Net.Base/Rendering/BetterTreemapOptions.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using WinDirStat.Net.Structures; -using WinDirStat.Net.Utils; - -#if DOUBLE -using Number = System.Double; -using Point2N = WinDirStat.Net.Structures.Point2D; -#else -using Number = System.Single; -using Point2N = WinDirStat.Net.Structures.Point2F; -#endif - -namespace WinDirStat.Net.Rendering { - /// A structure containing treemap rendering options. - [Serializable] - public struct BetterTreemapOptions { - - /// Squarification method - private TreemapStyle style; - /// 0..1.0 (default = 0.84) - private Number brightness; - /// 0..oo (default = 0.40) Factor "H" - private Number height; - /// 0..1.0 (default = 0.90) Factor "F" - private Number scaleFactor; - /// 0..1.0 (default = 0.15) Factor "Ia" - private Number ambientLight; - /// (-4.0,-4.0)..(+4.0,+4.0) (default = (-1.0,-1.0), negative = top-left - private Point2N lightSource; - - /// Squarification method - public TreemapStyle Style { - get => style; - set { - if (!Enum.IsDefined(typeof(TreemapStyle), value)) - throw new ArgumentException(nameof(Style)); - style = value; - } - } - /// Whether or not to draw grid lines - public bool Grid { get; set; } - /// Color of grid lines - public Rgb24Color GridColor { get; set; } - - /// 0..1.0 (default = 0.84) - public Number Brightness { - get => brightness; - set => brightness = MathUtils.Clamp(value, 0, 1); - } - /// 0..oo (default = 0.40) Factor "H" - public Number Height { - get => height; - set => height = Math.Max(value, 0); - } - /// 0..1.0 (default = 0.90) Factor "F" - public Number ScaleFactor { - get => scaleFactor; - set => scaleFactor = MathUtils.Clamp(value, 0, 1); - } - /// 0..1.0 (default = 0.15) Factor "Ia" - public Number AmbientLight { - get => ambientLight; - set => ambientLight = MathUtils.Clamp(value, 0, 1); - } - - /// (-4.0,-4.0)..(+4.0,+4.0) (default = (-1.0,-1.0), negative = top-left - public Point2N LightSource { - get => lightSource; - set { - LightSourceX = value.X; - LightSourceY = value.Y; - } - } - /// -4.0..+4.0 (default = -1.0), negative = left - public Number LightSourceX { - get => lightSource.X; - set => lightSource.X = MathUtils.Clamp(value, -4, 4); - } - /// -4.0..+4.0 (default = -1.0), negative = top - public Number LightSourceY { - get => lightSource.Y; - set => lightSource.Y = MathUtils.Clamp(value, -4, 4); - } - } -} diff --git a/WinDirStat.Net.Base/Rendering/ColorSpace.cs b/WinDirStat.Net.Base/Rendering/ColorSpace.cs deleted file mode 100644 index fc6af43..0000000 --- a/WinDirStat.Net.Base/Rendering/ColorSpace.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Structures; - -#if DOUBLE -using Number = System.Double; -#else -using Number = System.Single; -#endif - -namespace WinDirStat.Net.Rendering { - public static class ColorSpace { - - public const Number PaletteBrightness = (Number) 0.6; - - public static float GetBrightness(Rgb24Color color) { - return (color.R + color.G + color.B) / (Number) 255 / 3; - } - - public static Number GetBrightness(Rgba32Color color) { - return (color.R + color.G + color.B) / (Number) 255 / 3; - } - - public static Rgb24Color SetBrightness(Rgb24Color color, float brightness) { - Debug.Assert(brightness >= 0); - Debug.Assert(brightness <= 1); - - Number redf = color.R / 255f; - Number greenf = color.G / 255f; - Number bluef = color.B / 255f; - - Number f = 3 * brightness / (redf + greenf + bluef); - - int red = (int) (redf * f * 255); - int green = (int) (greenf * f * 255); - int blue = (int) (bluef * f * 255); - - NormalizeColor(ref red, ref green, ref blue); - - return new Rgb24Color(red, green, blue); - } - - public static Rgba32Color SetBrightness(Rgba32Color color, float brightness) { - Debug.Assert(brightness >= 0); - Debug.Assert(brightness <= 1); - - Number redf = color.R / 255f; - Number greenf = color.G / 255f; - Number bluef = color.B / 255f; - - Number f = 3 * brightness / (redf + greenf + bluef); - - int red = (int) (redf * f * 255); - int green = (int) (greenf * f * 255); - int blue = (int) (bluef * f * 255); - - NormalizeColor(ref red, ref green, ref blue); - - return new Rgba32Color(red, green, blue, color.A); - } - - public static Rgba32Color[] EqualizeColors(IEnumerable colors) { - List result = new List(); - foreach (Rgba32Color color in colors) - result.Add(SetBrightness(color, PaletteBrightness)); - return result.ToArray(); - } - - public static Rgb24Color[] EqualizeColors(IEnumerable colors) { - List result = new List(); - foreach (Rgb24Color color in colors) - result.Add(SetBrightness(color, PaletteBrightness)); - return result.ToArray(); - } - - public static void NormalizeColor(ref int red, ref int green, ref int blue) { - Debug.Assert(red + green + blue <= 3 * 255); - - if (red > 255) { - DistributeFirst(ref red, ref green, ref blue); - } - else if (green > 255) { - DistributeFirst(ref green, ref red, ref blue); - } - else if (blue > 255) { - DistributeFirst(ref blue, ref red, ref green); - } - } - - private static void DistributeFirst(ref int first, ref int second, ref int third) { - int h = (first - 255) / 2; - first = 255; - second += h; - third += h; - - if (second > 255) { - h = second - 255; - second = 255; - third += h; - Debug.Assert(third <= 255); - } - else if (third > 255) { - h = third - 255; - third = 255; - second += h; - Debug.Assert(second <= 255); - } - } - } -} diff --git a/WinDirStat.Net.Base/Rendering/ITreemapItem.cs b/WinDirStat.Net.Base/Rendering/ITreemapItem.cs deleted file mode 100644 index cf51e0a..0000000 --- a/WinDirStat.Net.Base/Rendering/ITreemapItem.cs +++ /dev/null @@ -1,26 +0,0 @@ -using WinDirStat.Net.Structures; - -namespace WinDirStat.Net.Rendering { - /// An interface for items to use in treemap rendering. - public interface ITreemapItem { - /// Gets if this treemap item is a leaf that should be drawn. - bool IsLeaf { get; } - - /// Gets the color of this treemap item leaf.Gets or sets the rectangular bounds of the treemap item in the treemap. - Rectangle2I Rectangle { get; set; } - - /// - /// Gets the file size of the treemap item. - /// The size of all children combined must match this value. - /// - long Size { get; } - - /// Gets the number of children in this treemap item. - int ChildCount { get; } - /// Gets the child at the specified index in the treemap item. - ITreemapItem this[int index] { get; } - } -} diff --git a/WinDirStat.Net.Base/Rendering/PreviewTreemapItem.cs b/WinDirStat.Net.Base/Rendering/PreviewTreemapItem.cs deleted file mode 100644 index 2717519..0000000 --- a/WinDirStat.Net.Base/Rendering/PreviewTreemapItem.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using WinDirStat.Net.Services; -using WinDirStat.Net.Structures; - -namespace WinDirStat.Net.Rendering { - /// An treemap item for previewing purposes only. - public class PreviewTreemapItem : ITreemapItem { - - #region Static Fields - - /// Gets the default preview treemap. - public static PreviewTreemapItem DefaultTreemap { get; } = Build(SettingsService.DefaultFilePalette); - - #endregion - - #region Fields - - /// The list of children in the treemap item. - private readonly List children; - /// Gets the color of this treemap item leaf.Gets or sets the rectangular bounds of the treemap item in the treemap. - private Rectangle2S rectangle; - /// - /// Gets the file size of the treemap item. - /// The size of all children combined must match this value. - /// - public long Size { get; private set; } - - #endregion - - #region Constructors - - /// Constructs an empty . - public PreviewTreemapItem() { - children = new List(); - Size = 0; - } - - /// Constructs a leaf. - /// - /// The size of the treemap item. - /// The color of the treemap item. - public PreviewTreemapItem(long size, Rgb24Color color) { - Size = size; - Color = color; - } - - /// Constructs a with the specified children. - /// - /// The children to populate the treemap item with. - public PreviewTreemapItem(IEnumerable children) { - this.children = children.ToList(); - Size = children.Sum(c => c.Size); - } - - #endregion - - #region Sort - - /// Validates the treemap item. - public void Validate() { - children.Sort((a, b) => b.Size.CompareTo(a.Size)); - int count = ChildCount; - for (int i = 0; i < count; i++) { - PreviewTreemapItem child = children[i]; - if (child.ChildCount != 0) - child.Validate(); - } - } - - #endregion - - #region Add - - /// Adds a leaf to the children. - /// - /// The size of the child treemap item. - /// The color of the child treemap item. - public void Add(long size, Rgb24Color color) { - children.Add(new PreviewTreemapItem(size, color)); - } - - /// Adds a to the children. - /// - /// The child treemap item to add. - public void Add(PreviewTreemapItem child) { - children.Add(child); - } - - /// Adds a collection of s to the children. - /// - /// The children to add to the treemap item. - public void Add(IEnumerable children) { - this.children.AddRange(children); - } - - #endregion - - #region Properties - - /// Gets if this treemap item is a leaf that should be drawn. - public bool IsLeaf => children == null; - - /// Gets or sets the rectangular bounds of the treemap item in the treemap. - public Rectangle2I Rectangle { - get => rectangle; - set => rectangle = (Rectangle2S) value; - } - - /// Gets the number of children in this treemap item. - public int ChildCount => (children != null ? children.Count : 0); - - /// Gets the child at the specified index in the treemap item. - public PreviewTreemapItem this[int index] => children[index]; - - /// Gets the child at the specified index in the treemap item. - ITreemapItem ITreemapItem.this[int index] => children[index]; - - #endregion - - #region Build Preview - - /// Gets the next color in the palette. - /// - /// The index to increment. - /// The palette to get the color from. - /// A color from the palette. - private static Rgb24Color NextColor(ref int index, IReadOnlyList palette) { - return palette[(index + 1 < palette.Count ? index++ : index)]; - } - - /// Builds a preview treemap for display purposes. - /// - /// The palette to use. - /// The root item of the preview treemap. - public static PreviewTreemapItem Build(IReadOnlyList palette) { - int col = 0; - Rgb24Color color; - - PreviewTreemapItem c4 = new PreviewTreemapItem(); - color = NextColor(ref col, palette); - for (int i = 0; i < 30; i++) - c4.Add(1 + 100 * i, color); - - PreviewTreemapItem c0 = new PreviewTreemapItem(); - for (int i = 0; i < 8; i++) - c0.Add(500 + 600 * i, NextColor(ref col, palette)); - - PreviewTreemapItem c1 = new PreviewTreemapItem(); - color = NextColor(ref col, palette); - for (int i = 0; i < 10; i++) - c1.Add(1 + 200 * i, color); - c0.Add(c1); - - PreviewTreemapItem c2 = new PreviewTreemapItem(); - color = NextColor(ref col, palette); - for (int i = 0; i < 160; i++) - c2.Add(1 + i, color); - - PreviewTreemapItem c3 = new PreviewTreemapItem(); - c3.Add(10000, NextColor(ref col, palette)); - c3.Add(c4); - c3.Add(c2); - c3.Add(6000, NextColor(ref col, palette)); - c3.Add(1500, NextColor(ref col, palette)); - - PreviewTreemapItem root = new PreviewTreemapItem(); - root.Add(c0); - root.Add(c3); - - root.Validate(); - return root; - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Rendering/TreemapOptions.cs b/WinDirStat.Net.Base/Rendering/TreemapOptions.cs deleted file mode 100644 index da6694b..0000000 --- a/WinDirStat.Net.Base/Rendering/TreemapOptions.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using WinDirStat.Net.Structures; -using WinDirStat.Net.Utils; - -#if DOUBLE -using Number = System.Double; -using Point2N = WinDirStat.Net.Structures.Point2D; -#else -using Number = System.Single; -using Point2N = WinDirStat.Net.Structures.Point2F; -#endif - -namespace WinDirStat.Net.Rendering { - /// A structure containing treemap rendering options. - [Serializable] - public struct TreemapOptions { - - public static readonly TreemapOptions Default = new TreemapOptions { - Style = TreemapStyle.KDirStatStyle, - Grid = false, - GridColor = Rgb24Color.Black, - Brightness = (Number) 0.88, - Height = (Number) 0.38, - ScaleFactor = (Number) 0.91, - AmbientLight = (Number) 0.13, - LightSourceX = -1, - LightSourceY = -1, - }; - - /// Squarification method - public TreemapStyle Style; - /// Whether or not to draw grid lines - public bool Grid; - /// Color of grid lines - public Rgb24Color GridColor; - /// 0..1.0 (default = 0.84) - public Number Brightness; - /// 0..oo (default = 0.40) Factor "H" - public Number Height; - /// 0..1.0 (default = 0.90) Factor "F" - public Number ScaleFactor; - /// 0..1.0 (default = 0.15) Factor "Ia" - public Number AmbientLight; - /// -4.0..+4.0 (default = -1.0), negative = left - public Number LightSourceX; - /// -4.0..+4.0 (default = -1.0), negative = top - public Number LightSourceY; - - public int BrightnessPercent { - get => MathUtils.Round(Brightness * 100); - set => Brightness = value / (Number) 100; - } - public int HeightPercent { - get => MathUtils.Round(Height * 100); - set => Height = value / (Number) 100; - } - public int ScaleFactorPercent { - get => MathUtils.Round(ScaleFactor * 100); - set => ScaleFactor = value / (Number) 100; - } - public int AmbientLightPercent { - get => MathUtils.Round(AmbientLight * 100); - set => AmbientLight = value / (Number) 100; - } - public int LightSourceXPercent { - get => MathUtils.Round(LightSourceX * 100); - set => LightSourceX = value / (Number) 100; - } - public int LightSourceYPercent { - get => MathUtils.Round(LightSourceY * 100); - set => LightSourceY = value / (Number) 100; - } - public Point2I LightSourcePoint { - get => new Point2I(LightSourceXPercent, LightSourceYPercent); - set { - LightSourceXPercent = value.X; - LightSourceYPercent = value.Y; - } - } - } -} diff --git a/WinDirStat.Net.Base/Rendering/TreemapRenderer.DrawChildren.cs b/WinDirStat.Net.Base/Rendering/TreemapRenderer.DrawChildren.cs deleted file mode 100644 index 1a76ca3..0000000 --- a/WinDirStat.Net.Base/Rendering/TreemapRenderer.DrawChildren.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System; -using System.Diagnostics; -using WinDirStat.Net.Structures; - -#if DOUBLE -using Number = System.Double; -using Point2N = WinDirStat.Net.Structures.Point2D; -#else -using Number = System.Single; -using Point2N = WinDirStat.Net.Structures.Point2F; -#endif - -namespace WinDirStat.Net.Rendering { - unsafe partial class TreemapRenderer { - - private void RecurseDrawGraph(Rgba32Color* bitmap, ITreemapItem item, Rectangle2I rc, - bool isroot, Number[] pSurface, Number h, uint flags) - { - Debug.Assert(rc.Width >= 0); - Debug.Assert(rc.Height >= 0); - Debug.Assert(item.Size > 0); - - item.Rectangle = rc; - - int gridWidth = options.Grid ? 1 : 0; - - if (rc.Width <= gridWidth || rc.Height <= gridWidth) - return; - - Number[] surface = new Number[] { 0, 0, 0, 0 }; - if (IsCushionShading) { - Array.Copy(pSurface, surface, pSurface.Length); - - if (!isroot) - AddRidge(rc, surface, h); - } - - if (item.IsLeaf) { - RenderLeaf(bitmap, item, surface); - } - else { - Debug.Assert(item.ChildCount > 0); - Debug.Assert(item.Size > 0); - - DrawChildren(bitmap, item, surface, h, flags); - } - } - - private void DrawChildren(Rgba32Color* bitmap, ITreemapItem parent, Number[] surface, Number h, uint flags) { - switch (options.Style) { - case TreemapStyle.KDirStatStyle: - KDirStat_DrawChildren(bitmap, parent, surface, h, flags); - break; - case TreemapStyle.SequoiaViewStyle: - throw new NotImplementedException("SequoiaViewStyle"); - //SequoiaView_DrawwChildren(bitmap, parent, surface, h, flags); - //break; - case TreemapStyle.SimpleStyle: - throw new NotImplementedException("SimpleStyle"); - //Simple_DrawwChildren(bitmap, parent, surface, h, flags); - //break; - } - } - - - private bool IsCushionShading { - get => options.AmbientLight < 1 && options.Height > 0 && options.ScaleFactor > 0; - } - - private void RenderLeaf(Rgba32Color* bitmap, ITreemapItem item, Number[] surface) { - Rectangle2I rc = item.Rectangle; - - if (options.Grid) { - rc.Y++; - rc.X++; - rc.Width--; - rc.Height--; - if (rc.Width <= 0 || rc.Height <= 0) - return; - } - - RenderRectangle(bitmap, rc, surface, item.Color); - } - - private void RenderRectangle(Rgba32Color* bitmap, Rectangle2I rc, Number[] surface, Rgba32Color color) { - Number brightness = options.Brightness; - - //color = ColorSpace.SetBrightness(color, PaletteBrightness); - //brightness *= (Number) 0.66; - - if (IsCushionShading) { - DrawCushion(bitmap, rc, surface, color, brightness); - } - else { - DrawSolidRect(bitmap, rc, color, brightness); - } - } - - private void DrawSolidRect(Rgba32Color* bitmap, Rectangle2I rc, Rgba32Color color, Number brightness) { - Number factor = brightness / ColorSpace.PaletteBrightness; - - int red = (int) (color.R * factor); - int green = (int) (color.G * factor); - int blue = (int) (color.B * factor); - color = new Rgba32Color(red, green, blue); - - ColorSpace.NormalizeColor(ref red, ref green, ref blue); - - for (int iy = rc.Top; iy < rc.Bottom; iy++) { - for (int ix = rc.Left; ix < rc.Right; ix++) { - bitmap[ix + iy * renderArea.Width] = color; - } - } - } - private void DrawCushion(Rgba32Color* bitmap, Rectangle2I rc, Number[] surface, Rgba32Color color, Number brightness) { - Number Ia = options.AmbientLight; - - Number Is = 1 - Ia; - - Number r = color.R; - Number g = color.G; - Number b = color.B; - - for (int iy = rc.Top; iy < rc.Bottom; iy++) { - for (int ix = rc.Left; ix < rc.Right; ix++) { - Number nx = (-(2 * surface[0] * (ix + (Number) 0.5) + surface[2])); - Number ny = (-(2 * surface[1] * (iy + (Number) 0.5) + surface[3])); - Number cosa = Math.Min(1, (Number) ((nx*lx + ny*ly + lz) / Math.Sqrt(nx*nx + ny*ny + 1))); - - Number pixel = Math.Max(0, Is * cosa); - - pixel += Ia; - Debug.Assert(pixel <= 1); - - // Now, pixel is the brightness of the pixel, 0...1.0. - - // Apply contrast. - // Not implemented. - // Costs performance and nearly the same effect can be - // made width the m_options->ambientLight parameter. - // pixel= pow(pixel, m_options->contrast); - - // Apply "brightness" - pixel *= brightness / ColorSpace.PaletteBrightness; - - int red = (int) (r * pixel); - int green = (int) (g * pixel); - int blue = (int) (b * pixel); - - ColorSpace.NormalizeColor(ref red, ref green, ref blue); - - bitmap[ix + iy * renderArea.Width] = new Rgba32Color(red, green, blue); - } - } - } - - private void AddRidge(Rectangle2I rc, Number[] surface, Number h) { - /* - Unoptimized: - - if(rc.Width() > 0) - { - surface[2] += 4 * h * (rc.right + rc.left) / (rc.right - rc.left); - surface[0] -= 4 * h / (rc.right - rc.left); - } - - if(rc.Height() > 0) - { - surface[3] += 4 * h * (rc.bottom + rc.top) / (rc.bottom - rc.top); - surface[1] -= 4 * h / (rc.bottom - rc.top); - } - */ - - // Optimized (gained 15 ms of 1030): - - int width = rc.Width; - int height = rc.Height; - - Debug.Assert(width > 0 && height > 0); - - Number h4 = 4 * h; - - Number wf = h4 / width; - surface[2] += wf * (rc.Right + rc.Left); - surface[0] -= wf; - - Number hf = h4 / height; - surface[3] += hf * (rc.Bottom + rc.Top); - surface[1] -= hf; - } - } -} diff --git a/WinDirStat.Net.Base/Rendering/TreemapRenderer.Highlighting.cs b/WinDirStat.Net.Base/Rendering/TreemapRenderer.Highlighting.cs deleted file mode 100644 index 4fd555a..0000000 --- a/WinDirStat.Net.Base/Rendering/TreemapRenderer.Highlighting.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Collections.Generic; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Structures; - -#if DOUBLE -using Number = System.Double; -using Point2N = WinDirStat.Net.Structures.Point2D; -#else -using Number = System.Single; -using Point2N = WinDirStat.Net.Structures.Point2F; -#endif - -namespace WinDirStat.Net.Rendering { - unsafe partial class TreemapRenderer { - - public void HighlightItems(IWriteableBitmap bitmap, Rectangle2I rc, Rgba32Color color, IEnumerable items) { - if (rc.Width <= 0 || rc.Height <= 0) - return; - - renderArea = rc; - - InitPixels(rc, Rgba32Color.Transparent); - - fixed (Rgba32Color* pBitmapBits = pixels) { - - foreach (FileItemBase item in items) - HighlightRectangle(pBitmapBits, item.Rectangle, color); - - bitmap.SetPixels(pBitmapBits); - } - } - - public void HighlightExtensions(IWriteableBitmap bitmap, Rectangle2I rc, FileItemBase root, Rgba32Color color, string extension) { - if (rc.Width <= 0 || rc.Height <= 0) - return; - - renderArea = rc; - - InitPixels(rc, Rgba32Color.Transparent); - - fixed (Rgba32Color* pBitmapBits = pixels) { - - RecurseHighlightExtensions(pBitmapBits, root, color, extension); - - bitmap.SetPixels(pBitmapBits); - } - } - - private void RecurseHighlightExtensions(Rgba32Color* bitmap, FileItemBase parent, Rgba32Color color, string extension) { - List children = parent.Children; - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - Rectangle2S rc = child.Rectangle; - if (rc.Width > 0 && rc.Height > 0) { - if (child.IsLeaf) { - if (child.Extension == extension) - HighlightRectangle(bitmap, rc, color); - } - else { - RecurseHighlightExtensions(bitmap, child, color, extension); - } - } - } - } - - private void HighlightRectangle(Rgba32Color* bitmap, Rectangle2I rc, Rgba32Color color) { - if (rc.Width >= 7 && rc.Height >= 7) { - FillRectangle(bitmap, Rectangle2I.FromLTRB(rc.Left, rc.Top, rc.Right, rc.Top + 3), color); - FillRectangle(bitmap, Rectangle2I.FromLTRB(rc.Left, rc.Bottom - 3, rc.Right, rc.Bottom), color); - FillRectangle(bitmap, Rectangle2I.FromLTRB(rc.Left, rc.Top + 3, rc.Left + 3, rc.Bottom - 3), color); - FillRectangle(bitmap, Rectangle2I.FromLTRB(rc.Right - 3, rc.Top + 3, rc.Right, rc.Bottom - 3), color); - } - else if (rc.Width == 1 && rc.Height == 1) { - bitmap[rc.Left + rc.Top * renderArea.Width] = color; - } - else if (rc.Width > 0 && rc.Height > 0) { - FillRectangle(bitmap, rc, color); - } - } - - private void FillRectangle(Rgba32Color* bitmap, Rectangle2I rc, Rgba32Color color) { - int bottom = rc.Bottom; - int right = rc.Right; - if (rc.Width >= rc.Height) { - for (int iy = rc.Top; iy < bottom; iy++) { - for (int ix = rc.Left; ix < right; ix++) { - bitmap[ix + iy * renderArea.Width] = color; - } - } - } - else { - for (int ix = rc.Left; ix < right; ix++) { - for (int iy = rc.Top; iy < bottom; iy++) { - bitmap[ix + iy * renderArea.Width] = color; - } - } - } - } - } -} diff --git a/WinDirStat.Net.Base/Rendering/TreemapRenderer.KDirStat.cs b/WinDirStat.Net.Base/Rendering/TreemapRenderer.KDirStat.cs deleted file mode 100644 index 7ff3298..0000000 --- a/WinDirStat.Net.Base/Rendering/TreemapRenderer.KDirStat.cs +++ /dev/null @@ -1,190 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Structures; - -#if DOUBLE -using Number = System.Double; -using Point2N = WinDirStat.Net.Structures.Point2D; -#else -using Number = System.Single; -using Point2N = WinDirStat.Net.Structures.Point2F; -#endif - -namespace WinDirStat.Net.Rendering { - unsafe partial class TreemapRenderer { - - private void KDirStat_DrawChildren(Rgba32Color* bitmap, ITreemapItem parent, Number[] surface, Number h, uint flags) { - Debug.Assert(parent.ChildCount > 0); - - Rectangle2I rc = parent.Rectangle; - List rows = new List(); - List childrenPerRow = new List(); - - Number[] childWidth = new Number[parent.ChildCount]; - - bool horizontalRows = KDirStat_ArrangeChildren(parent, childWidth, rows, childrenPerRow); - - int width = horizontalRows ? rc.Width : rc.Height; - int height = horizontalRows ? rc.Height : rc.Width; - Debug.Assert(width >= 0); - Debug.Assert(height >= 0); - - int c = 0; - Number top = horizontalRows ? rc.Top : rc.Left; - for (int row = 0; row < rows.Count; row++) { - Number fBottom = top + rows[row] * height; - int bottom = (int) fBottom; - if (row == rows.Count - 1) { - bottom = horizontalRows ? rc.Bottom : rc.Right; - } - Number left = horizontalRows ? rc.Left : rc.Top; - for (int i = 0; i < childrenPerRow[row]; i++, c++) { - ITreemapItem child = parent[c]; - Debug.Assert(childWidth[c] >= 0); - Number fRight = left + childWidth[c] * width; - int right = (int) fRight; - - bool lastChild = (i == childrenPerRow[row] - 1 || childWidth[c + 1] == 0); - - if (lastChild) - right = horizontalRows ? rc.Right : rc.Bottom; - - Rectangle2I rcChild; - if (horizontalRows) { - rcChild = Rectangle2I.FromLTRB((int) left, (int) top, right, bottom); - } - else { - rcChild = Rectangle2I.FromLTRB((int) top, (int) left, bottom, right); - } - -#if DEBUG - if (rcChild.Width > 0 && rcChild.Height > 0) { - //Rectangle2I test; - //test.IntersectRect(parent->TmiGetRectangle(), rcChild); - //Debug.Assert(test == rcChild); - } -#endif - RecurseDrawGraph(bitmap, child, rcChild, false, surface, h * options.ScaleFactor, 0); - - if (lastChild) { - i++; c++; - - if (i < childrenPerRow[row]) { - parent[c].Rectangle = Rectangle2I.FromLTRB(-1, -1, -1, -1); - } - - c += childrenPerRow[row] - i; - break; - } - - left = fRight; - } - top = fBottom; - } - } - - private bool KDirStat_ArrangeChildren(ITreemapItem parent, Number[] childWidth, List rows, List childrenPerRow) { - Debug.Assert(!parent.IsLeaf); - Debug.Assert(parent.ChildCount > 0); - - if (parent.Size == 0) { - rows.Add(1); - childrenPerRow.Add(parent.ChildCount); - for (int i = 0; i < parent.ChildCount; i++) { - childWidth[i] = 1 / parent.ChildCount; - } - return true; - } - - bool horizontalRows = parent.Rectangle.Width >= parent.Rectangle.Height; - - Number width = 1; - if (horizontalRows) { - if (parent.Rectangle.Height > 0) - width = (Number) parent.Rectangle.Width / parent.Rectangle.Height; - } - else { - if (parent.Rectangle.Width > 0) - width = (Number) parent.Rectangle.Height / parent.Rectangle.Width; - } - - int nextChild = 0; - while (nextChild < parent.ChildCount) { - rows.Add(KDirStat_CalculateNextRow(parent, nextChild, width, out int childrenUsed, childWidth)); - childrenPerRow.Add(childrenUsed); - nextChild += childrenUsed; - } - - return horizontalRows; - } - - private Number KDirStat_CalculateNextRow(ITreemapItem parent, int nextChild, Number width, out int childrenUsed, Number[] childWidth) { - int i = 0; - const Number minProportion = (Number) 0.4; - Debug.Assert(minProportion < 1); - - Debug.Assert(nextChild < parent.ChildCount); - Debug.Assert(width >= 1); - - Number mySize = parent.Size; - Debug.Assert(mySize > 0); - long sizeUsed = 0; - Number rowHeight = 0; - - for (i = nextChild; i < parent.ChildCount; i++) { - long childSize = parent[i].Size; - if (childSize == 0) { - Debug.Assert(i > nextChild); - break; - } - - sizeUsed += childSize; - Number virtualRowHeight = sizeUsed / mySize; - Debug.Assert(virtualRowHeight > 0); - Debug.Assert(virtualRowHeight <= 1); - - // Rectangle2I(mySize) = width * 1.0 - // Rectangle2I(childSize) = childWidth * virtualRowHeight - // Rectangle2I(childSize) = childSize / mySize * width - - Number childWidth_ = childSize / mySize * width / virtualRowHeight; - - if (childWidth_ / virtualRowHeight < minProportion) { - Debug.Assert(i > nextChild); // because width >= 1 and _minProportion < 1. - // For the first child we have: - // childWidth / rowHeight - // = childSize / mySize * width / rowHeight / rowHeight - // = childSize * width / sizeUsed / sizeUsed * mySize - // > childSize * mySize / sizeUsed / sizeUsed - // > childSize * childSize / childSize / childSize - // = 1 > _minProportion. - break; - } - rowHeight = virtualRowHeight; - } - Debug.Assert(i > nextChild); - - while (i < parent.ChildCount && parent[i].Size == 0) { - i++; - } - - childrenUsed = i - nextChild; - - for (i = 0; i < childrenUsed; i++) { - // Rectangle2I(1 * 1) = mySize - Number rowSize = mySize * rowHeight; - Number childSize = parent[nextChild + i].Size; - Number cw = childSize / rowSize; - Debug.Assert(cw >= 0); - childWidth[nextChild + i] = cw; - } - - return rowHeight; - } - - } -} diff --git a/WinDirStat.Net.Base/Rendering/TreemapRenderer.Sequoia.cs b/WinDirStat.Net.Base/Rendering/TreemapRenderer.Sequoia.cs deleted file mode 100644 index c38ab80..0000000 --- a/WinDirStat.Net.Base/Rendering/TreemapRenderer.Sequoia.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Structures; - -#if DOUBLE -using Number = System.Double; -using Point2N = WinDirStat.Net.Structures.Point2D; -#else -using Number = System.Single; -using Point2N = WinDirStat.Net.Structures.Point2F; -#endif - -namespace WinDirStat.Net.Rendering { - unsafe partial class TreemapRenderer { - - } -} diff --git a/WinDirStat.Net.Base/Rendering/TreemapRenderer.cs b/WinDirStat.Net.Base/Rendering/TreemapRenderer.cs deleted file mode 100644 index b58bd65..0000000 --- a/WinDirStat.Net.Base/Rendering/TreemapRenderer.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System; -using System.Diagnostics; -using WinDirStat.Net.Utils; -using WinDirStat.Net.Services; -using WinDirStat.Net.Structures; -using WinDirStat.Net.Services.Structures; - -#if DOUBLE -using Number = System.Double; -using Point2N = WinDirStat.Net.Structures.Point2D; -#else -using Number = System.Single; -using Point2N = WinDirStat.Net.Structures.Point2F; -#endif - -namespace WinDirStat.Net.Rendering { - /// A service for rendering WinDirStat treemaps. - public unsafe partial class TreemapRenderer { - - #region Fields - - /// The UI service. - private readonly IUIService ui; - - /// The last pixel array used for drawing. - private Rgba32Color[] pixels; - - /// The render options for the treemap. - private TreemapOptions options; - /// Calculated light position for the treemap. - private Number lx; - /// Calculated light position for the treemap. - private Number ly; - /// Calculated light position for the treemap. - private Number lz; - /// The render area for the current operation. - private Rectangle2I renderArea; - - #endregion - - #region Constructors - - /// Constructs the . - public TreemapRenderer(IUIService ui) { - this.ui = ui; - Options = TreemapOptions.Default; - } - - #endregion - - #region Properties - - /// Gets or sets the treemap options. - public TreemapOptions Options { - get => options; - set { - options = value; - - Number lx = options.LightSourceX; - Number ly = options.LightSourceY; - const Number lz = 10; - - Number lenght = (Number) Math.Sqrt(lx*lx + ly*ly + lz*lz); - this.lx = lx / lenght; - this.ly = ly / lenght; - this.lz = lz / lenght; - } - } - - #endregion - - private void InitPixels(Rectangle2I rc, Rgba32Color? background = null) { - int pixelCount = rc.Width * rc.Height; - if (pixels == null || pixels.Length != pixelCount) - pixels = new Rgba32Color[rc.Width * rc.Height]; - if (background.HasValue) - pixels.Memset(background.Value); - } - - [Conditional("DEBUG")] - private void RecurseCheckTree(ITreemapItem item) { - if (item.IsLeaf) { - Debug.Assert(item.ChildCount == 0); - } - else { - // TODO: check that children are sorted by size. - long sum = 0; - for (int i = 0; i < item.ChildCount; i++) { - ITreemapItem child = item[i]; - sum += child.Size; - RecurseCheckTree(child); - } - Debug.Assert(sum == item.Size); - } - } - - public void DrawTreemap(IWriteableBitmap bitmap, Rectangle2I rc, ITreemapItem root) { - RecurseCheckTree(root); - - Rectangle2I fullRc = rc; - - rc.Width--; - rc.Height--; - - if (rc.Width <= 0 || rc.Height <= 0) - return; - - renderArea = fullRc; - - if (root.Size == 0) - InitPixels(fullRc, Rgba32Color.Black); - else if (options.Grid) - InitPixels(fullRc, options.GridColor); - else - InitPixels(fullRc, new Rgba32Color(160, 160, 160)); - - fixed (Rgba32Color* pBitmapBits = pixels) { - - // Recursively draw the tree graph - if (root.Size > 0) { - Number[] surface = { 0, 0, 0, 0 }; - RecurseDrawGraph(pBitmapBits, root, rc, true, surface, options.Height, 0); - } - - bitmap.SetPixels(pBitmapBits); - } - } - - public void DrawColorPreview(IWriteableBitmap bitmap, Rectangle2I rc, Rgb24Color color) { - if (rc.Width <= 0 || rc.Height <= 0) - return; - - renderArea = rc; - - // That bitmap in turn will be created from this array - InitPixels(rc); - - fixed (Rgba32Color* pBitmapBits = pixels) { - - Number[] surface = { 0, 0, 0, 0 }; - - AddRidge(rc, surface, options.Height * options.ScaleFactor); - RenderRectangle(pBitmapBits, rc, surface, color); - - bitmap.SetPixels(pBitmapBits); - } - } - - public static ITreemapItem FindItemAtPoint(ITreemapItem item, Point2I p) { - if (item.IsLeaf) { - return item; - } - else { - for (int i = 0; i < item.ChildCount; i++) { - ITreemapItem child = item[i]; - Rectangle2I rcChild = child.Rectangle; - - if (rcChild.Contains(p)) - return FindItemAtPoint(child, p); - } - } - - return null; - } - } -} diff --git a/WinDirStat.Net.Base/Rendering/TreemapRendererFactory.cs b/WinDirStat.Net.Base/Rendering/TreemapRendererFactory.cs deleted file mode 100644 index 3694949..0000000 --- a/WinDirStat.Net.Base/Rendering/TreemapRendererFactory.cs +++ /dev/null @@ -1,32 +0,0 @@ -using WinDirStat.Net.Services; - -namespace WinDirStat.Net.Rendering { - /// A factory for treemap renderers. - public class TreemapRendererFactory { - - #region Fields - - /// The UI service. - private readonly IUIService ui; - - #endregion - - #region Constructors - - /// Constructs the. - public TreemapRendererFactory(IUIService ui) { - this.ui = ui; - } - - #endregion - - #region TreemapRenderer Factory - - /// Constructs a new . - public TreemapRenderer Create() { - return new TreemapRenderer(ui); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Rendering/TreemapStyle.cs b/WinDirStat.Net.Base/Rendering/TreemapStyle.cs deleted file mode 100644 index 9dcd4fc..0000000 --- a/WinDirStat.Net.Base/Rendering/TreemapStyle.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Rendering { - /// The types of render methods for treemaps. - [Serializable] - public enum TreemapStyle { - /// Horizontal/Vertical align. - [Description("KDirStat")] - KDirStatStyle = 0, - /// Corner align. - [Description("SequoiaView")] - SequoiaViewStyle = 1, - /// Dunno. - [Description("Simple")] - SimpleStyle = 2, - } -} diff --git a/WinDirStat.Net.Base/Services/IBitmapFactory.cs b/WinDirStat.Net.Base/Services/IBitmapFactory.cs deleted file mode 100644 index 5120114..0000000 --- a/WinDirStat.Net.Base/Services/IBitmapFactory.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Structures; - -namespace WinDirStat.Net.Services { - /// An interface for creating and loading bitmaps. - public interface IBitmapFactory { - - #region Create - - /// Creates a new writeable bitmap. - /// - /// The size of the bitmap. - /// The new writeable bitmap. - IWriteableBitmap CreateBitmap(Point2I size); - - #endregion - - #region From Source - - /// Loads a bitmap from the specified resource path. - /// - /// The resource path to load the bitmap from. - /// - /// The assembly to load the resource from. The calling assembly is used if null. - /// - /// The loaded bitmap. - IBitmap FromResource(string resourcePath, Assembly assembly = null); - - /// Loads a bitmap from the specified file path. - /// - /// The file path to load the bitmap from. - /// The loaded bitmap. - IBitmap FromFile(string filePath); - - /// Loads a bitmap from the specified stream. - /// - /// The stream to load the bitmap from. - /// The loaded bitmap. - IBitmap FromStream(Stream stream); - -#if WINDOWS - - /// Loads a bitmap from the specified icon handle. - /// - /// The handle of the icon to load. - /// The loaded bitmap. - IBitmap FromHIcon(IntPtr handle); - -#endif - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/IClipboardService.cs b/WinDirStat.Net.Base/Services/IClipboardService.cs deleted file mode 100644 index 0a41ce9..0000000 --- a/WinDirStat.Net.Base/Services/IClipboardService.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Services { - /// A service for interacting with the clipboard. - public interface IClipboardService { - - #region Text - - /// Gets the text assigned to the clipboard. - /// - /// A string if the clipboard has text assigned to it. - string GetText(); - /// Assigns text to the clipboard. - /// - /// The new text to assign to the clipboard. - void SetText(string text); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/IIconCacheService.cs b/WinDirStat.Net.Base/Services/IIconCacheService.cs deleted file mode 100644 index 8e49cfe..0000000 --- a/WinDirStat.Net.Base/Services/IIconCacheService.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.Collections.Specialized; -using System.ComponentModel; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Services { - /// A service for caching and looking up icons. - public interface IIconCacheService : INotifyPropertyChanged { - - #region Properties - - /// Gets the number of cached icons. - int Count { get; } - - #endregion - - #region Icon Properties - - /// Gets the default file icon. - IImage FileIcon { get; } - /// Gets the default folder icon. - IImage FolderIcon { get; } - /// Gets the default drive icon. - IImage VolumeIcon { get; } - /// Gets the default shortcut icon. - IImage ShortcutIcon { get; } - - #endregion - - #region Icon Caching - - /// Caches the icon of the specified file. - /// - /// The path of the file. - /// The cached icon on success, otherwise null. - IImage CacheIcon(string path); - /// Asynchronousy caches the icon of the specified file. - /// - /// The path of the file. - /// The method that returns the icon upon completion. - void CacheIconAsync(string path, ICacheIconCallback callback); - - /// Caches the icon and display name of the specified file. - /// - /// The path of the file. - /// The cached icon and icon on success, otherwise null. - IIconAndName CacheIconAndDisplayName(string path); - /// Asynchronousy caches the icon and display name of the specified file. - /// - /// The path of the file. - /// The method that returns the icon and name upon completion. - void CacheIconAndDisplayNameAsync(string path, ICacheIconAndNameCallback callback); - - /// Caches the file type's icon and type name. - /// - /// The extension of the file type. - /// The cached icon and type name on success, otherwise null. - IIconAndName CacheFileType(string extension); - /// Asynchronousy caches the file type's icon and type name. - /// - /// The extension of the file type. - /// The method that returns the icon and type name upon completion. - void CacheFileTypeAsync(string extension, ICacheIconAndNameCallback callback); - - /// Caches the special folder's icon and display name. - /// - /// The special folder type. - /// The cached icon and name on success, otherwise null. - IIconAndName CacheSpecialFolder(Environment.SpecialFolder folder); - /// Asynchronousy caches the special folder's icon and display name. - /// - /// The special folder type. - /// The method that returns the icon and name upon completion. - void CacheSpecialFolderAsync(Environment.SpecialFolder folder, ICacheIconAndNameCallback callback); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/IImagesService.cs b/WinDirStat.Net.Base/Services/IImagesService.cs deleted file mode 100644 index eaf42eb..0000000 --- a/WinDirStat.Net.Base/Services/IImagesService.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Services { - /// A service for image references. - public interface IImagesService { - - #region File Icon Fields - - /// Gets the icon for file collection items. - IImage FileCollection { get; } - /// Gets the icon for free space items. - IImage FreeSpace { get; } - /// Gets the icon for unknown space items. - IImage UnknownSpace { get; } - /// Gets the icon for files that no longer exist. - IImage Missing { get; } - - #endregion - - } -} diff --git a/WinDirStat.Net.Base/Services/IMainCommandInfoService.cs b/WinDirStat.Net.Base/Services/IMainCommandInfoService.cs deleted file mode 100644 index 91d77a9..0000000 --- a/WinDirStat.Net.Base/Services/IMainCommandInfoService.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Services { - public interface IMainCommandInfoService { - - #region File Menu - - IRelayUICommandInfo Open { get; } - IRelayUICommandInfo Save { get; } - IRelayUICommandInfo Reload { get; } - IRelayUICommandInfo Close { get; } - IRelayUICommandInfo Cancel { get; } - IRelayUICommandInfo Elevate { get; } - IRelayUICommandInfo Exit { get; } - - #endregion - - #region Context Menu/ToolBar - - IRelayUICommandInfo Expand { get; } - IRelayUICommandInfo Collapse { get; } - IRelayUICommandInfo OpenItem { get; } - IRelayUICommandInfo CopyPath { get; } - IRelayUICommandInfo Explore { get; } - IRelayUICommandInfo CommandPrompt { get; } - IRelayUICommandInfo PowerShell { get; } - IRelayUICommandInfo RefreshSelected { get; } - IRelayUICommandInfo DeleteRecycle { get; } - IRelayUICommandInfo DeletePermanently { get; } - IRelayUICommandInfo Properties { get; } - - #endregion - - #region Options Menu - - IRelayUICommandInfo ShowFreeSpace { get; } - IRelayUICommandInfo ShowUnknown { get; } - IRelayUICommandInfo ShowTotalSpace { get; } - IRelayUICommandInfo ShowFileTypes { get; } - IRelayUICommandInfo ShowTreemap { get; } - IRelayUICommandInfo ShowToolBar { get; } - IRelayUICommandInfo ShowStatusBar { get; } - IRelayUICommandInfo Configure { get; } - - #endregion - - #region Other - - IRelayUICommandInfo EmptyRecycleBin { get; } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/IOSService.cs b/WinDirStat.Net.Base/Services/IOSService.cs deleted file mode 100644 index fbf6fe0..0000000 --- a/WinDirStat.Net.Base/Services/IOSService.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Services { - /// A service for OS-specific actions. - public interface IOSService { - - #region Privileges - - /// Gets if the current process has elevated privileges. - bool IsElevated { get; } - - /// Starts a new version of this process in an elevated environment. - void StartNewElevated(string arguments = ""); - - #endregion - - #region RunItem - - /// Opens the specified item using the default action. - /// - /// The file to open. - void RunItem(string file); - - #endregion - - #region Explore - - /// Opens the computer folder in Explorer. - void ExploreComputer(); - - /// Opens the folder in Explorer. - /// - /// The path of the folder to open. - void ExploreFolder(string folderPath); - - /// Opens the parent folder in Explorer and selects the file. - /// - /// The path of the file to select. - void ExploreFile(string filePath); - - /// Opens the properties window for the computer. - bool OpenComputerProperties(string filePath); - - /// Opens the properties window of the file. - /// The path of the file to view the properties of. - bool OpenProperties(string filePath); - - #endregion - - #region Console - - /// Opens the command prompt in the specified working directory. - /// - /// The working directory to open the command prompt in. - void OpenCommandPrompt(string directory); - - /// Opens PowerShell in the specified working directory. - /// - /// The working directory to open PowerShell in. - void OpenPowerShell(string directory); - - #endregion - - #region Delete/Recycle - - /// Permanently deletes the file. - /// - /// The path of the file to delete. - /// True if the operation was successful. - bool DeleteFile(string file); - - /// Sends the file or directory to the recycle bin. - /// - /// The path of the file to delete. - /// True if the operation was successful. - bool RecycleFile(string file); - - /// Deletes or recycles the file based on the conditional value. - /// - /// The path of the file to delete. - /// True if the file should be recycled. - /// True if the operation was successful. - bool DeleteOrRecycleFile(string file, bool recycle); - - /// Empties the recycle bin at the specified path. - /// - /// The window to own the dialogs. - /// The path of the recycle bin - /// True if the operation was successful. - bool EmptyRecycleBin(IWindow owner, string path = ""); - - /// Gets the stats about the specified recycle bin. - /// - /// The path of the recycle bin - /// The info about the recycle bin on success, otherwise null. - RecycleBinInfo GetRecycleBinInfo(string path); - - /// Gets the stats about every recycle bin. - /// - /// The info about the recycle bin on success, otherwise null. - RecycleBinInfo GetAllRecycleBinInfo(); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/IScanningService.cs b/WinDirStat.Net.Base/Services/IScanningService.cs deleted file mode 100644 index c5fdd27..0000000 --- a/WinDirStat.Net.Base/Services/IScanningService.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Model.Extensions; -using WinDirStat.Net.Model.Files; - -namespace WinDirStat.Net.Services { - - - - - /// A service for scanning a file tree. - public interface IScanningService : INotifyPropertyChanged, IDisposable { - - - - /// The available root item once the scan has fully started. - RootItem RootItem { get; } - - - event ScanEventHander Started; - event ScanEventHander Ended; - event EventHandler SpaceChanged; - - bool ShowFreeSpace { get; } - bool ShowUnknown { get; } - bool ShowTotalSpace { get; } - - ExtensionItems Extensions { get; } - - void Scan(params string[] rootPaths); - void ScanAsync(params string[] rootPaths); - void Close(bool waitForClose = false); - void CloseAsync(Action callback, bool runWhenAlreadyClosed = true); - void Cancel(bool waitForCancel = false); - void CancelAsync(Action callback, bool runWhenNotScanning = true); - void CancelAsync(ScanEventHander callback, bool runWhenNotScanning = true); - - TimeSpan ScanTime { get; } - TimeSpan ValidateTime { get; } - ScanState ScanState { get; } - ScanProgressState ProgressState { get; } - - bool CanDisplayProgress { get; } - double Progress { get; } - - bool IsScanning { get; } - bool IsScanningAndNotRefreshing { get; } - bool IsRefreshing { get; } - bool IsFinished { get; } - bool IsOpen { get; } - bool IsSuspended { get; set; } - bool IsAsync { get; } - Exception ExceptionResult { get; } - } -} diff --git a/WinDirStat.Net.Base/Services/ISettingsService.cs b/WinDirStat.Net.Base/Services/ISettingsService.cs deleted file mode 100644 index 5f280d7..0000000 --- a/WinDirStat.Net.Base/Services/ISettingsService.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using WinDirStat.Net.Model.Drives; -using WinDirStat.Net.Rendering; -using WinDirStat.Net.Structures; - -namespace WinDirStat.Net.Services { - public interface ISettingsService : INotifyPropertyChanged { - - DriveSelectMode DriveSelectMode { get; set; } - string[] SelectedDrives { get; set; } - string SelectedFolderPath { get; set; } - - ThreadPriority RenderPriority { get; set; } - ThreadPriority ScanPriority { get; set; } - - TimeSpan RAMInterval { get; set; } - TimeSpan StatusInterval { get; set; } - TimeSpan ValidateInterval { get; set; } - - TreemapOptions TreemapOptions { get; set; } - Rgba32Color HighlightColor { get; set; } - - bool ShowUnknown { get; set; } - bool ShowFreeSpace { get; set; } - bool ShowTotalSpace { get; set; } - - bool ShowFileTypes { get; set; } - bool ShowTreemap { get; set; } - bool ShowToolBar { get; set; } - bool ShowStatusBar { get; set; } - - IconCacheMode IconCacheMode { get; set; } - - ReadOnlyCollection FilePalette { get; } - ReadOnlyCollection OriginalFilePalette { get; } - IList FilePalettePreviews { get; } - - Rgb24Color GetFilePaletteColor(int index); - void SetFilePalette(IEnumerable filePalette); - object GetFilePalettePreview(int index); - - ReadOnlyCollection SubtreePalette { get; } - - Rgb24Color GetSubtreePaletteColor(int level); - void SetSubtreePalette(IEnumerable subtreePalette); - - } -} diff --git a/WinDirStat.Net.Base/Services/IShortcutsService.cs b/WinDirStat.Net.Base/Services/IShortcutsService.cs deleted file mode 100644 index d7a44bf..0000000 --- a/WinDirStat.Net.Base/Services/IShortcutsService.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Services { - /// A service for storing platform independent shortcuts. - public interface IShortcutsService { - - #region File Menu - - IShortcut Open { get; } - IShortcut Save { get; } - IShortcut Reload { get; } - IShortcut Close { get; } - IShortcut Cancel { get; } - IShortcut Elevate { get; } - IShortcut Exit { get; } - - #endregion - - #region Context Menu/Toolbar - - IShortcut Expand { get; } - IShortcut OpenItem { get; } - IShortcut CopyPath { get; } - IShortcut Explore { get; } - IShortcut CommandPrompt { get; } - IShortcut PowerShell { get; } - IShortcut RefreshSelected { get; } - IShortcut DeleteRecycle { get; } - IShortcut DeletePermanently { get; } - IShortcut Properties { get; } - - #endregion - - #region Options Menu - - IShortcut ShowFreeSpace { get; } - IShortcut ShowUnknown { get; } - IShortcut ShowTotalSpace { get; } - IShortcut ShowFileTypes { get; } - IShortcut ShowTreemap { get; } - IShortcut ShowToolBar { get; } - IShortcut ShowStatusBar { get; } - IShortcut Configure { get; } - - #endregion - - #region Other - - IShortcut EmptyRecycleBin { get; } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/IUIService.cs b/WinDirStat.Net.Base/Services/IUIService.cs deleted file mode 100644 index 507bc7d..0000000 --- a/WinDirStat.Net.Base/Services/IUIService.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Services { - /// A service for all UI actions. - public interface IUIService { - - #region Dispatcher - - /// Invokes the action on the UI thread. - /// - /// The action to invoke. - void Invoke(Action action); - - /// Invokes the function on the UI thread. - /// - /// The function to invoke. - /// The result of the function. - T Invoke(Func action); - - /// Invokes the action asynchronously on the UI thread. - /// - /// The action to invoke. - /// True if the action should use normal priority. - void BeginInvoke(Action action, bool normalPriority); - - /// Checks if the current thread is the UI thread. - /// - /// True if the current thread is the UI thread. - bool CheckAccess(); - - #endregion - - #region Shutdown - - /// Shuts down the application. - void Shutdown(); - - event EventHandler ShuttingDown; - - #endregion - - #region Create Timer - - /// Creates a new stopped UI timer. - /// - /// The interval for the timer. - /// True if the timer runs at normal priority. - /// The callback on the timer tick event. - IUITimer CreateTimer(TimeSpan interval, bool normalPriority, Action callback); - /// Creates a new running UI timer. - /// - /// The interval for the timer. - /// True if the timer runs at normal priority. - /// The callback on the timer tick event. - /// The newly created timer. - IUITimer StartTimer(TimeSpan interval, bool normalPriority, Action callback); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/IWindowDialogService.cs b/WinDirStat.Net.Base/Services/IWindowDialogService.cs deleted file mode 100644 index 2494218..0000000 --- a/WinDirStat.Net.Base/Services/IWindowDialogService.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using WinDirStat.Net.Model.Drives; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Services { - /// A service for launching dialogs and showing messages. - public interface IWindowDialogService { - - /// Shows the dialog for selecting paths to scan. - /// - /// The owner window for this dialog. - /// The selected root paths on success, otherwise null. - DriveSelectResult ShowDriveSelect(IWindow owner); - - /// Shows the folder browser dialog to select a folder. - /// - /// The owner window for this dialog. - /// The description to display. - /// True if the new folder button is present. - /// The currently selected path. Use an empty string for nothing. - /// The selected path on success, otherwise null. - string ShowFolderBrowser(IWindow owner, string description, bool showNewFolder, string selectedPath = ""); - - /// Shows a message with no icon. - /// - /// The owner window for this dialog message. - /// The text message. - /// The message window title. - /// The message buttons to display. - MessageResult ShowMessage(IWindow owner, string message, string title, MessageButton button = MessageButton.OK); - - /// Shows a message with an information icon. - /// - /// The owner window for this dialog message. - /// The text message. - /// The message window title. - /// The message buttons to display. - MessageResult ShowInformation(IWindow owner, string message, string title, MessageButton button = MessageButton.OK); - - /// Shows a message with a question icon. - /// - /// The owner window for this dialog message. - /// The text message. - /// The message window title. - /// The message buttons to display. - MessageResult ShowQuestion(IWindow owner, string message, string title, MessageButton button = MessageButton.OK); - - /// Shows a message with a warning icon. - /// - /// The owner window for this dialog message. - /// The text message. - /// The message window title. - /// The message buttons to display. - MessageResult ShowWarning(IWindow owner, string message, string title, MessageButton button = MessageButton.OK); - - /// Shows a message with an error icon. - /// - /// The owner window for this dialog message. - /// The text message. - /// The message window title. - /// The message buttons to display. - MessageResult ShowError(IWindow owner, string message, string title, MessageButton button = MessageButton.OK); - } -} diff --git a/WinDirStat.Net.Base/Services/ImagesServiceBase.cs b/WinDirStat.Net.Base/Services/ImagesServiceBase.cs deleted file mode 100644 index 955a452..0000000 --- a/WinDirStat.Net.Base/Services/ImagesServiceBase.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Services { - /// A service for image references. - public abstract class ImagesServiceBase { - - #region File Icon Fields - - /// Gets the icon for file collection items. - public IImage FileCollection { get; protected set; } - /// Gets the icon for free space items. - public IImage FreeSpace { get; protected set; } - /// Gets the icon for unknown space items. - public IImage UnknownSpace { get; protected set; } - /// Gets the icon for files that no longer exist. - public IImage Missing { get; protected set; } - - #endregion - - #region Icon Fields - - /// The icon for the Close command. - public IImage Close { get; protected set; } - /// The icon Command Prompt command. - public IImage Cmd { get; protected set; } - //public ImageSource CmdElevated { get; protected set; } - /// The icon Copy command. - public IImage Copy { get; protected set; } - /// The icon Cut command. - public IImage Cut { get; protected set; } - /// The icon Delete command. - public IImage Delete { get; protected set; } - /// The icon Elevate command. - public IImage Elevate { get; protected set; } - /// The icon Empty Recycle Bin command. - public IImage EmptyRecycleBin { get; protected set; } - /// The icon Exit command. - public IImage Exit { get; protected set; } - /// The icon Expand command. - public IImage Expand { get; protected set; } - /// The icon ExploreCommand command. - public IImage Explore { get; protected set; } - /// The icon Open command. - public IImage Open { get; protected set; } - /// The icon Paste command. - public IImage Paste { get; protected set; } - /// The icon Copy Path command. - public IImage CopyPath { get; protected set; } - /// The icon PowerShell command. - public IImage PowerShell { get; protected set; } - //public IImage PowerShellElevated { get; protected set; } - /// The icon Properties command. - public IImage Properties { get; protected set; } - /// The icon Recycle command. - public IImage RecycleBin { get; protected set; } - /// The icon Redo command. - public IImage Redo { get; protected set; } - /// The icon Reload command. - public IImage Reload { get; protected set; } - /// The icon Refresh Selected command. - public IImage RefreshSelected { get; protected set; } - /// The icon Run (Open Item) command. - public IImage Run { get; protected set; } - /// The icon Save command. - public IImage Save { get; protected set; } - /// The icon Search command. - public IImage Search { get; protected set; } - /// The icon Settings command. - public IImage Settings { get; protected set; } - /*/// The icon Show File Types command. - public IImage ShowFileTypes { get; protected set; }*/ - /// The icon Show Total Space command. - public IImage ShowTotalSpace { get; protected set; } - /// The icon Show Treemap command. - public IImage ShowTreemap { get; protected set; } - /// The icon Undo command. - public IImage Undo { get; protected set; } - - #endregion - - #region Fields - - /// The bitmap factory service. - protected IBitmapFactory BitmapFactory { get; } - /// Gets the UI service. - protected IUIService UI { get; } - - #endregion - - #region Constructors - - /// Constructs the . - public ImagesServiceBase(IBitmapFactory bitmapFactory, - IUIService ui) - { - BitmapFactory = bitmapFactory; - UI = ui; - - UI.Invoke(() => { - // Load file type icons with a different method - FileCollection = LoadFileIcon(nameof(FileCollection)); - FreeSpace = LoadFileIcon(nameof(FreeSpace)); - UnknownSpace = LoadFileIcon(nameof(UnknownSpace)); - Missing = LoadFileIcon(nameof(Missing)); - - // Load all unassigned icons with reflection - foreach (PropertyInfo propInfo in typeof(ImagesServiceBase).GetProperties()) { - if (propInfo.PropertyType == typeof(IImage) && propInfo.CanWrite) { - IImage value = (IImage) propInfo.GetValue(this); - if (value != null) - continue; - value = LoadIcon(propInfo.Name); - propInfo.SetValue(this, value); - } - } - }); - } - - #endregion - - #region Abstract Methods - - /// Loads the icon with the specified name. - /// - /// The name of the icon. - protected abstract IImage LoadIcon(string name); - - /// Loads the file icon with the specified name. - /// - /// The name of the file icon. - protected abstract IImage LoadFileIcon(string name); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/Implementation/CommandInfoService.cs b/WinDirStat.Net.Base/Services/Implementation/CommandInfoService.cs deleted file mode 100644 index 4d5cb94..0000000 --- a/WinDirStat.Net.Base/Services/Implementation/CommandInfoService.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Services.Implementation { - public abstract class CommandInfoService { - - private readonly Dictionary commandInfos; - - - public CommandInfoService() { - commandInfos = new Dictionary(); - } - - public void Initialize() { - foreach (PropertyInfo prop in GetType().GetProperties()) { - if (prop.PropertyType == typeof(IRelayUICommandInfo)) { - commandInfos.Add(prop.Name, (IRelayUICommandInfo) prop.GetValue(this)); - } - } - } - - public IRelayUICommandInfo this[string commandName] => commandInfos[commandName]; - - } -} diff --git a/WinDirStat.Net.Base/Services/Implementation/RelayCommandService.cs b/WinDirStat.Net.Base/Services/Implementation/RelayCommandService.cs deleted file mode 100644 index 6ae9711..0000000 --- a/WinDirStat.Net.Base/Services/Implementation/RelayCommandService.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.ViewModel; - -namespace WinDirStat.Net.Services.Implementation { - public abstract class RelayCommandService { - - /// - /// Creates a new with the specified info and actions. - /// - /// - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - public abstract IRelayCommand Create(IRelayCommandInfo info, Action execute, - Func canExecute = null); - - /// - /// Creates a new with the specified info and actions. - /// - /// - /// The parameter type of the command. - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - public abstract IRelayCommand Create(IRelayCommandInfo info, Action execute, - Func canExecute = null); - - /// - /// Creates a new with the specified info and actions. - /// - /// - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - public abstract IRelayUICommand Create(IRelayUICommandInfo info, Action execute, - Func canExecute = null); - - /// - /// Creates a new with the specified info and actions. - /// - /// - /// The parameter type of the command. - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - public abstract IRelayUICommand Create(IRelayUICommandInfo info, Action execute, - Func canExecute = null); - - } -} diff --git a/WinDirStat.Net.Base/Services/Implementation/ScanningService.cs b/WinDirStat.Net.Base/Services/Implementation/ScanningService.cs deleted file mode 100644 index 054d2d7..0000000 --- a/WinDirStat.Net.Base/Services/Implementation/ScanningService.cs +++ /dev/null @@ -1,895 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Threading; -using System.Windows; -using WinDirStat.Net.Model.Drives; -using WinDirStat.Net.Model.Extensions; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Utils; - -namespace WinDirStat.Net.Services { - /// A service for scanning a path's file tree. - public abstract partial class ScanningService : ObservableVolatileObject { - - #region Protected Classes - - /// A collection of parent folders and files to refresh. - protected class RefreshFiles { - /// The parent folder of the files. - public FolderItem Parent { get; } - /// The files in the parent folder to refresh. - public List Files { get; } - - /// Constructs the . - public RefreshFiles(FolderItem parent) { - Parent = parent; - Files = new List(); - } - - /// Constructs the . - public RefreshFiles(KeyValuePair> pair) { - Parent = pair.Key; - Files = pair.Value; - } - } - - #endregion - - #region Fields - - /// The program settings. - protected readonly SettingsService settings; - /// The OS specific service - protected readonly IOSService os; - /// The UI service - protected readonly IUIService ui; - - // Scan async - /// The cancellation token source for the asynchronous scan thread. - private CancellationTokenSource cancel; - /// The current asynchronous scan thread. - private Thread scanThread; - /// The lock object for scan thread setup. - private readonly object threadLock = new object(); - /// The lock object exclusively for accessing the resume event. - private readonly object resumeLock = new object(); - /// The timer for validating the file tree during a scan. - private readonly Timer validateTimer; - - // Scan progress - /// The total size that has been scanned so far. - private long totalScannedSize; - /// The total size for all scanned roots. - private long totalSize; - /// The total free space for all scanned roots. - private long totalFreeSpace; - /// True if all scanned roots are drives and thus have a definite used size. - private bool canDisplayProgress; - /// The watch for keeping track of the scan duration. - private readonly Stopwatch scanWatch; - /// A watch that keeps track of the time spent validating. - private readonly Stopwatch validateWatch; - /// True if validation has been requested on the scan thread. - private volatile bool validationRequested; - - // Scan state - /// The current state of the scan. - private ScanState scanState; - /// The current progress state of the scan. - private ScanProgressState progressState; - /// True if a refresh operation is in progress. - private bool isRefreshing; - /// The wait handle for resuming a scan. Set if the scan is not suspended. - private ManualResetEvent resumeEvent = new ManualResetEvent(true); - /// True if the UI refreshing should be supressed due to validation. - private bool suppressRefresh; - - // Scan result - /// The root item of the file tree being scanned. - private RootItem rootItem; - /// The resulting exception from the current scan. - private Exception exceptionResult; - /// Gets the extension item collection that records all encountered extensions. - public ExtensionItems Extensions { get; } - /// Gets the drive item collection that records the current drive list. - public DriveItems Drives { get; } - /// The root paths to scan. - private string[] rootPaths; - /// The files to refresh. - private RefreshFiles[] refreshFiles; - /// The result of the drive select dialog used for scanning. - private DriveSelectResult driveSelectResult; - - // Dispose - /// True if the scanning service has been disposed of. - private volatile bool disposed; - - #endregion - - #region Events - - /// Callbacks for when a scan has ended in any fashion. - public event ScanEventHander Ended; - /// Callbacks for . - private event ScanEventHander Cancelled; - - /// Called when the space settings have changed. - public event EventHandler SpaceChanged; - - #endregion - - #region Constructors - - /// Constructs the . - public ScanningService(SettingsService settings, - IOSService os, - IUIService ui) - { - this.settings = settings; - this.os = os; - this.ui = ui; - settings.PropertyChanged += OnSettingsPropertyChanged; - Extensions = new ExtensionItems(this, settings); - Drives = new DriveItems(this); - validateTimer = new Timer(OnValidateTick, null, Timeout.Infinite, Timeout.Infinite); - validateWatch = new Stopwatch(); - scanWatch = new Stopwatch(); - validationRequested = false; - } - - #endregion - - #region Event Handlers - - /// Called when the settings' properties have changed. - private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - case nameof(SettingsService.ShowFreeSpace): - case nameof(SettingsService.ShowUnknown): - case nameof(SettingsService.ShowTotalSpace): - bool shouldSet = !IsScanning && !IsRefreshing; - if (shouldSet) - IsRefreshing = true; - RaisePropertyChanged(e.PropertyName); - RaiseSpaceChanged(); - if (shouldSet) - IsRefreshing = false; - break; - case nameof(SettingsService.ScanPriority): - lock (volatileLock) { - if (IsAsync) - scanThread.Priority = settings.ScanPriority; - } - break; - case nameof(SettingsService.ValidateInterval): - // Same thing as performing an interval change - StartValidateTimer(); - break; - } - } - - #endregion - - #region Private Helpers - - /// Stops the validate timer. - private void StopValidateTimer() { - if (!disposed) - validateTimer.Change(Timeout.Infinite, Timeout.Infinite); - } - - /// Starts the validate timer. - private void StartValidateTimer() { - if (!disposed) - validateTimer.Change(settings.ValidateInterval, Timeout.InfiniteTimeSpan); - } - - /// Adds a request for the file tree to be validated. - private void OnValidateTick(object state) { - validationRequested = true; - } - - /// Raises the event. - private void RaiseSpaceChanged() { - SpaceChanged?.Invoke(this, EventArgs.Empty); - } - - /// Throws an exception if a scan is in progress. - [DebuggerStepThrough] - private void ThrowIfScanning() { - if (IsScanning) - throw new InvalidOperationException("Cannot start new scan while one is currently in progress!"); - } - - #endregion - - #region Public Scanning - - /// Begins a synchronous scan of the specified root paths. - public void Scan(DriveSelectResult result) { - if (result == null) - throw new ArgumentNullException(nameof(result)); - ThrowIfScanning(); - lock (threadLock) { - RootPaths = result.GetResultPaths(); - driveSelectResult = result; - ScanPrepare(false); - ScanThread(false, cancel.Token); - } - } - - /// Begins a asynchronous scan of the specified root paths. - public void ScanAsync(DriveSelectResult result) { - if (result == null) - throw new ArgumentNullException(nameof(result)); - ThrowIfScanning(); - lock (threadLock) { - RootPaths = result.GetResultPaths(); - driveSelectResult = result; - ScanPrepare(false); - scanThread = new Thread(() => ScanThread(false, cancel.Token)) { - Priority = settings.ScanPriority, - Name = "File Scan", - }; - scanThread.Start(); - } - } - - /// Closes the current scanned file tree. - /// - /// - /// Waits for the scan to fully close. DO NOT call this on the UI thread. - /// - public void Close(bool waitForClose = false) { - if (IsOpen) { - Cancel(waitForClose); - RootItem = null; - ClosedCleanup(); - ScanState = ScanState.NotStarted; - ProgressState = ScanProgressState.NotStarted; - Extensions.Clear(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - } - } - - /// - /// Closes the current scanned file tree if one exists and runs the callback if needed. - /// - /// - /// The callback to run after close has fininshed. - /// True if the callback is run when no file tree is open. - public void CloseAsync(Action callback, bool runWhenNotOpen = true) { - if (callback == null) - throw new ArgumentNullException(nameof(callback)); - if (IsScanning) { - CancelAsync(() => { - Close(true); - callback(); - }, true); - } - else if (IsOpen || runWhenNotOpen) { - Close(true); - callback(); - } - } - - /// Cancels the current scan if one exists. - /// - /// - /// Waits for the scan to fully complete. DO NOT call this on the UI thread. - /// - public void Cancel(bool waitForCancel = false) { - if (IsScanning && ScanState != ScanState.Cancelling) { - ScanState = ScanState.Cancelling; - CancellationTokenSource cancel = this.cancel; - ProgressState = ScanProgressState.Ending; - cancel.Cancel(); - // Make sure the wait handle resumes if suspended. - // Otherwise cancellation will never be reached. - IsSuspended = false; - while (waitForCancel && IsAsync) - Thread.Sleep(5); - } - } - - /// Cancels the current scan if one exists and runs the callback if needed. - /// - /// The callback to run after cancellation is fininshed. - /// True if the callback is run when no scan is running. - public void CancelAsync(Action callback, bool runWhenNotScanning = true) { - if (callback == null) - throw new ArgumentNullException(nameof(callback)); - CancelAsync((o, e) => callback(), runWhenNotScanning); - } - - /// Cancels the current scan if one exists and runs the callback if needed. - /// - /// The callback to run after cancellation is fininshed. - /// True if the callback is run when no scan is running. - public void CancelAsync(ScanEventHander callback, bool runWhenNotScanning = true) { - if (callback == null) - throw new ArgumentNullException(nameof(callback)); - if (IsScanning) { - if (ScanState != ScanState.Cancelling) { - Cancelled += new ScanEventHander(callback); - Cancel(false); - } - } - else if (runWhenNotScanning) { - callback(this, new ScanEventArgs(scanState, progressState)); - } - } - - #endregion - - #region Scan Prepare/Thread - - /// Prepares the scan before starting. - private void ScanPrepare(bool refreshing) { - lock (threadLock) { - IsSuspended = false; - IsRefreshing = refreshing; - refreshFiles = null; - CanDisplayProgress = false; - validateWatch.Reset(); - scanWatch.Reset(); - ProgressState = ScanProgressState.Starting; - ScanState = ScanState.Scanning; - TotalScannedSize = 0; - TotalSize = 0; - TotalFreeSpace = 0; - if (!refreshing) { - Extensions.Clear(); - RootItem = null; - } - validateWatch.Reset(); - RaisePropertyChanged(nameof(ScanTime)); - scanWatch.Start(); - cancel = new CancellationTokenSource(); - StartValidateTimer(); - } - } - - /// The root method for running the scan. - private void ScanThread(bool useRefreshFiles, CancellationToken token) { - Exception exception = null; - try { - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - if (useRefreshFiles) - Refresh(refreshFiles, token); - else - Scan(rootPaths, token); - RootItem?.FullValidate(); - } - catch (ThreadAbortException ex) { - exception = ex; - } - catch (Exception ex) { - Debug.WriteLine(ex); - exception = ex; - } - finally { - refreshFiles = null; - FinishedCleanup(); - StopValidateTimer(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - ProgressState = ScanProgressState.Ending; - cancel?.Dispose(); - cancel = null; - scanWatch?.Stop(); - scanThread = null; - - if (!disposed) { - RaisePropertyChanged(nameof(ScanTime)); - if (scanState == ScanState.Cancelling) { - // TODO: Should cancel remove all progress made? - //RootItem = null; - ScanState = ScanState.Cancelled; - } - else if (exception == null) { - ScanState = ScanState.Finished; - } - else { - RootItem = null; - ExceptionResult = exception; - ScanState = ScanState.Failed; - } - IsRefreshing = false; - ProgressState = ScanProgressState.Ended; - Ended?.Invoke(this, new ScanEventArgs(scanState, progressState, exception)); - if (scanState == ScanState.Cancelled) { - Cancelled?.Invoke(this, new ScanEventArgs(scanState, progressState, exception)); - Cancelled = null; - } - } - else { - IsRefreshing = false; - ExceptionResult = exception; - ScanState = ScanState.Failed; - } - } - } - - #endregion - - #region Root Space Properties - - /// Gets if free space items should be listed. - public bool ShowFreeSpace => settings.ShowFreeSpace; - /// Gets if unknown items should be listed. - public bool ShowUnknown => settings.ShowUnknown; - /// - /// Gets if free space and unknown items should be listed in the absolute or file root. - /// - public bool ShowTotalSpace => settings.ShowTotalSpace; - - #endregion - - #region Scan Properties - - /*/// Gets the result of the drive select dialog used for scanning. - public DriveSelectResult DriveSelectResult { - get => driveSelectResult; - set => Set(ref driveSelectResult, value); - }*/ - - /// Gets the root paths to scan. - public string[] RootPaths { - get => rootPaths; - set => Set(ref rootPaths, value); - } - - /// Gets the root item of the scanned/scanning file tree. - public RootItem RootItem { - get => VolatileGet(ref rootItem); - protected set { - lock (volatileLock) { - if (rootItem == value) - return; - // Unhooks the events from the IScanningService - rootItem?.Dispose(); - rootItem = value; - } - RaisePropertyChanged(); - } - } - - /// Gets how long the scan has been going on for. Or how long the scan took. - public TimeSpan ScanTime => scanWatch.Elapsed; - - /// Gets the amount of time taken to validate the file tree while scanning. - public TimeSpan ValidateTime => validateWatch.Elapsed; - - /// Gets the current state of the scan. - public ScanState ScanState { - get => scanState; - set { - bool suspendedChanged = false; - bool scanningChanged = false; - bool scanningNotRefreshingChanged = false; - bool finishedChanged = false; - bool openChanged = false; - lock (volatileLock) { - if (scanState == value) - return; - - bool suspendedBefore = IsSuspended; - bool scanningBefore = IsScanning; - bool scanningNotRefreshingBefore = IsScanningAndNotRefreshing; - bool finishedBefore = IsFinished; - bool openBefore = IsOpen; - - scanState = value; - - suspendedChanged = suspendedBefore != IsSuspended; - scanningChanged = scanningBefore != IsScanning; - scanningNotRefreshingChanged = scanningNotRefreshingBefore != IsScanningAndNotRefreshing; - finishedChanged = finishedBefore != IsFinished; - openChanged = openBefore != IsOpen; - - if (suspendedChanged) { - if (IsSuspended) - scanWatch.Stop(); - else - scanWatch.Start(); - } - } - RaisePropertyChanged(); - RaisePropertyChangedIf(suspendedChanged, nameof(IsSuspended)); - RaisePropertyChangedIf(scanningChanged, nameof(IsScanning)); - RaisePropertyChangedIf(scanningNotRefreshingChanged, nameof(IsScanningAndNotRefreshing)); - RaisePropertyChangedIf(finishedChanged, nameof(IsFinished)); - RaisePropertyChangedIf(openChanged, nameof(IsOpen)); - } - } - /// Gets the current progress state of the scan. - public ScanProgressState ProgressState { - get => VolatileGet(ref progressState); - protected set => VolatileSet(ref progressState, value); - } - - /// Gets if the scanner can guarantee some estimate of scan progress. - public bool CanDisplayProgress { - get => VolatileGet(ref canDisplayProgress); - protected set => VolatileSet(ref canDisplayProgress, value); - } - /// Gets the progress of the scan, or 1 if the scan is ended. - public double Progress { - get { - lock (volatileLock) { - if (canDisplayProgress) { - switch (progressState) { - case ScanProgressState.Started: - return (double) totalScannedSize / (totalSize - totalFreeSpace); - case ScanProgressState.Ending: - case ScanProgressState.Ended: - return 1d; - } - } - return 0d; - } - } - } - /// Gets if the scanner is scanning or cancelling a scan. - public bool IsScanning { - get { - lock (volatileLock) - return scanState == ScanState.Scanning || scanState == ScanState.Cancelling; - } - } - // Todo: We can probably remove this - /// Gets if the scanner is scanning or cancelling a scan, but not refreshing. - public bool IsScanningAndNotRefreshing { - get { - lock (volatileLock) - return (scanState == ScanState.Scanning || scanState == ScanState.Cancelling) && - !isRefreshing; - } - } - /// Gets if the scanner is refreshing. - public bool IsRefreshing { - get => VolatileGet(ref isRefreshing); - protected set => VolatileSet(ref isRefreshing, value); - } - /// Gets if the scanner has a successfully finished scan. - public bool IsFinished { - get => VolatileGet(ref scanState) == ScanState.Finished; - } - /// Gets if a finished or cancelled scanned file tree is open. - public bool IsOpen { - get { - lock (volatileLock) - return scanState == ScanState.Finished || scanState == ScanState.Cancelled; - } - } - /// Gets or sets if the current scan operation is suspended. - public bool IsSuspended { - get { - lock (resumeLock) { - if (!disposed) - return !resumeEvent.WaitOne(0); - } - return false; - } - set { - lock (resumeLock) { - lock (volatileLock) { - //if (!IsScanning) - // throw new InvalidOperationException("Cannot changed suspended state while not scanning!"); - if (IsSuspended == value) - return; - - if (!disposed) { - if (value) - resumeEvent.Reset(); - else - resumeEvent.Set(); - } - } - } - RaisePropertyChanged(); - } - } - /// Gets if an asynchronous scan thread is running. - public bool IsAsync { - get { - lock (volatileLock) - return scanThread != null && scanThread.IsAlive; - } - } - /// Gets if an asynchronous scan thread is running. - public Exception ExceptionResult { - get => VolatileGet(ref exceptionResult); - private set => VolatileSet(ref exceptionResult, value); - } - - /// Gets if the UI refreshing should be supressed due to validation. - public bool SuppressFileTreeRefresh { - get => VolatileGet(ref suppressRefresh); - private set => VolatileSet(ref suppressRefresh, value); - } - - #endregion - - #region IDisposable Implementation - - /// Disposes of the scanning service. - public void Dispose() { - if (!disposed) { - disposed = true; - scanThread?.Abort(); - validateTimer?.Dispose(); - resumeEvent.Dispose(); - } - } - - /// Disposes of the scanning service. - /*protected virtual void Dispose(bool disposing) { - }*/ - - #endregion - - #region Protected Properties - - /// Gets or sets the total size that has been scanned so far. - protected long TotalScannedSize { - get { lock (volatileLock) return totalScannedSize; } - set { lock (volatileLock) totalScannedSize = value; } - } - /// Gets or sets the total size for all scanned roots. - protected long TotalSize { - get { lock (volatileLock) return totalSize; } - set { lock (volatileLock) totalSize = value; } - } - /// Gets or sets the total free space for all scanned roots. - protected long TotalFreeSpace { - get { lock (volatileLock) return totalFreeSpace; } - set { lock (volatileLock) totalFreeSpace = value; } - } - - #endregion - - #region Protected Methods - - /// Checks if the scan operation is suspended and waits until resume if it is. - protected bool AsyncChecks(CancellationToken token) { - if (disposed) - return true; - - if (!resumeEvent.WaitOne(0)) { - StopValidateTimer(); - // Let's validate before suspension so that things are up to date - BasicValidate(); - resumeEvent.WaitOne(); - StartValidateTimer(); - validationRequested = false; - } - else if (validationRequested) { - StopValidateTimer(); - BasicValidate(); - StartValidateTimer(); - validationRequested = false; - } - return token.IsCancellationRequested; - } - - /// Performs a basic validation of the file tree being scanned. - private void BasicValidate() { - if (RootItem != null) { - ui.Invoke(() => { - Stopwatch validateWatch = Stopwatch.StartNew(); - SuppressFileTreeRefresh = true; - RootItem.BasicValidate(); - SuppressFileTreeRefresh = false; - TimeSpan validateTime = validateWatch.Elapsed; - Console.WriteLine($"Took {validateTime.TotalMilliseconds}ms to validate"); - }); - } - } - - #endregion - - #region Drives - - /// Scans and returns all valid drive items. - /// - /// All valid drive items. - public DriveItem[] ScanDrives() { - List drives = new List(); - DriveInfo[] driveInfos = DriveInfo.GetDrives(); - for (int i = 0; i < driveInfos.Length; i++) { - DriveInfo driveInfo = driveInfos[i]; - if (IsDriveValid(driveInfo)) - drives.Add(new DriveItem(driveInfo)); - } - return drives.ToArray(); - } - - /// Scans and returns all valid drive names. - /// - /// All valid drive names. - public string[] ScanDriveNames() { - List paths = new List(); - DriveInfo[] driveInfos = DriveInfo.GetDrives(); - for (int i = 0; i < driveInfos.Length; i++) { - DriveInfo driveInfo = driveInfos[i]; - if (IsDriveValid(driveInfo)) - paths.Add(driveInfo.Name); - } - return paths.ToArray(); - } - - /// Gets if the drive is valid for use. - /// - /// The drive to check. - /// True if the drive is valid. - public bool IsDriveValid(DriveInfo driveInfo) { - return driveInfo.IsReady && - driveInfo.DriveType != DriveType.Unknown && - driveInfo.DriveType != DriveType.NoRootDirectory; - } - - #endregion - - #region Abstract Methods - - /// Runs the scan process. - /// - /// The root paths to scan. - /// The scan cancellation token. - protected abstract void Scan(string[] rootPaths, CancellationToken token); - - protected abstract void Refresh(RefreshFiles[] refreshFiles, CancellationToken token); - - /// Cleanup called as a scan finishes. - protected abstract void FinishedCleanup(); - /// Cleanup called when a scanned file tree is closed. - protected abstract void ClosedCleanup(); - - #endregion - - #region File Management - - /// Permanently deletes the file. - /// - /// The path of the file to delete. - /// True if the operation was successful. - public bool DeleteFile(FileItemBase file) { - return DeleteOrRecycleFile(file, false); - } - - /// Sends the file or directory to the recycle bin. - /// - /// The path of the file to delete. - /// True if the operation was successful. - public bool RecycleFile(FileItemBase file) { - return DeleteOrRecycleFile(file, true); - } - - /// Deletes or recycles the file based on the conditional value. - /// - /// The path of the file to delete. - /// True if the file should be recycled. - /// True if the operation was successful. - public bool DeleteOrRecycleFile(FileItemBase file, bool recycle) { - ThrowIfScanning(); - if (!file.IsFileType || file.Type == FileItemType.Volume) - throw new InvalidOperationException("Can only delete files or folders"); - if (os.DeleteOrRecycleFile(file.FullName, recycle)) { - // File was successfully deleted, let's remove it from the file tree - // Set IsRefreshing to trigger any required UI invalidation - IsRefreshing = true; - FolderItem parent = file.Parent; - parent.RemoveItem(file); - parent.UpdwardsFullValidate(); - IsRefreshing = false; - return true; - } - return false; - } - - #endregion - - #region Public Refreshing - - /// Reloads the selected files. - /// - /// The files to reload. - public void RefreshFilesAsync(IEnumerable selectedFiles) { - if (!IsOpen) - throw new InvalidOperationException("No scan is open to refresh!"); - ThrowIfScanning(); - lock (threadLock) { - ScanPrepare(true); - scanThread = new Thread(() => RefreshThread(selectedFiles, cancel.Token)) { - Priority = settings.ScanPriority, - Name = "File Refresh", - }; - - // Measures to ensure garbage collection - //selectedFiles = null; - - scanThread.Start(); - } - } - - private void RefreshThread(IEnumerable selectedFiles, CancellationToken token) { - FileItemBase[] isolatedFiles = FolderItem.IsolateAncestores(selectedFiles); - if (isolatedFiles.Length > 0) { - if (isolatedFiles[0].IsAbsoluteRootType) { - // Just perform a full reload - ScanThread(false, token); - return; - } - - // Group all files into lists for each similar parent - Dictionary> refreshFilesMap = new Dictionary>(); - for (int i = 0; i < isolatedFiles.Length; i++) { - FileItemBase file = isolatedFiles[i]; - FolderItem parent = file.FileParent; - if (!refreshFilesMap.TryGetValue(parent, out List parentFiles)) { - parentFiles = new List(); - refreshFilesMap.Add(parent, parentFiles); - } - parentFiles.Add(file); - } - - // Convert the refresh files to an array - refreshFiles = new RefreshFiles[refreshFilesMap.Count]; - int index = 0; - foreach (var pair in refreshFilesMap) - refreshFiles[index++] = new RefreshFiles(pair); - - // Next remove the files' children from the tree - foreach (RefreshFiles parentFile in refreshFiles) { - FolderItem parent = parentFile.Parent; - FolderItem fileCollection = parent.GetFileCollection(); - int count = parentFile.Files.Count; - for (int i = 0; i < count; i++) { - if (parentFile.Files[i] is FolderItem folder) - folder.ClearItems(); - } - } - - // Measures to ensure garbage collection - selectedFiles = null; - isolatedFiles = null; - refreshFilesMap = null; - - if (AsyncChecks(token)) - return; - - ScanThread(true, token); - } - } - - /// Reloads the scanned file tree from the beginning. - public void ReloadAsync() { - if (!IsOpen) - throw new InvalidOperationException("No scan is open to reload!"); - ThrowIfScanning(); - lock (threadLock) { - ScanPrepare(true); - rootPaths = driveSelectResult.GetResultPaths(); - scanThread = new Thread(() => ScanThread(false, cancel.Token)) { - Priority = settings.ScanPriority, - Name = "File Reload", - }; - scanThread.Start(); - } - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/Implementation/SettingsService.Defaults.cs b/WinDirStat.Net.Base/Services/Implementation/SettingsService.Defaults.cs deleted file mode 100644 index f17dd39..0000000 --- a/WinDirStat.Net.Base/Services/Implementation/SettingsService.Defaults.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using WinDirStat.Net.Model.Drives; -using WinDirStat.Net.Rendering; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Structures; - -namespace WinDirStat.Net.Services { - partial class SettingsService { - /// The default file palette colors. - public static readonly ReadOnlyCollection DefaultFilePalette = - Array.AsReadOnly(new[] { - new Rgb24Color(0, 0, 255), - new Rgb24Color(255, 0, 0), - new Rgb24Color(0, 255, 0), - new Rgb24Color(0, 255, 255), - new Rgb24Color(255, 0, 255), - new Rgb24Color(255, 255, 0), - new Rgb24Color(150, 150, 255), - new Rgb24Color(255, 150, 150), - new Rgb24Color(150, 255, 150), - new Rgb24Color(150, 255, 255), - new Rgb24Color(255, 150, 255), - new Rgb24Color(255, 255, 150), - new Rgb24Color(255, 255, 255), - }); - - /// The default subtree percentage bar colors. - public static readonly ReadOnlyCollection DefaultSubtreePalette = - Array.AsReadOnly(new[] { - new Rgb24Color(64, 64, 140), - new Rgb24Color(140, 64, 64), - new Rgb24Color(64, 140, 64), - new Rgb24Color(140, 140, 64), - }); - - /*/// The default interval for updating the RAM usage. - public static readonly TimeSpan DefaultRAMInterval = TimeSpan.FromSeconds(1.0); - /// The default interval for updating the scan status. - public static readonly TimeSpan DefaultStatusInterval = TimeSpan.FromSeconds(0.05); - /// The default interval for updating the file tree in the UI. - public static readonly TimeSpan DefaultValidateInterval = TimeSpan.FromSeconds(2);*/ - - /// Resets the settings to their defaults. - public void Reset() { - // Drive Select - DriveSelectMode = DriveSelectMode.Individual; - SelectedDrives = new[] { @"C:\" }; - SelectedFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); - - // CPU Usage - ScanPriority = ThreadPriority.Highest; - RenderPriority = ThreadPriority.AboveNormal; - RAMInterval = TimeSpan.FromSeconds(1.0); - StatusInterval = TimeSpan.FromSeconds(0.05); - ValidateInterval = TimeSpan.FromSeconds(1); - - // Space Display - ShowFreeSpace = false; - ShowUnknown = false; - ShowTotalSpace = false; - - // UI Display - ShowFileTypes = true; - ShowTreemap = true; - ShowToolBar = true; - ShowStatusBar = true; - IconCacheMode = IconCacheMode.Individual; - - // Treemap - TreemapOptions = TreemapOptions.Default; - HighlightColor = Rgba32Color.White; - - // File Palette - SetFilePalette(DefaultFilePalette); - - // Subtree Percentage - SetSubtreePalette(DefaultSubtreePalette); - } - } -} diff --git a/WinDirStat.Net.Base/Services/Implementation/SettingsService.cs b/WinDirStat.Net.Base/Services/Implementation/SettingsService.cs deleted file mode 100644 index e6f70ba..0000000 --- a/WinDirStat.Net.Base/Services/Implementation/SettingsService.cs +++ /dev/null @@ -1,339 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; -using WinDirStat.Net.Model.Drives; -using WinDirStat.Net.Rendering; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Structures; - -namespace WinDirStat.Net.Services { - /// The service for containing all program settings. - public partial class SettingsService : ObservableObjectEx { - - #region Fields - - /// The UI service. - private readonly IUIService ui; - /// The bitmap factory service. - private readonly IBitmapFactory bitmapFactory; - /// The treemap renderer. - private readonly TreemapRenderer treemap; - - // Drive Select - /// The default mode for selecting paths to scan. - protected DriveSelectMode driveSelectMode; - /// The selected drives from the individual list. - protected string[] selectedDrives; - /// The selected folder path. - protected string selectedFolderPath; - - // CPU Usage - /// The thread priority for scanning the file tree. - protected ThreadPriority scanPriority; - /// The thread priority for rendering the treemap. - protected ThreadPriority renderPriority; - /// How often the RAM Usage is updated. - protected TimeSpan ramInterval; - /// How often the scan status is updated. - protected TimeSpan statusInterval; - /// How often the scanned file tree is updated in the UI. - protected TimeSpan validateInterval; - - // Space Display - /// True if free space items are displayed for drives. - protected bool showFreeSpace; - /// True if unknown space items are displayed for drives. - protected bool showUnknown; - /// - /// True if space items should show one single root item instead of one for each individual drive. - /// - protected bool showTotalSpace; - - // UI Display - /// True if the file types list should be shown. - protected bool showFileTypes; - /// True if the treemap should be shown. - protected bool showTreemap; - /// True if the tool bar should be shown. - protected bool showToolBar; - /// True if the status bar should be shown. - protected bool showStatusBar; - /// The setting for how icons are cached for file tree items. - protected IconCacheMode iconCacheMode; - - // Treemap - /// The options for how the treemap is rendered. - protected TreemapOptions treemapOptions; - /// The treemap highlight color. - protected Rgba32Color highlightColor; - - // File Palette - /// The array of the original (not equalized) file palette colors. - protected Rgb24Color[] filePalette = new Rgb24Color[0]; - /// The array of the prepared (equalized) file palette colors. - protected Rgb24Color[] equalizedFilePalette = new Rgb24Color[0]; - /// The array of file palette preview images. - protected IImage[] filePalettePreviews = new IImage[0]; - - // Subtree Palette - /// The array of subtree percentage bar colors. - protected Rgb24Color[] subtreePalette = new Rgb24Color[0]; - - #endregion - - #region Constructors - - /// Constructs the . - public SettingsService(IUIService ui, - IBitmapFactory bitmapFactory, - TreemapRendererFactory treemapFactory) - { - this.ui = ui; - this.bitmapFactory = bitmapFactory; - treemap = treemapFactory.Create(); - Reset(); - } - - #endregion - - #region Drive Select - - /// Gets or sets the default mode for selecting paths to scan. - public DriveSelectMode DriveSelectMode { - get => driveSelectMode; - set => Set(ref driveSelectMode, value); - } - - /// Gets or sets the selected drives from the individual list. - public string[] SelectedDrives { - get => selectedDrives; - set { - if (value == null || value.Any(s => string.IsNullOrEmpty(s))) - throw new ArgumentNullException(nameof(SelectedDrives)); - Set(ref selectedDrives, value); - } - } - - /// Gets or sets the selected folder path. - public string SelectedFolderPath { - get => selectedFolderPath; - set => Set(ref selectedFolderPath, value); - } - - #endregion - - #region CPU Usage - - /// Gets or sets the thread priority for scanning the file tree. - public ThreadPriority ScanPriority { - get => scanPriority; - set => Set(ref scanPriority, value); - } - - /// Gets or sets the thread priority for rendering the treemap. - public ThreadPriority RenderPriority { - get => renderPriority; - set => Set(ref renderPriority, value); - } - - /// Gets or sets how often the RAM Usage is updated. - public TimeSpan RAMInterval { - get => ramInterval; - set => Set(ref ramInterval, value); - } - - /// Gets or sets how often the scan status is updated. - public TimeSpan StatusInterval { - get => statusInterval; - set => Set(ref statusInterval, value); - } - - /// Gets or sets how often the scanned file tree is updated in the UI. - public TimeSpan ValidateInterval { - get => validateInterval; - set => Set(ref validateInterval, value); - } - - #endregion - - #region Space Display - - /// Gets or sets if free space items are displayed for drives. - public bool ShowFreeSpace { - get => showFreeSpace; - set => Set(ref showFreeSpace, value); - } - - /// Gets or sets if unknown space items are displayed for drives. - public bool ShowUnknown { - get => showUnknown; - set => Set(ref showUnknown, value); - } - - /// - /// Gets or sets if space items should show one single root item instead of one for each individual - /// drive. - /// - public bool ShowTotalSpace { - get => showTotalSpace; - set => Set(ref showTotalSpace, value); - } - - #endregion - - #region UI Display - - /// Gets or sets if the file types list should be shown. - public bool ShowFileTypes { - get => showFileTypes; - set => Set(ref showFileTypes, value); - } - - /// Gets or sets if the treemap should be shown. - public bool ShowTreemap { - get => showTreemap; - set => Set(ref showTreemap, value); - } - - /// Gets or sets if the tool bar should be shown. - public bool ShowToolBar { - get => showToolBar; - set => Set(ref showToolBar, value); - } - - /// Gets or sets if the status bar should be shown. - public bool ShowStatusBar { - get => showStatusBar; - set => Set(ref showStatusBar, value); - } - - /// Gets or sets the setting for how icons are cached for file tree items. - public IconCacheMode IconCacheMode { - get => iconCacheMode; - set => Set(ref iconCacheMode, value); - } - - #endregion - - #region Treemap - - /// Gets or sets the options for how the treemap is rendered. - public TreemapOptions TreemapOptions { - get => treemapOptions; - set { - treemapOptions = value; - UpdateFilePalettePreviews(); - RaisePropertyChanged(); - } - } - - /// Gets or sets the treemap highlight color. - public Rgba32Color HighlightColor { - get => highlightColor; - set => Set(ref highlightColor, value); - } - - /// Gets the array of the prepared (equalized) file palette colors. - public ReadOnlyCollection FilePalette { - get => Array.AsReadOnly(equalizedFilePalette); - } - - /// Gets the array of the original (not equalized) file palette colors. - public ReadOnlyCollection OriginalFilePalette { - get => Array.AsReadOnly(filePalette); - } - - /// Gets the array of file palette preview images. - public ReadOnlyCollection FilePalettePreviews { - get => Array.AsReadOnly(filePalettePreviews); - } - - /// Gets the file palette color at the specified index. - /// - /// The index of the extension in the list ordered by size descending. - /// The color of the file palette. - public Rgb24Color GetFilePaletteColor(int index) { - return equalizedFilePalette[Math.Min(index, equalizedFilePalette.Length - 1)]; - } - - /// Gets the file palette color preview image at the specified index. - /// - /// The index of the extension in the list ordered by size descending. - /// The preview image of the file palette color. - public IImage GetFilePalettePreview(int index) { - return filePalettePreviews[Math.Min(index, filePalettePreviews.Length - 1)]; - } - - /// Sets the new file palette colors. - /// - /// The new collection of colors to use. - public void SetFilePalette(IEnumerable filePalette) { - this.filePalette = filePalette.ToArray(); - this.equalizedFilePalette = ColorSpace.EqualizeColors(filePalette); - UpdateFilePalettePreviews(); - RaisePropertyChanged(nameof(FilePalette)); - RaisePropertyChanged(nameof(OriginalFilePalette)); - } - - #endregion - - #region Subtree Percentage - - /// Gets the array of subtree percentage bar colors. - public ReadOnlyCollection SubtreePalette { - get => Array.AsReadOnly(subtreePalette); - } - - /// Gets the subtree percentage bar color at the specified level. - /// - /// The 0-indexed level. - /// The color of the subtree percentage bar. - public Rgb24Color GetSubtreePaletteColor(int level) { - return subtreePalette[level % subtreePalette.Length]; - } - - /// Sets the new subtree percentage bar colors. - /// - /// The new collection of colors to use. - public void SetSubtreePalette(IEnumerable subtreePalette) { - this.subtreePalette = subtreePalette.ToArray(); - RaisePropertyChanged(nameof(SubtreePalette)); - } - - #endregion - - #region Private Methods - - /// Updates the file palette previews after a change has been made to the list. - protected void UpdateFilePalettePreviews() { - if (filePalettePreviews == null) - filePalettePreviews = new IImage[filePalette.Length]; - else if (filePalette.Length != filePalettePreviews.Length) - Array.Resize(ref filePalettePreviews, filePalette.Length); - for (int i = 0; i < filePalettePreviews.Length; i++) { - DrawFilePalettePreview(ref filePalettePreviews[i], equalizedFilePalette[i]); - } - RaisePropertyChanged(nameof(FilePalettePreviews)); - } - - /// Draws a single file palette preview. - /// - /// The image reference to update. - protected void DrawFilePalettePreview(ref IImage image, Rgb24Color color) { - IWriteableBitmap bitmap = (IWriteableBitmap) image; - if (bitmap == null) { - bitmap = bitmapFactory.CreateBitmap(new Point2I(256, 13)); - image = bitmap; - } - treemap.DrawColorPreview(bitmap, new Rectangle2I(256, 13), color); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/RelayCommandService.cs b/WinDirStat.Net.Base/Services/RelayCommandService.cs deleted file mode 100644 index fb62ffc..0000000 --- a/WinDirStat.Net.Base/Services/RelayCommandService.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.ViewModel; - -namespace WinDirStat.Net.Services { - /// A service for creating relay commands to be loaded by the view model. - public class RelayCommandService { - - #region Abstract Create - - /// - /// Creates a new with the specified info and functions. - /// - /// - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - IRelayCommand CreateCommand(Action execute, Func canExecute = null, - bool keepTargetAlive = false); - - /// - /// Creates a new with the specified info and functions. - /// - /// - /// The parameter type of the command. - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - IRelayCommand CreateCommand(Action execute, Func canExecute = null, - bool keepTargetAlive = false); - - /// - /// Creates a new with the specified info and functions. - /// - /// - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - IRelayUICommand CreateCommand(IRelayUICommandInfo info, Action execute, Func canExecute = null, - bool keepTargetAlive = false); - - /// - /// Creates a new with the specified info and functions. - /// - /// - /// The parameter type of the command. - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - IRelayUICommand CreateCommand(IRelayUICommandInfo info, Action execute, - Func canExecute = null, bool keepTargetAlive = false); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/IBrush.cs b/WinDirStat.Net.Base/Services/Structures/IBrush.cs deleted file mode 100644 index d49ba44..0000000 --- a/WinDirStat.Net.Base/Services/Structures/IBrush.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace WinDirStat.Net.Services.Structures { - /// An interface for a UI-independent brush. - public interface IBrush { - - /// Gets the actual brush object. - object Brush { get; } - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/IControl.cs b/WinDirStat.Net.Base/Services/Structures/IControl.cs deleted file mode 100644 index fcce779..0000000 --- a/WinDirStat.Net.Base/Services/Structures/IControl.cs +++ /dev/null @@ -1,25 +0,0 @@ - -namespace WinDirStat.Net.Services.Structures { - /// An interface for storing the control. - public interface IControl { - - #region Properties - - /// Gets the actual window object. - object Control { get; } - /// Gets the window that contains this control. - IWindow Window { get; } - - #endregion - - #region Equals - - /// Gets if the two controls are referencing the same control. - /// - /// The control wrapper to compare. - /// True if the interfaces are referencing the same control. - bool Equals(IControl control); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/IImage.cs b/WinDirStat.Net.Base/Services/Structures/IImage.cs deleted file mode 100644 index 9682a08..0000000 --- a/WinDirStat.Net.Base/Services/Structures/IImage.cs +++ /dev/null @@ -1,48 +0,0 @@ -using WinDirStat.Net.Structures; - -namespace WinDirStat.Net.Services.Structures { - /// An interface for a UI-independent image. - public interface IImage { - - #region Properties - - /// Gets the actual image object. - object Source { get; } - - #endregion - } - - /// An interface for a UI-independent bitmap. - public interface IBitmap : IImage { - - #region Properties - - /// Gets the width of the bitmap. - int Width { get; } - /// Gets the height of the bitmap. - int Height { get; } - /// Gets the size of the bitmap. - Point2I Size { get; } - /// Gets the bounds of the bitmap. - Rectangle2I Bounds { get; } - - #endregion - } - - /// An interface for a UI-independent bitmap with writeable pixels. - public interface IWriteableBitmap : IBitmap { - - #region Pixels - - /// Creates a new array of pixels for populating the bitmap. - Rgba32Color[] CreatePixels(); - /// Gets the bitmap's pixels. - Rgba32Color[] GetPixels(); - /// Sets the bitmap's pixels. - void SetPixels(Rgba32Color[] pixels); - /// Sets the bitmap's pixels. - unsafe void SetPixels(Rgba32Color* pixels); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/IRelayCommandInfo.Generic.cs b/WinDirStat.Net.Base/Services/Structures/IRelayCommandInfo.Generic.cs deleted file mode 100644 index ddeaffa..0000000 --- a/WinDirStat.Net.Base/Services/Structures/IRelayCommandInfo.Generic.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Windows.Input; -using WinDirStat.Net.ViewModel; - -namespace WinDirStat.Net.Services.Structures { - /// An interface with construction information for a . - public interface IRelayCommandInfo { - - /*#region Properties - - /// Gets an optional action to call before . - Action ExecuteBefore { get; } - /// Gets an optional action to call after . - Action ExecuteAfter { get; } - - /// Gets an optional function to call before . - Func CanExecuteBefore { get; } - /// Gets an optional function to call after . - Func CanExecuteAfter { get; } - - #endregion*/ - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/IRelayCommandInfo.cs b/WinDirStat.Net.Base/Services/Structures/IRelayCommandInfo.cs deleted file mode 100644 index 32e578e..0000000 --- a/WinDirStat.Net.Base/Services/Structures/IRelayCommandInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Windows.Input; -using WinDirStat.Net.ViewModel; - -namespace WinDirStat.Net.Services.Structures { - /// An interface with construction information for a . - public interface IRelayCommandInfo { - - /*#region Properties - - /// Gets an optional action to call before . - Action ExecuteBefore { get; } - /// Gets an optional action to call after . - Action ExecuteAfter { get; } - - /// Gets an optional function to call before . - Func CanExecuteBefore { get; } - /// Gets an optional function to call after . - Func CanExecuteAfter { get; } - - #endregion*/ - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/IRelayUICommandInfo.Generic.cs b/WinDirStat.Net.Base/Services/Structures/IRelayUICommandInfo.Generic.cs deleted file mode 100644 index 3d38b22..0000000 --- a/WinDirStat.Net.Base/Services/Structures/IRelayUICommandInfo.Generic.cs +++ /dev/null @@ -1,14 +0,0 @@ -using WinDirStat.Net.ViewModel; - -namespace WinDirStat.Net.Services.Structures { - /// An interface with construction information for a . - public interface IRelayUICommandInfo : IRelayCommandInfo { - - /// Gets the text to display for the command. - string Text { get; } - /// Gets the icon to display for the command. - IImage Icon { get; } - /// Gets the shortcut for the command. - IShortcut Shortcut { get; } - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/IRelayUICommandInfo.cs b/WinDirStat.Net.Base/Services/Structures/IRelayUICommandInfo.cs deleted file mode 100644 index 4f7c004..0000000 --- a/WinDirStat.Net.Base/Services/Structures/IRelayUICommandInfo.cs +++ /dev/null @@ -1,14 +0,0 @@ -using WinDirStat.Net.ViewModel; - -namespace WinDirStat.Net.Services.Structures { - /// An interface with construction information for a . - public interface IRelayUICommandInfo : IRelayCommandInfo { - - /// Gets the text to display for the command. - string Text { get; } - /// Gets the icon to display for the command. - IImage Icon { get; } - /// Gets the shortcut for the command. - IShortcut Shortcut { get; } - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/IShortcut.cs b/WinDirStat.Net.Base/Services/Structures/IShortcut.cs deleted file mode 100644 index 50d332c..0000000 --- a/WinDirStat.Net.Base/Services/Structures/IShortcut.cs +++ /dev/null @@ -1,15 +0,0 @@ - -namespace WinDirStat.Net.Services.Structures { - /// An interface for a shortcut implementation. - public interface IShortcut { - - /// The actual shortcut object. - object Shortcut { get; } - - /// Gets the display text for the shortcut. - string DisplayText { get; } - - /// Gets the display image for the shortcut. - IImage DisplayImage { get; } - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/IUITimer.cs b/WinDirStat.Net.Base/Services/Structures/IUITimer.cs deleted file mode 100644 index 61fd84c..0000000 --- a/WinDirStat.Net.Base/Services/Structures/IUITimer.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; - -namespace WinDirStat.Net.Services.Structures { - /// An interface for a UI timer. - public interface IUITimer { - - #region Properties - - /// Gets or sets the callback method for the timer. - Action Callback { get; set; } - /// Gets or sets the interval for the timer. - TimeSpan Interval { get; set; } - /// Gets or sets if the timer is running. - bool IsRunning { get; set; } - - #endregion - - #region Start/Stop - - /// Starts the timer. - void Start(); - /// Stops the timer. - void Stop(); - /// Restarts the timer. - void Restart(); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/IWindow.cs b/WinDirStat.Net.Base/Services/Structures/IWindow.cs deleted file mode 100644 index 57dce52..0000000 --- a/WinDirStat.Net.Base/Services/Structures/IWindow.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; - -namespace WinDirStat.Net.Services.Structures { - /// An interface for storing the window. - public interface IWindow { - - #region Properties - - /// Gets the actual window object. - object Window { get; } - /// Gets the window that owns this window. - IWindow Owner { get; } - /// Gets the children owned by this window. - IWindow[] Children { get; } - /// Gets the handle for the window. - IntPtr Handle { get; } - /// Gets or sets the dialog result. - bool DialogResult { get; set; } - - #endregion - - #region Close - - /// Closes the window. - void Close(); - - /// Called when the window is closed. - event EventHandler Closed; - - #endregion - - #region Equals - - /// Gets if the two windows are referencing the same window. - /// - /// The window wrapper to compare. - /// True if the interfaces are referencing the same window. - bool Equals(IWindow window); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/Implementation/IconCache.cs b/WinDirStat.Net.Base/Services/Structures/Implementation/IconCache.cs deleted file mode 100644 index d9b4bfe..0000000 --- a/WinDirStat.Net.Base/Services/Structures/Implementation/IconCache.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.ComponentModel; - -namespace WinDirStat.Net.Services.Structures { - /// How icons are stored and displayed. - [Serializable] - public enum IconCacheMode : byte { - /// Don't show icons. - [Description("Don't show icons")] - None, - /// Use default icons (File/Folder/Drive/Computer). - [Description("Use default icons")] - Basic, - /// Use file type icons. - [Description("Use file type icons")] - FileType, - /// Use individual icons. - [Description("Individual icons")] - Individual, - /// Use individual icons with overlays. - //[Description("Individual icons with overlays")] - //IndividualOverlays, - } - - /// The states for caching an icon. - public enum IconCacheState : byte { - /// The icon has not been cached yet. - NotCached, - /// An asynchronous operation is running to cache the icon. - Caching, - /// The icon has been cached at its highest level. - Cached, - } - - /// A structure containing both a cached icon and name. - public class IIconAndName { - /// The returned icon. - public IImage Icon { get; } - /// The returned name. - public string Name { get; } - - /// Constructs a new . - /// - /// The icon to use. - /// The name to use. - public IIconAndName(IImage icon, string name) { - Icon = icon; - Name = name; - } - } - - /// The callback delegate for caching an icon. - /// - /// The returned icon. - public delegate void ICacheIconCallback(IImage icon); - /// The callback delegate for caching an icon and name. - /// - /// The returned icon and name. - public delegate void ICacheIconAndNameCallback(IIconAndName iconName); -} diff --git a/WinDirStat.Net.Base/Services/Structures/Implementation/Message.cs b/WinDirStat.Net.Base/Services/Structures/Implementation/Message.cs deleted file mode 100644 index f573308..0000000 --- a/WinDirStat.Net.Base/Services/Structures/Implementation/Message.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Services.Structures { - /// Specifies result from a dialog message box. - public enum MessageResult { - /// The message box returns no result. - None = 0, - /// The result value of the message box is OK. - OK = 1, - /// The result value of the message box is Cancel. - Cancel = 2, - /// The result value of the message box is Yes. - Yes = 6, - /// The result value of the message box is No. - No = 7, - } - - /// Specifies the buttons that are displayed on a dialog message. - public enum MessageButton { - /// The message box displays an OK button. - OK = 0, - /// The message box displays OK and Cancel buttons. - OKCancel = 1, - /// The message box displays Yes and No buttons. - YesNo = 4, - /// The message box displays Yes, No, and Cancel buttons. - YesNoCancel = 3, - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/Implementation/RecyleBinInfo.cs b/WinDirStat.Net.Base/Services/Structures/Implementation/RecyleBinInfo.cs deleted file mode 100644 index 22b4bb2..0000000 --- a/WinDirStat.Net.Base/Services/Structures/Implementation/RecyleBinInfo.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Services.Structures { - /// Information on the contents of the Recycle Bin. - public class RecycleBinInfo { - /// Gets the owner of the Recycle Bin. May be null. - public string Owner { get; } - /// Gets the total number of items in the Recycle Bin. - public long ItemCount { get; } - /// Gets the total size of all items in the Recycle Bin. - public long Size { get; } - - /// Constructs the . - /// - /// The total number of items in the Recycle Bin. - /// The total size of items in the Recycle Bin. - public RecycleBinInfo(long itemCount, long size) { - ItemCount = itemCount; - Size = size; - } - - /// Constructs the . - /// - /// The owner of the Recycle Bin. Can be null. - /// The total number of items in the Recycle Bin. - /// The total size of items in the Recycle Bin. - public RecycleBinInfo(string owner, long itemCount, long size) { - Owner = owner; - ItemCount = itemCount; - Size = size; - } - } -} diff --git a/WinDirStat.Net.Base/Services/Structures/Implementation/Scanning.cs b/WinDirStat.Net.Base/Services/Structures/Implementation/Scanning.cs deleted file mode 100644 index 846ee0d..0000000 --- a/WinDirStat.Net.Base/Services/Structures/Implementation/Scanning.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Services.Structures { - /// The scan states for . - [Serializable] - public enum ScanState { - /// The scan has not started, or the last scan has been closed. - NotStarted, - /// A scan is currently in progress. - Scanning, - /// The current scan is suspended. - Suspended, - /// The last scan has finished and is still open. - Finished, - /// The scan is being canceled and has not ended yet. - Cancelling, - /// The last scan was cancelled. - Cancelled, - /// The last scan failed. - Failed, - } - - /// The scan progress states for . - [Serializable] - public enum ScanProgressState { - /// The scan has not started, or the last scan has been closed. - NotStarted, - /// The scan is preparing to start. - Starting, - /// The scan has fully started. - Started, - /// The scan is preparing to end. - Ending, - /// The scan has fully ended. - Ended, - } - - /// Event args for a event. - public class ScanEventArgs { - /// The current scan state. - public ScanState ScanState { get; } - /// The current scan progress state. - public ScanProgressState ProgressState { get; } - /// The exception that occurred during a failed scan. - public Exception Exception { get; } - - /// Constructs the without an exception. - public ScanEventArgs(ScanState state, ScanProgressState progress) { - ScanState = state; - ProgressState = progress; - Exception = null; - } - - /// Constructs the with an exception. - public ScanEventArgs(ScanState state, ScanProgressState progress, Exception exception) { - ScanState = state; - ProgressState = progress; - Exception = exception; - } - } - - /// Event handler for a event. - public delegate void ScanEventHander(object sender, ScanEventArgs e); -} diff --git a/WinDirStat.Net.Base/StringConstants.cs b/WinDirStat.Net.Base/StringConstants.cs deleted file mode 100644 index dcc641f..0000000 --- a/WinDirStat.Net.Base/StringConstants.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net { - public static class StringConstants { - - public const string FileName = "File"; - - public const string ComputerName = "Computer"; - public const string FileCollectionName = ""; - public const string FreeSpaceName = ""; - public const string UnknownName = ""; - } -} diff --git a/WinDirStat.Net.Base/Structures/Point2D.cs b/WinDirStat.Net.Base/Structures/Point2D.cs deleted file mode 100644 index 8e712a7..0000000 --- a/WinDirStat.Net.Base/Structures/Point2D.cs +++ /dev/null @@ -1,275 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using WinDirStat.Net.Utils; - -namespace WinDirStat.Net.Structures { - /// Point structure for double floating point 2D positions (X, Y). - [Serializable] - [StructLayout(LayoutKind.Sequential)] - public struct Point2D { - - #region Constants - - /// Returns a point positioned at (0, 0). - public static readonly Point2D Zero = new Point2D(0, 0); - /// Returns a point positioned at (0.5, 0.5). - public static readonly Point2D Half = new Point2D(0.5d, 0.5d); - /// Returns a point positioned at (0.5, 0). - public static readonly Point2D HalfX = new Point2D(0.5d, 0); - /// Returns a point positioned at (0, 0.5). - public static readonly Point2D HalfY = new Point2D(0, 0.5d); - /// Returns a point positioned at (1, 1). - public static readonly Point2D One = new Point2D(1, 1); - /// Returns a point positioned at (1, 0). - public static readonly Point2D OneX = new Point2D(1, 0); - /// Returns a point positioned at (0, 1). - public static readonly Point2D OneY = new Point2D(0, 1); - - #endregion - - #region Fields - - /// X coordinate of this point. - public double X; - /// Y coordinate of this point. - public double Y; - - #endregion - - #region Constructors - - /// Constructs a from the X and Y coordinates. - /// The X coordinate to use. - /// The Y coordinate to use. - public Point2D(double x, double y) { - X = x; - Y = y; - } - - /// Constructs a from the same coordinates. - /// The X and Y coordinate to use. - public Point2D(double uniform) { - X = uniform; - Y = uniform; - } - - #endregion - - #region Static Constructors - - /// Constructs a from polar coordinates. - /// The length of the polar point. - /// The radians of the polar point. - /// The constructed . - public static Point2D FromPolarRad(double length, double radians) { - if (length == 0) - return Zero; - return new Point2D( - (double) (length * Math.Cos(radians)), - (double) (length * Math.Sin(radians))); - } - - /// Constructs a from polar coordinates. - /// The length of the polar point. - /// The degrees of the polar point. - /// The constructed . - public static Point2D FromPolarDeg(double length, double degrees) { - return FromPolarRad(length, MathUtils.DegToRad(degrees)); - } - - #endregion - - #region Object Overrides - - /// Convert to a human-readable string. - public override string ToString() => $"(X={X} Y={Y})"; - - /// Returns the hash code of this point. - public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode(); - - /// Checks if the point is equal to the other point. - public override bool Equals(object obj) { - switch (obj) { - case Point2I pt2i: return this == pt2i; - case Point2F pt2f: return this == pt2f; - case Point2D pt2d: return this == pt2d; - default: return false; - } - } - - #endregion - - #region Operators - - #region Unary Arithmetic Operators - - public static Point2D operator +(Point2D a) => a; - public static Point2D operator -(Point2D a) => new Point2D(-a.X, -a.Y); - - public static Point2D operator ++(Point2D a) => new Point2D(++a.X, ++a.Y); - public static Point2D operator --(Point2D a) => new Point2D(--a.X, --a.Y); - - #endregion - - #region Binary Arithmetic Operators - - public static Point2D operator +(Point2D a, Point2D b) => new Point2D(a.X + b.X, a.Y + b.Y); - public static Point2D operator +(Point2D a, double b) => new Point2D(a.X + b, a.Y + b ); - public static Point2D operator +(double a, Point2D b) => new Point2D(a + b.X, a + b.Y); - - public static Point2D operator -(Point2D a, Point2D b) => new Point2D(a.X - b.X, a.Y - b.Y); - public static Point2D operator -(Point2D a, double b) => new Point2D(a.X - b, a.Y - b ); - public static Point2D operator -(double a, Point2D b) => new Point2D(a - b.X, a - b.Y); - - public static Point2D operator *(Point2D a, Point2D b) => new Point2D(a.X * b.X, a.Y * b.Y); - public static Point2D operator *(Point2D a, double b) => new Point2D(a.X * b, a.Y * b ); - public static Point2D operator *(double a, Point2D b) => new Point2D(a * b.X, a * b.Y); - - public static Point2D operator /(Point2D a, Point2D b) => new Point2D(a.X / b.X, a.Y / b.Y); - public static Point2D operator /(Point2D a, double b) => new Point2D(a.X / b, a.Y / b ); - public static Point2D operator /(double a, Point2D b) => new Point2D(a / b.X, a / b.Y); - - public static Point2D operator %(Point2D a, Point2D b) => new Point2D(a.X % b.X, a.Y % b.Y); - public static Point2D operator %(Point2D a, double b) => new Point2D(a.X % b, a.Y % b ); - public static Point2D operator %(double a, Point2D b) => new Point2D(a % b.X, a % b.Y); - - #endregion - - #region Binary Logic Operators - - public static bool operator ==(Point2D a, Point2D b) => (a.X == b.X && a.Y == b.Y); - public static bool operator ==(Point2D a, double b) => (a.X == b && a.Y == b ); - public static bool operator ==(double a, Point2D b) => (a == b.X && a == b.Y); - - public static bool operator !=(Point2D a, Point2D b) => (a.X != b.X || a.Y != b.Y); - public static bool operator !=(Point2D a, double b) => (a.X != b || a.Y != b ); - public static bool operator !=(double a, Point2D b) => (a != b.X || a != b.Y); - - public static bool operator <(Point2D a, Point2D b) => (a.X < b.X && a.Y < b.Y); - public static bool operator <(Point2D a, double b) => (a.X < b && a.Y < b ); - public static bool operator <(double a, Point2D b) => (a < b.X && a < b.Y); - - public static bool operator >(Point2D a, Point2D b) => (a.X > b.X && a.Y > b.Y); - public static bool operator >(Point2D a, double b) => (a.X > b && a.Y > b ); - public static bool operator >(double a, Point2D b) => (a > b.X && a > b.Y); - - public static bool operator <=(Point2D a, Point2D b) => (a.X <= b.X && a.Y <= b.Y); - public static bool operator <=(Point2D a, double b) => (a.X <= b && a.Y <= b ); - public static bool operator <=(double a, Point2D b) => (a <= b.X && a <= b.Y); - - public static bool operator >=(Point2D a, Point2D b) => (a.X >= b.X && a.Y >= b.Y); - public static bool operator >=(Point2D a, double b) => (a.X >= b && a.Y >= b ); - public static bool operator >=(double a, Point2D b) => (a >= b.X && a >= b.Y); - - #endregion - - #endregion - - #region Casting - - /// Casts the to a . - public static implicit operator Point2D(Point2I point) { - return new Point2D(point.X, point.Y); - } - - /// Casts the to a . - public static implicit operator Point2D(Point2F point) { - return new Point2D(point.X, point.Y); - } - - /// Casts the to a . - public static explicit operator Point2I(Point2D point) { - return new Point2I((int) point.X, (int) point.Y); - } - - /// Casts the to a . - public static explicit operator Point2F(Point2D point) { - return new Point2F((float) point.X, (float) point.Y); - } - - #endregion - - #region Properties - - /// Gets or sets the direction of the point in degrees. - public double DirectionDeg { - get { - if (IsZero) - return 0; - return (double) MathUtils.RadToDeg(Math.Atan2(Y, X)); - } - set { - if (!IsZero) { - double length = Length; - X = (double) (length * Math.Cos(value)); - Y = (double) (length * Math.Sin(value)); - } - } - } - - /// Gets or sets the direction of the point in radians. - public double DirectionRad { - get { - if (IsZero) - return 0; - return (double) Math.Atan2(Y, X); - } - set { - if (!IsZero) { - double radians = MathUtils.DegToRad(value); - double length = Length; - X = (double) (length * Math.Cos(radians)); - Y = (double) (length * Math.Sin(radians)); - } - } - } - - /// Gets or sets the length of the point. - public double Length { - get => (double) Math.Sqrt((X * X) + (Y * Y)); - set { - if (!IsZero) { - double oldLength = Length; - X *= value / oldLength; - Y *= value / oldLength; - } - else { - X = value; - Y = 0; - } - } - } - - /// Gets the squared length of the point. - public double LengthSquared => ((X * X) + (Y * Y)); - - /// Gets the coordinate at the specified index. - public double this[int index] { - get { - switch (index) { - case 0: return X; - case 1: return Y; - default: throw new ArgumentOutOfRangeException(nameof(index)); - } - } - set { - switch (index) { - case 0: X = value; return; - case 1: Y = value; return; - default: throw new ArgumentOutOfRangeException(nameof(index)); - } - } - } - - /// Returns true if the point is positioned at (0, 0). - public bool IsZero => (X == 0 && Y == 0); - - /// Returns true if either X or Y is positioned at 0. - public bool IsAnyZero => (X == 0 || Y == 0); - - /// Returns the perpendicular point. - public Point2D Perpendicular => new Point2D(-Y, X); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Structures/Point2F.cs b/WinDirStat.Net.Base/Structures/Point2F.cs deleted file mode 100644 index 0b89c06..0000000 --- a/WinDirStat.Net.Base/Structures/Point2F.cs +++ /dev/null @@ -1,265 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using WinDirStat.Net.Utils; - -namespace WinDirStat.Net.Structures { - /// Point structure for floating point 2D positions (X, Y). - [Serializable] - [StructLayout(LayoutKind.Sequential)] - public struct Point2F { - - #region Constants - - /// Returns a point positioned at (0, 0). - public static readonly Point2F Zero = new Point2F(0, 0); - /// Returns a point positioned at (0.5, 0.5). - public static readonly Point2F Half = new Point2F(0.5f, 0.5f); - /// Returns a point positioned at (0.5, 0). - public static readonly Point2F HalfX = new Point2F(0.5f, 0); - /// Returns a point positioned at (0, 0.5). - public static readonly Point2F HalfY = new Point2F(0, 0.5f); - /// Returns a point positioned at (1, 1). - public static readonly Point2F One = new Point2F(1, 1); - /// Returns a point positioned at (1, 0). - public static readonly Point2F OneX = new Point2F(1, 0); - /// Returns a point positioned at (0, 1). - public static readonly Point2F OneY = new Point2F(0, 1); - - #endregion - - #region Fields - - /// X coordinate of this point. - public float X; - /// Y coordinate of this point. - public float Y; - - #endregion - - #region Constructors - - /// Constructs a from the X and Y coordinates. - /// The X coordinate to use. - /// The Y coordinate to use. - public Point2F(float x, float y) { - X = x; - Y = y; - } - - /// Constructs a from the same coordinates. - /// The X and Y coordinate to use. - public Point2F(float uniform) { - X = uniform; - Y = uniform; - } - - #endregion - - #region Static Constructors - - /// Constructs a from polar coordinates. - /// The length of the polar point. - /// The radians of the polar point. - /// The constructed . - public static Point2F FromPolarRad(float length, float radians) { - if (length == 0) - return Zero; - return new Point2F( - (float) (length * Math.Cos(radians)), - (float) (length * Math.Sin(radians))); - } - - /// Constructs a from polar coordinates. - /// The length of the polar point. - /// The degrees of the polar point. - /// The constructed . - public static Point2F FromPolarDeg(float length, float degrees) { - return FromPolarRad(length, MathUtils.DegToRad(degrees)); - } - - #endregion - - #region Object Overrides - - /// Convert to a human-readable string. - public override string ToString() => $"(X={X} Y={Y})"; - - /// Returns the hash code of this point. - public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode(); - - /// Checks if the point is equal to the other point. - public override bool Equals(object obj) { - switch (obj) { - case Point2I pt2i: return this == pt2i; - case Point2F pt2f: return this == pt2f; - case Point2D pt2d: return this == pt2d; - default: return false; - } - } - - #endregion - - #region Operators - - #region Unary Arithmetic Operators - - public static Point2F operator +(Point2F a) => a; - public static Point2F operator -(Point2F a) => new Point2F(-a.X, -a.Y); - - public static Point2F operator ++(Point2F a) => new Point2F(++a.X, ++a.Y); - public static Point2F operator --(Point2F a) => new Point2F(--a.X, --a.Y); - - #endregion - - #region Binary Arithmetic Operators - - public static Point2F operator +(Point2F a, Point2F b) => new Point2F(a.X + b.X, a.Y + b.Y); - public static Point2F operator +(Point2F a, float b) => new Point2F(a.X + b, a.Y + b ); - public static Point2F operator +(float a, Point2F b) => new Point2F(a + b.X, a + b.Y); - - public static Point2F operator -(Point2F a, Point2F b) => new Point2F(a.X - b.X, a.Y - b.Y); - public static Point2F operator -(Point2F a, float b) => new Point2F(a.X - b, a.Y - b ); - public static Point2F operator -(float a, Point2F b) => new Point2F(a - b.X, a - b.Y); - - public static Point2F operator *(Point2F a, Point2F b) => new Point2F(a.X * b.X, a.Y * b.Y); - public static Point2F operator *(Point2F a, float b) => new Point2F(a.X * b, a.Y * b ); - public static Point2F operator *(float a, Point2F b) => new Point2F(a * b.X, a * b.Y); - - public static Point2F operator /(Point2F a, Point2F b) => new Point2F(a.X / b.X, a.Y / b.Y); - public static Point2F operator /(Point2F a, float b) => new Point2F(a.X / b, a.Y / b ); - public static Point2F operator /(float a, Point2F b) => new Point2F(a / b.X, a / b.Y); - - public static Point2F operator %(Point2F a, Point2F b) => new Point2F(a.X % b.X, a.Y % b.Y); - public static Point2F operator %(Point2F a, float b) => new Point2F(a.X % b, a.Y % b ); - public static Point2F operator %(float a, Point2F b) => new Point2F(a % b.X, a % b.Y); - - #endregion - - #region Binary Logic Operators - - public static bool operator ==(Point2F a, Point2F b) => (a.X == b.X && a.Y == b.Y); - public static bool operator ==(Point2F a, float b) => (a.X == b && a.Y == b ); - public static bool operator ==(float a, Point2F b) => (a == b.X && a == b.Y); - - public static bool operator !=(Point2F a, Point2F b) => (a.X != b.X || a.Y != b.Y); - public static bool operator !=(Point2F a, float b) => (a.X != b || a.Y != b ); - public static bool operator !=(float a, Point2F b) => (a != b.X || a != b.Y); - - public static bool operator <(Point2F a, Point2F b) => (a.X < b.X && a.Y < b.Y); - public static bool operator <(Point2F a, float b) => (a.X < b && a.Y < b ); - public static bool operator <(float a, Point2F b) => (a < b.X && a < b.Y); - - public static bool operator >(Point2F a, Point2F b) => (a.X > b.X && a.Y > b.Y); - public static bool operator >(Point2F a, float b) => (a.X > b && a.Y > b ); - public static bool operator >(float a, Point2F b) => (a > b.X && a > b.Y); - - public static bool operator <=(Point2F a, Point2F b) => (a.X <= b.X && a.Y <= b.Y); - public static bool operator <=(Point2F a, float b) => (a.X <= b && a.Y <= b ); - public static bool operator <=(float a, Point2F b) => (a <= b.X && a <= b.Y); - - public static bool operator >=(Point2F a, Point2F b) => (a.X >= b.X && a.Y >= b.Y); - public static bool operator >=(Point2F a, float b) => (a.X >= b && a.Y >= b ); - public static bool operator >=(float a, Point2F b) => (a >= b.X && a >= b.Y); - - #endregion - - #endregion - - #region Casting - - /// Casts the to a . - public static implicit operator Point2F(Point2I point) { - return new Point2F(point.X, point.Y); - } - - /// Casts the to a . - public static explicit operator Point2I(Point2F point) { - return new Point2I((int) point.X, (int) point.Y); - } - - #endregion - - #region Properties - - /// Gets or sets the direction of the point in degrees. - public float DirectionDeg { - get { - if (IsZero) - return 0; - return (float) MathUtils.RadToDeg(Math.Atan2(Y, X)); - } - set { - if (!IsZero) { - float length = Length; - X = (float) (length * Math.Cos(value)); - Y = (float) (length * Math.Sin(value)); - } - } - } - - /// Gets or sets the direction of the point in radians. - public float DirectionRad { - get { - if (IsZero) - return 0; - return (float) Math.Atan2(Y, X); - } - set { - if (!IsZero) { - double radians = MathUtils.DegToRad(value); - float length = Length; - X = (float) (length * Math.Cos(radians)); - Y = (float) (length * Math.Sin(radians)); - } - } - } - - /// Gets or sets the length of the point. - public float Length { - get => (float) Math.Sqrt((X * X) + (Y * Y)); - set { - if (!IsZero) { - float oldLength = Length; - X *= value / oldLength; - Y *= value / oldLength; - } - else { - X = value; - Y = 0; - } - } - } - - /// Gets the squared length of the point. - public float LengthSquared => ((X * X) + (Y * Y)); - - /// Gets the coordinate at the specified index. - public float this[int index] { - get { - switch (index) { - case 0: return X; - case 1: return Y; - default: throw new ArgumentOutOfRangeException(nameof(index)); - } - } - set { - switch (index) { - case 0: X = value; return; - case 1: Y = value; return; - default: throw new ArgumentOutOfRangeException(nameof(index)); - } - } - } - - /// Returns true if the point is positioned at (0, 0). - public bool IsZero => (X == 0 && Y == 0); - - /// Returns true if either X or Y is positioned at 0. - public bool IsAnyZero => (X == 0 || Y == 0); - - /// Returns the perpendicular point. - public Point2F Perpendicular => new Point2F(-Y, X); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Structures/Point2I.cs b/WinDirStat.Net.Base/Structures/Point2I.cs deleted file mode 100644 index 248bb1d..0000000 --- a/WinDirStat.Net.Base/Structures/Point2I.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace WinDirStat.Net.Structures { - /// Point structure for integer 2D positions (X, Y). - [Serializable] - [StructLayout(LayoutKind.Sequential)] - public struct Point2I { - - #region Constants - - /// Returns a point positioned at (0, 0). - public static readonly Point2I Zero = new Point2I(0, 0); - /// Returns a point positioned at (1, 1). - public static readonly Point2I One = new Point2I(1, 1); - /// Returns a point positioned at (1, 0). - public static readonly Point2I OneX = new Point2I(1, 0); - /// Returns a point positioned at (0, 1). - public static readonly Point2I OneY = new Point2I(0, 1); - - #endregion - - #region Fields - - /// X coordinate of this point. - public int X; - /// Y coordinate of this point. - public int Y; - - #endregion - - #region Constructors - - /// Constructs a from the X and Y coordinates. - /// The X coordinate to use. - /// The Y coordinate to use. - public Point2I(int x, int y) { - X = x; - Y = y; - } - - /// Constructs a from the same coordinates. - /// The X and Y coordinate to use. - public Point2I(int uniform) { - X = uniform; - Y = uniform; - } - - #endregion - - #region Object Overrides - - /// Convert to a human-readable string. - public override string ToString() => $"(X={X} Y={Y})"; - - /// Returns the hash code of this point. - public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode(); - - /// Checks if the point is equal to the other point. - public override bool Equals(object obj) { - switch (obj) { - case Point2I pt2i: return this == pt2i; - case Point2F pt2f: return this == pt2f; - case Point2D pt2d: return this == pt2d; - default: return false; - } - } - - #endregion - - #region Operators - - #region Unary Arithmetic Operators - - public static Point2I operator +(Point2I a) => a; - public static Point2I operator -(Point2I a) => new Point2I(-a.X, -a.Y); - - public static Point2I operator ++(Point2I a) => new Point2I(++a.X, ++a.Y); - public static Point2I operator --(Point2I a) => new Point2I(--a.X, --a.Y); - - #endregion - - #region Binary Arithmetic Operators - - public static Point2I operator +(Point2I a, Point2I b) => new Point2I(a.X + b.X, a.Y + b.Y); - public static Point2I operator +(Point2I a, int b) => new Point2I(a.X + b, a.Y + b ); - public static Point2I operator +(int a, Point2I b) => new Point2I(a + b.X, a + b.Y); - - public static Point2I operator -(Point2I a, Point2I b) => new Point2I(a.X - b.X, a.Y - b.Y); - public static Point2I operator -(Point2I a, int b) => new Point2I(a.X - b, a.Y - b ); - public static Point2I operator -(int a, Point2I b) => new Point2I(a - b.X, a - b.Y); - - public static Point2I operator *(Point2I a, Point2I b) => new Point2I(a.X * b.X, a.Y * b.Y); - public static Point2I operator *(Point2I a, int b) => new Point2I(a.X * b, a.Y * b ); - public static Point2I operator *(int a, Point2I b) => new Point2I(a * b.X, a * b.Y); - - public static Point2I operator /(Point2I a, Point2I b) => new Point2I(a.X / b.X, a.Y / b.Y); - public static Point2I operator /(Point2I a, int b) => new Point2I(a.X / b, a.Y / b ); - public static Point2I operator /(int a, Point2I b) => new Point2I(a / b.X, a / b.Y); - - public static Point2I operator %(Point2I a, Point2I b) => new Point2I(a.X % b.X, a.Y % b.Y); - public static Point2I operator %(Point2I a, int b) => new Point2I(a.X % b, a.Y % b ); - public static Point2I operator %(int a, Point2I b) => new Point2I(a % b.X, a % b.Y); - - #endregion - - #region Binary Logic Operators - - public static bool operator ==(Point2I a, Point2I b) => (a.X == b.X && a.Y == b.Y); - public static bool operator ==(Point2I a, int b) => (a.X == b && a.Y == b ); - public static bool operator ==(int a, Point2I b) => (a == b.X && a == b.Y); - - public static bool operator !=(Point2I a, Point2I b) => (a.X != b.X || a.Y != b.Y); - public static bool operator !=(Point2I a, int b) => (a.X != b || a.Y != b ); - public static bool operator !=(int a, Point2I b) => (a != b.X || a != b.Y); - - public static bool operator <(Point2I a, Point2I b) => (a.X < b.X && a.Y < b.Y); - public static bool operator <(Point2I a, int b) => (a.X < b && a.Y < b ); - public static bool operator <(int a, Point2I b) => (a < b.X && a < b.Y); - - public static bool operator >(Point2I a, Point2I b) => (a.X > b.X && a.Y > b.Y); - public static bool operator >(Point2I a, int b) => (a.X > b && a.Y > b ); - public static bool operator >(int a, Point2I b) => (a > b.X && a > b.Y); - - public static bool operator <=(Point2I a, Point2I b) => (a.X <= b.X && a.Y <= b.Y); - public static bool operator <=(Point2I a, int b) => (a.X <= b && a.Y <= b ); - public static bool operator <=(int a, Point2I b) => (a <= b.X && a <= b.Y); - - public static bool operator >=(Point2I a, Point2I b) => (a.X >= b.X && a.Y >= b.Y); - public static bool operator >=(Point2I a, int b) => (a.X >= b && a.Y >= b ); - public static bool operator >=(int a, Point2I b) => (a >= b.X && a >= b.Y); - - #endregion - - #endregion - - #region Properties - - /// Gets the coordinate at the specified index. - public int this[int index] { - get { - switch (index) { - case 0: return X; - case 1: return Y; - default: throw new ArgumentOutOfRangeException(nameof(index)); - } - } - set { - switch (index) { - case 0: X = value; return; - case 1: Y = value; return; - default: throw new ArgumentOutOfRangeException(nameof(index)); - } - } - } - - /// Returns true if the point is positioned at (0, 0). - public bool IsZero => (X == 0 && Y == 0); - - /// Returns true if either X or Y is positioned at 0. - public bool IsAnyZero => (X == 0 || Y == 0); - - /// Returns the perpendicular point. - public Point2I Perpendicular => new Point2I(-Y, X); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Structures/Rectangle2I.cs b/WinDirStat.Net.Base/Structures/Rectangle2I.cs deleted file mode 100644 index 14fc3d7..0000000 --- a/WinDirStat.Net.Base/Structures/Rectangle2I.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace WinDirStat.Net.Structures { - [Serializable] - [StructLayout(LayoutKind.Sequential)] - public struct Rectangle2I { - - #region Constants - - /// Returns a rectangle positioned at (0, 0) with a size of (0, 0). - public static readonly Rectangle2I Empty = new Rectangle2I(0, 0, 0, 0); - /// Returns a rectangle positioned at (0, 0) with a size of (1, 1). - public static readonly Rectangle2I One = new Rectangle2I(0, 0, 1, 1); - /// Returns a rectangle positioned at (-1, -1) with a size of (0, 0). - public static readonly Rectangle2I Invalid = new Rectangle2I(-1, -1, 0, 0); - - #endregion - - #region Fields - - /// X coordinate of this rectangle. - public int X; - /// Y coordinate of this rectangle. - public int Y; - /// Width of this rectangle. - public int Width; - /// Height of this rectangle. - public int Height; - - #endregion - - #region Constructors - - public Rectangle2I(int width, int height) { - X = 0; - Y = 0; - Width = width; - Height = height; - } - - public Rectangle2I(int x, int y, int width, int height) { - X = x; - Y = y; - Width = width; - Height = height; - } - - public Rectangle2I(Point2I size) { - X = 0; - Y = 0; - Width = size.X; - Height = size.Y; - } - - public Rectangle2I(Point2I point, Point2I size) { - X = point.X; - Y = point.Y; - Width = size.X; - Height = size.Y; - } - - #endregion - - #region Static Constructors - - public static Rectangle2I FromLTRB(int left, int top, int right, int bottom) { - return new Rectangle2I(left, top, right - left, bottom - top); - } - - #endregion - - #region Properties - - public int Left { - get => X; - set { - // Keep the right position - Width += X - value; - X = value; - } - } - - public int Top { - get => Y; - set { - // Keep the right position - Height += Y - value; - Y = value; - } - } - - public int Right { - get => X + Width; - set => Width = value - X; - } - - public int Bottom { - get => Y + Height; - set => Height = value - Y; - } - - #endregion - - #region Casting - - public static implicit operator Rectangle2I(Rectangle2S rect) { - return new Rectangle2I( - (rect.X == ushort.MaxValue ? -1 : rect.X), - (rect.Y == ushort.MaxValue ? -1 : rect.Y), - rect.Width, - rect.Height); - } - - public static explicit operator Rectangle2S(Rectangle2I rect) { - return new Rectangle2S(rect.X, rect.Y, rect.Width, rect.Height); - } - - #endregion - - #region Accessors - - public bool Contains(int x, int y) { - return Contains(new Point2I(x, y)); - } - - public bool Contains(Point2I point) { - return (point.X >= Left && point.X <= Right && - point.Y >= Top && point.Y <= Bottom); - } - - #endregion - - #region Mutators - - public void Inflate(int x, int y) { - X -= x; - Y -= y; - Width += x * 2; - Height += y * 2; - } - - public void Deflate(int x, int y) { - X += x; - Y += y; - Width -= x * 2; - Height -= y * 2; - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Structures/Rectangle2S.cs b/WinDirStat.Net.Base/Structures/Rectangle2S.cs deleted file mode 100644 index 843af83..0000000 --- a/WinDirStat.Net.Base/Structures/Rectangle2S.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace WinDirStat.Net.Structures { - [Serializable] - [StructLayout(LayoutKind.Sequential)] - public struct Rectangle2S { - - #region Constants - - /// Returns a rectangle positioned at (0, 0) with a size of (0, 0). - public static readonly Rectangle2S Empty = new Rectangle2S(0, 0, 0, 0); - /// Returns a rectangle positioned at (0, 0) with a size of (1, 1). - public static readonly Rectangle2S One = new Rectangle2S(0, 0, 1, 1); - /// - /// Returns a rectangle positioned at (, ) - /// with a size of (0, 0). - /// - public static readonly Rectangle2S Invalid = new Rectangle2S(ushort.MaxValue, ushort.MaxValue, 0, 0); - - #endregion - - #region Fields - - /// X coordinate of this rectangle. - public ushort X; - /// Y coordinate of this rectangle. - public ushort Y; - /// Width of this rectangle. - public ushort Width; - /// Height of this rectangle. - public ushort Height; - - #endregion - - #region Constructors - - public Rectangle2S(int width, int height) { - X = 0; - Y = 0; - Width = (ushort) width; - Height = (ushort) height; - } - - public Rectangle2S(int x, int y, int width, int height) { - X = (ushort) (x == -1 ? ushort.MaxValue : x); - Y = (ushort) (y == -1 ? ushort.MaxValue : y); - Width = (ushort) width; - Height = (ushort) height; - } - - public Rectangle2S(Point2I size) { - X = 0; - Y = 0; - Width = (ushort) size.X; - Height = (ushort) size.Y; - } - - public Rectangle2S(Point2I point, Point2I size) { - X = (ushort) (point.X == -1 ? ushort.MaxValue : point.X); - Y = (ushort) (point.Y == -1 ? ushort.MaxValue : point.Y); - Width = (ushort) size.X; - Height = (ushort) size.Y; - } - - #endregion - - #region Static Constructors - - public static Rectangle2S FromLTRB(int left, int top, int right, int bottom) { - return new Rectangle2S(left, top, right - left, bottom - top); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Structures/Rgb24Color.cs b/WinDirStat.Net.Base/Structures/Rgb24Color.cs deleted file mode 100644 index caf84c1..0000000 --- a/WinDirStat.Net.Base/Structures/Rgb24Color.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace WinDirStat.Net.Structures { - /// An unmanaged 24-bit RGB color. - [Serializable] - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct Rgb24Color { - - #region Constants - - public static readonly Rgb24Color Black = new Rgb24Color(0, 0, 0); - public static readonly Rgb24Color White = new Rgb24Color(255, 255, 255); - - #endregion - - #region Fields - - /// The blue channel for the color. - public byte B; - /// The green channel for the color. - public byte G; - /// The red channel for the color. - public byte R; - - #endregion - - #region Constructors - - /// Constructs the . - /// The red channel. - /// The green channel. - /// The blue channel. - public Rgb24Color(int red, int green, int blue) { - R = (byte) red; - G = (byte) green; - B = (byte) blue; - } - - #endregion - - #region Properties - - public int PackedValue { - get => (B << 16) | (G << 8) | R; - set { - B = (byte) ((value >> 16) & 0xFF); - G = (byte) ((value >> 8) & 0xFF); - R = (byte) ((value) & 0xFF); - } - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Structures/Rgba32Color.cs b/WinDirStat.Net.Base/Structures/Rgba32Color.cs deleted file mode 100644 index 9f7fe5f..0000000 --- a/WinDirStat.Net.Base/Structures/Rgba32Color.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using WinDirStat.Net.Utils; - -namespace WinDirStat.Net.Structures { - /// An unmanaged 32-bit RGBA color. - [Serializable] - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct Rgba32Color { - - #region Constants - - public static readonly Rgba32Color Transparent = new Rgba32Color(0, 0, 0, 0); - public static readonly Rgba32Color Black = new Rgba32Color(0, 0, 0); - public static readonly Rgba32Color White = new Rgba32Color(255, 255, 255); - - #endregion - - #region Fields - - /// The blue channel for the color. - public byte B; - /// The green channel for the color. - public byte G; - /// The red channel for the color. - public byte R; - /// The alpha channel for the color. - public byte A; - - #endregion - - #region Constructors - - /// Constructs the with an alpha of 255. - /// The red channel. - /// The green channel. - /// The blue channel. - public Rgba32Color(int red, int green, int blue) { - R = (byte) red; - G = (byte) green; - B = (byte) blue; - A = byte.MaxValue; - } - - /// Constructs the .The red channel. - /// The green channel. - /// The blue channel. - /// The alpha channel. - public Rgba32Color(int red, int green, int blue, int alpha) { - R = (byte) red; - G = (byte) green; - B = (byte) blue; - A = (byte) alpha; - } - - /// Constructs the (0.0-1.0) with an alpha of 1.0. - /// The red channel. - /// The green channel. - /// The blue channel. - public Rgba32Color(float red, float green, float blue) { - R = (byte) MathUtils.Round(red * 255); - G = (byte) MathUtils.Round(green * 255); - B = (byte) MathUtils.Round(blue * 255); - A = byte.MaxValue; - } - - /// Constructs the (0.0-1.0) . - /// The red channel. - /// The green channel. - /// The blue channel. - /// The alpha channel. - public Rgba32Color(float red, float green, float blue, float alpha) { - R = (byte) MathUtils.Round(red * 255); - G = (byte) MathUtils.Round(green * 255); - B = (byte) MathUtils.Round(blue * 255); - A = (byte) MathUtils.Round(alpha * 255); - } - - /// Constructs the (0.0-1.0) with an alpha of 1.0. - /// The red channel. - /// The green channel. - /// The blue channel. - public Rgba32Color(double red, double green, double blue) { - R = (byte) MathUtils.Round(red * 255); - G = (byte) MathUtils.Round(green * 255); - B = (byte) MathUtils.Round(blue * 255); - A = byte.MaxValue; - } - - /// Constructs the (0.0-1.0) . - /// The red channel. - /// The green channel. - /// The blue channel. - /// The alpha channel. - public Rgba32Color(double red, double green, double blue, double alpha) { - R = (byte) MathUtils.Round(red * 255); - G = (byte) MathUtils.Round(green * 255); - B = (byte) MathUtils.Round(blue * 255); - A = (byte) MathUtils.Round(alpha * 255); - } - - /// Constructs the packed value . - /// The packed value. - public Rgba32Color(int rgba) { - B = (byte) ((rgba >> 24) & 0xFF); - G = (byte) ((rgba >> 16) & 0xFF); - R = (byte) ((rgba >> 8) & 0xFF); - A = (byte) ((rgba) & 0xFF); - } - - #endregion - - #region Properties - - public int PackedValue { - get => (B << 24) | (G << 16) | (R << 8) | A; - set { - B = (byte) ((value >> 24) & 0xFF); - G = (byte) ((value >> 16) & 0xFF); - R = (byte) ((value >> 8) & 0xFF); - A = (byte) ((value) & 0xFF); - } - } - - #endregion - - #region Casting - - /// Casts the to an . - public static explicit operator Rgb24Color(Rgba32Color color) { - return new Rgb24Color(color.R, color.G, color.B); - } - - /// Casts the to a . - public static implicit operator Rgba32Color(Rgb24Color color) { - return new Rgba32Color(color.R, color.G, color.B); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Utils/ArrayExtensions.cs b/WinDirStat.Net.Base/Utils/ArrayExtensions.cs deleted file mode 100644 index c6296d6..0000000 --- a/WinDirStat.Net.Base/Utils/ArrayExtensions.cs +++ /dev/null @@ -1,598 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; - -namespace WinDirStat.Net.Utils { - /// How to handle BlockCast when the array byte sizes do not align. - public enum BlockCastAlign { - /// Throw an exception due to unalignment. - Error = 0, - /// Oversize the new array by one element. - Oversize, - /// Undersize the new array by one element. - Undersize, - } - - /// Extensions for 1-dimensional objects. - public static class ArrayExtensions { - - #region Memset (Single) - - /// Populates the entire array with the specified value. - /// The array to fill. - /// The value to populate the array with. - /// Returns the same array that was populated. - /// Created by TowerOfBricks: - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - public static void Memset(this Array array, object value) { - Memset(array, value, 0, array.Length); - } - - /// - /// Populates the specified section of the array with the specified value. - /// - /// - /// The array to fill. - /// The value to populate the array with. - /// The index to start populating the array at. - /// The number of elements to populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - /// - /// or is less than zero. - /// - public static void Memset(this Array array, object value, int startIndex, - int length) - { - if (length < 0) - throw new ArgumentOutOfRangeException(nameof(length), - $"{nameof(length)} '{length}' is less than zero!"); - - int block = Math.Min(32, length); - int index = startIndex; - int end = startIndex + block; - - while (index < end) - array.SetValue(value, index++); - - end = startIndex + length; - while (index < end) { - Array.Copy(array, startIndex, array, index, Math.Min(block, end - index)); - index += block; - block *= 2; - } - } - - /// Populates the entire array with the specified value. - /// The element type of the array. - /// The array to fill. - /// The value to populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - public static void Memset(this T[] array, T value) { - Memset(array, value, 0, array.Length); - } - - /// - /// Populates the specified section of the array with the specified value. - /// - /// - /// The element type of the array. - /// The array to fill. - /// The value to populate the array with. - /// The index to start populating the array at. - /// The number of elements to populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - /// - /// or is less than zero. - /// - public static void Memset(this T[] array, T value, int startIndex, - int length) - { - if (length < 0) - throw new ArgumentOutOfRangeException(nameof(length), - $"{nameof(length)} '{length}' is less than zero!"); - - int block = Math.Min(32, length); - int index = startIndex; - int end = startIndex + block; - - while (index < end) - array[index++] = value; - - end = startIndex + length; - while (index < end) { - Array.Copy(array, startIndex, array, index, Math.Min(block, end - index)); - index += block; - block *= 2; - } - } - - #endregion - - #region Memset (Multiple) - - /// Populates the entire array with the specified repeating values. - /// The array to fill. - /// The ordered values to repeatedly populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - /// - /// has a length of zero. - /// - /// is null. - public static void Memset(this Array array, Array values) { - array.Memset(values, 0, array.Length); - } - - /// - /// Populates the specified section of the array with the specified repeating values. - /// - /// - /// The array to fill. - /// The ordered values to repeatedly populate the array with. - /// The index to start populating the array at. - /// The number of single elements to populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - /// - /// or is less than zero. - /// - /// - /// has a length of zero. - /// - /// is null. - public static void Memset(this Array array, Array values, int startIndex, - int length) - { - if (length < 0) - throw new ArgumentOutOfRangeException(nameof(length), - $"{nameof(length)} '{length}' is less than zero!"); - else if (values == null) - throw new ArgumentNullException(nameof(values)); - else if (values.Length == 0) - throw new ArgumentException($"{nameof(values)} has a length of zero!", - nameof(values)); - - // Make sure the starting block is divisible by the number of values. - int block = Math.Max(values.Length, (32 / values.Length) * values.Length); - int index = startIndex; - int end = startIndex + block; - - for (int i = 0; i < block; i++) - array.SetValue(values.GetValue(i), index++); - - end = startIndex + length; - while (index < end) { - Array.Copy(array, 0, array, index, Math.Min(block, end - index)); - index += block; - block *= 2; - } - } - - /// Populates the entire array with the specified repeating values. - /// The element type of the array. - /// The array to fill. - /// The ordered values to repeatedly populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - /// - /// has a length of zero. - /// - /// is null. - public static void Memset(this T[] array, params T[] values) { - array.Memset(values, 0, array.Length); - } - - /// - /// Populates the specified section of the array with the specified repeating values. - /// - /// - /// The element type of the array. - /// The array to fill. - /// The ordered values to repeatedly populate the array with. - /// The index to start populating the array at. - /// The number of single elements to populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - /// - /// or is less than zero. - /// - /// has a length of zero. - /// - /// is null. - public static void Memset(this T[] array, T[] values, int startIndex, - int length) - { - if (length < 0) - throw new ArgumentOutOfRangeException(nameof(length), - $"{nameof(length)} '{length}' is less than zero!"); - else if (values == null) - throw new ArgumentNullException(nameof(values)); - else if (values.Length == 0) - throw new ArgumentException($"{nameof(values)} has a length of zero!", - nameof(values)); - - // Make sure the starting block is divisible by the number of values. - int block = Math.Max(values.Length, (32 / values.Length) * values.Length); - int index = startIndex; - int end = startIndex + block; - - for (int i = 0; i < block; i++) - array[index++] = values[i]; - - end = startIndex + length; - while (index < end) { - Array.Copy(array, 0, array, index, Math.Min(block, end - index)); - index += block; - block *= 2; - } - } - - #endregion - - #region Contains - - /// Returns true if the array contains the specified value. - /// The array to check for containment. - /// The value to check for. - /// Returns true if the array contains the specified value. - public static bool Contains(this Array array, object value) { - return Array.IndexOf(array, value) != -1; - } - - /// Returns true if the array contains the specified value. - /// The element type of the array. - /// The array to check for containment. - /// The value to check for. - /// Returns true if the array contains the specified value. - public static bool Contains(this T[] array, T value) { - return Array.IndexOf(array, value) != -1; - } - - #endregion - - #region BlockCast - - /// - /// Block copies the source array to a new array of primitive type . - /// - /// - /// The primitive type to cast to. - /// The array to block cast. - /// How alignment remainders are handled. - /// Return a new array with the casted type. - /// - /// - /// is not an array of primitives, - /// is not a primitive type, or is invalid. - /// - /// - /// The length of is greater than . - /// - public static TResult[] BlockCast(this Array source, - BlockCastAlign align = BlockCastAlign.Error) where TResult : struct - { - Type srcType = source.GetType().GetElementType(); - Type resultType = typeof(TResult); - if (!srcType.IsPrimitive) - throw new ArgumentException($"{nameof(source)} is not an array of " + - $"primitives!", nameof(source)); - else if (!resultType.IsPrimitive) - throw new ArgumentException($"{nameof(TResult)} '{resultType.Name}' " + - $"is not a primitive type!", nameof(TResult)); - - int srcSize = Marshal.SizeOf(srcType); - int srcByteLength = source.Length * srcSize; - - int resultSize = Marshal.SizeOf(); - int resultLength = Math.DivRem(srcByteLength, resultSize, out int rem); - int copyByteLength = srcByteLength; - if (rem != 0) { - switch (align) { - case BlockCastAlign.Oversize: - resultLength += resultSize; - break; - case BlockCastAlign.Undersize: - copyByteLength = resultLength * resultSize; - break; - case BlockCastAlign.Error: - throw new ArgumentException($"{srcType.Name}[] of length " + - $"'{source.Length}' cannot align with {resultType.Name}[] " + - $"of length '{resultLength}`!", nameof(source)); - default: - throw new ArgumentException($"{nameof(align)} is invalid!", - nameof(align)); - } - } - - TResult[] result = new TResult[resultLength]; - Buffer.BlockCopy(source, 0, result, 0, copyByteLength); - return result; - } - - #endregion - - #region Reverse - - /// Creates a reversed copy the array. - /// - /// The arrat to copy. - /// A reversed array. - /// - /// is multidimensional. - public static Array Reverse(this Array array) { - Array output = (Array) array.Clone(); - Array.Reverse(output); - return output; - } - - /// Creates a reversed copy the array. - /// - /// The element type of the array. - /// The arrat to copy. - /// A reversed array. - public static T[] Reverse(this T[] array) { - T[] output = (T[]) array.Clone(); - Array.Reverse(output); - return output; - } - - #endregion - - #region Swap - - /// Swaps two elements within an array. - /// - /// The array to swap elements in. - /// The index of the first element to swap. - /// The index of the second element to swap. - /// - /// - /// or is outside the bounds of the array. - /// - public static void Swap(this Array array, int indexA, int indexB) { - object swap = array.GetValue(indexA); - array.SetValue(array.GetValue(indexB), indexA); - array.SetValue(swap, indexB); - } - - /// Swaps two elements within an array. - /// - /// The element type of the array. - /// The array to swap elements in. - /// The index of the first element to swap. - /// The index of the second element to swap. - /// - /// - /// or is outside the bounds of the array. - /// - public static void Swap(this T[] array, int indexA, int indexB) { - T swap = array[indexA]; - array[indexA] = array[indexB]; - array[indexB] = swap; - } - - #endregion - - #region ToJagged - - /// Copies a 2D multidimension array to a 2D jagged array. - /// - /// The type of the array. - /// The array to create a jagged version of. - /// - /// True if the first dimension in the multidimension array should be the last dimension in the - /// jagged array. - /// - /// The new jagged array. - public static T[][] ToJagged(this T[,] array, bool reverse) { - T[][] output; - int lengthx, lengthy; - if (reverse) { - lengthx = array.GetLength(1); - lengthy = array.GetLength(0); - output = new T[lengthx][]; - for (int x = 0; x < lengthx; x++) { - output[x] = new T[lengthy]; - for (int y = 0; y < lengthy; y++) - output[x][y] = array[y, x]; - } - } - else { - lengthx = array.GetLength(0); - lengthy = array.GetLength(1); - output = new T[lengthx][]; - for (int x = 0; x < lengthx; x++) { - output[x] = new T[lengthy]; - for (int y = 0; y < lengthy; y++) - output[x][y] = array[x, y]; - } - } - return output; - } - - /// Copies a 3D multidimension array to a 3D jagged array. - /// - /// The type of the array. - /// The array to create a jagged version of. - /// - /// True if the first dimension in the multidimension array should be the last dimension in the - /// jagged array. - /// - /// The new jagged array. - public static T[][][] ToJagged(this T[,,] array, bool reverse) { - T[][][] output; - int lengthx, lengthy, lengthz; - if (reverse) { - lengthx = array.GetLength(2); - lengthy = array.GetLength(1); - lengthz = array.GetLength(0); - output = new T[lengthx][][]; - for (int x = 0; x < lengthx; x++) { - output[x] = new T[lengthy][]; - for (int y = 0; y < lengthy; y++) { - output[x][y] = new T[lengthz]; - for (int z = 0; z < lengthz; z++) - output[x][y][z] = array[z, y, x]; - } - } - } - else { - lengthx = array.GetLength(0); - lengthy = array.GetLength(1); - lengthz = array.GetLength(2); - output = new T[lengthx][][]; - for (int x = 0; x < lengthx; x++) { - output[x] = new T[lengthy][]; - for (int y = 0; y < lengthy; y++) { - output[x][y] = new T[lengthz]; - for (int z = 0; z < lengthz; z++) - output[x][y][z] = array[x, y, z]; - } - } - } - return output; - } - - #endregion - - #region ToMultidimension - - /// Copies a 2D jagged array to a 2D multidimension array. - /// - /// The type of the array. - /// The array to create a jagged version of. - /// - /// True if the first dimension in the jagged array should be the last dimension in the - /// multidimension array. - /// - /// The new multidimension array. - /// - /// - /// One of the dimensions in is null. - /// - public static T[,] ToMultidimension(this T[][] array, bool reverse) { - T[,] output; - int lengthx = array.Length; - int lengthy = array.FirstOrDefault()?.Length ?? 0; - if (reverse) { - output = new T[lengthy, lengthx]; - for (int x = 0; x < lengthx; x++) { - LengthCheck(array, x, lengthy, 1); - for (int y = 0; y < lengthy; y++) - output[y, x] = array[x][y]; - } - } - else { - output = new T[lengthx, lengthy]; - for (int x = 0; x < lengthx; x++) { - LengthCheck(array, x, lengthy, 1); - for (int y = 0; y < lengthy; y++) - output[x, y] = array[x][y]; - } - } - return output; - } - - /// Copies a 3D jagged array to a 3D multidimension array. - /// - /// The type of the array. - /// The array to create a jagged version of. - /// - /// True if the first dimension in the jagged array should be the last dimension in the - /// multidimension array. - /// - /// The new multidimension array. - /// - /// - /// One of the dimensions in is null. - /// - public static T[,,] ToMultidimension(this T[][][] array, bool reverse) { - T[,,] output; - int lengthx = array.Length; - int lengthy = array.FirstOrDefault()?.Length ?? 0; - int lengthz = array.FirstOrDefault()?.FirstOrDefault()?.Length ?? 0; - if (reverse) { - output = new T[lengthz, lengthy, lengthx]; - for (int x = 0; x < lengthx; x++) { - LengthCheck(array, x, lengthy, 1); - for (int y = 0; y < lengthy; y++) { - LengthCheck(array, y, lengthz, 1); - for (int z = 0; z < lengthz; y++) - output[z, y, x] = array[x][y][z]; - } - } - } - else { - output = new T[lengthx, lengthy, lengthz]; - for (int x = 0; x < lengthx; x++) { - LengthCheck(array, x, lengthy, 1); - for (int y = 0; y < lengthy; y++) { - LengthCheck(array, y, lengthz, 1); - for (int z = 0; z < lengthz; y++) - output[x, y, z] = array[x][y][z]; - } - } - } - return output; - } - - #endregion - - #region Private - - /// Ensures the jagged array conforms to the same length for every index. - /// - /// The element type of the array. - /// The array to check the length of. - /// The index of the array to check the length of. - /// The initial length of the array. - /// The current pdeth of teh array. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void LengthCheck(T[][] array, int index, int length, int depth) { - if (array[index].Length != length) { - throw new ArgumentException($"Jagged array of depth: {depth}, index: {index}, " + - $"length: {array[index].Length} does not match initial length of {length}!"); - } - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Utils/CommandExtensions.cs b/WinDirStat.Net.Base/Utils/CommandExtensions.cs deleted file mode 100644 index 624e370..0000000 --- a/WinDirStat.Net.Base/Utils/CommandExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; - -namespace WinDirStat.Net.Utils { - /// Extensions for s. - public static class CommandExtensions { - - #region Execute - - /// Executes the method without a parameter. - /// - /// The command to execute. - public static void Execute(this ICommand command) { - command.Execute(null); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Utils/Enumerator.cs b/WinDirStat.Net.Base/Utils/Enumerator.cs deleted file mode 100644 index d1ca616..0000000 --- a/WinDirStat.Net.Base/Utils/Enumerator.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace WinDirStat.Net.Utils { - /// A static class for creating basic s. - public static class Enumerator { - - #region EmptyEnumerator - - /// An empty non-generic enumerator. - private class EmptyEnumerator : IEnumerator { - - /// Constructs an empty enumerator. - public EmptyEnumerator() { } - - /// - /// Sets the enumerator to its initial position, which is before the first element in the - /// collection. - /// - public void Reset() { } - - /// Advances the enumerator to the next element of the collection. - /// - /// - /// true if the enumerator was successfully advanced to the next element; false if the enumerator - /// has passed the end of the collection. - /// - public bool MoveNext() { - return false; - } - - /// Gets the current element in the collection. - public object Current { - get => throw new InvalidOperationException(); - } - } - - #endregion - - #region EmptyEnumerator - - /// An empty generic enumerator. - private class EmptyEnumerator : IEnumerator, IEnumerator { - - /// Constructs an empty generic enumerator. - public EmptyEnumerator() { } - - /// Disposes of the enumerator. - public void Dispose() { } - - /// - /// Sets the enumerator to its initial position, which is before the first element in the - /// collection. - /// - public void Reset() { } - - /// Advances the enumerator to the next element of the collection. - /// - /// - /// true if the enumerator was successfully advanced to the next element; false if the enumerator - /// has passed the end of the collection. - /// - public bool MoveNext() { - return false; - } - - /// Gets the current element in the collection. - public T Current { - get => throw new InvalidOperationException(); - } - - /// Gets the current element in the collection. - object IEnumerator.Current { - get => throw new InvalidOperationException(); - } - } - - #endregion - - #region EmptyEnumerator Static Constructors - - /// Construct an empty . - /// - /// The new non-generic enumerator. - public static IEnumerator Empty() { - return new EmptyEnumerator(); - } - - /// Construct an empty . - /// - /// The generic type of the enumerator. - /// The new generic enumerator. - public static IEnumerator Empty() { - return new EmptyEnumerator(); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Utils/FormatBytes.cs b/WinDirStat.Net.Base/Utils/FormatBytes.cs deleted file mode 100644 index 65afa51..0000000 --- a/WinDirStat.Net.Base/Utils/FormatBytes.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Utils { - /// A formatter for displaying bytes with their abbreviations. - public static class FormatBytes { - - #region Constants - - /// All supported byte abbrevations. - public static readonly ReadOnlyCollection Abbreviations = - Array.AsReadOnly(new[] { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }); - - /// The default format for abbreviations of just bytes. - public const string SingleFormat = "N0"; - /// The default format for abbreviations greater than just bytes. - public const string MultiFormat = "N1"; - - #endregion - - #region Default Format - - /// Formats the bytes using the default formats. - public static string Format(int bytes) { - return Format(Convert.ToDouble(bytes)); - } - /// Formats the bytes using the default formats. - public static string Format(uint bytes) { - return Format(Convert.ToDouble(bytes)); - } - /// Formats the bytes using the default formats. - public static string Format(long bytes) { - return Format(Convert.ToDouble(bytes)); - } - /// Formats the bytes using the default formats. - public static string Format(ulong bytes) { - return Format(Convert.ToDouble(bytes)); - } - /// Formats the bytes using the default formats. - public static string Format(float bytes) { - return Format(bytes, SingleFormat, MultiFormat); - } - /// Formats the bytes using the default formats. - public static string Format(decimal bytes) { - return Format(Convert.ToDouble(bytes)); - } - /// Formats the bytes using the default formats. - public static string Format(double bytes) { - return Format(bytes, SingleFormat, MultiFormat); - } - - #endregion - - #region Custom Format - - /// Formats the bytes using the specified formats. - public static string Format(int bytes, string singleFormat, string multiFormat) { - return Format(Convert.ToDouble(bytes), singleFormat, multiFormat); - } - /// Formats the bytes using the specified formats. - public static string Format(uint bytes, string singleFormat, string multiFormat) { - return Format(Convert.ToDouble(bytes), singleFormat, multiFormat); - } - /// Formats the bytes using the specified formats. - public static string Format(long bytes, string singleFormat, string multiFormat) { - return Format(Convert.ToDouble(bytes), singleFormat, multiFormat); - } - /// Formats the bytes using the specified formats. - public static string Format(ulong bytes, string singleFormat, string multiFormat) { - return Format(Convert.ToDouble(bytes), singleFormat, multiFormat); - } - /// Formats the bytes using the specified formats. - public static string Format(float bytes, string singleFormat, string multiFormat) { - return Format(Convert.ToDouble(bytes), singleFormat, multiFormat); - } - /// Formats the bytes using the specified formats. - public static string Format(decimal bytes, string singleFormat, string multiFormat) { - return Format(Convert.ToDouble(bytes), singleFormat, multiFormat); - } - /// Formats the bytes using the specified formats. - public static string Format(double bytes, string singleFormat, string multiFormat) { - int order; - int sign = Math.Sign(bytes); - bytes = Math.Abs(bytes); - for (order = 0; order < Abbreviations.Count && bytes >= 1024; order++) { - bytes /= 1024; - } - - // Don't show decimal places for Bytes - string format = (order == 0 ? singleFormat : multiFormat); - - return string.Format("{0:" + format + "} {1}", sign * bytes, Abbreviations[order]); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Utils/ListExtensions.cs b/WinDirStat.Net.Base/Utils/ListExtensions.cs deleted file mode 100644 index 8a78b6d..0000000 --- a/WinDirStat.Net.Base/Utils/ListExtensions.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Utils { - /// Extensions for the list class. - public static class ListExtensions { - /// - /// Minimizes the memory usage of teh list by reducing the to the - /// current . - /// - /// - /// The element type of the list. - /// The list to minimize. - public static void Minimize(this List source) { - source.Capacity = source.Count; - } - - /// Moves a single item in the list. - /// - /// The element type of the list. - /// The list to move an item in. - /// The new index of the item. - /// The old index of the item. - public static void Move(this List source, int index, int oldIndex) { - T item = source[oldIndex]; - source.RemoveAt(index); - source.Insert(index, item); - } - - /// Movess a range of items in the list. - /// - /// The element type of the list. - /// The list to move items in. - /// The new index of the items. - /// The old index of the items. - /// The number of items to move. - public static void MoveRange(this List source, int index, int oldIndex, int count) { - List items = source.GetRange(oldIndex, count); - source.RemoveRange(oldIndex, count); - source.InsertRange(index, items); - } - - /// - /// Creates a copy of the list using a more efficient method than with . - /// - /// - /// The element type of the list. - /// The list to create a copy of. - public static List GetFullRange(this List source) { - return source.GetRange(0, source.Count); - } - } -} diff --git a/WinDirStat.Net.Base/Utils/MathUtils.cs b/WinDirStat.Net.Base/Utils/MathUtils.cs deleted file mode 100644 index ac97f93..0000000 --- a/WinDirStat.Net.Base/Utils/MathUtils.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Utils { - /// Simple additional math functions. - public static class MathUtils { - - /// Converts degrees to radians. - /// - /// The degress to convert. - /// The as radians. - public static float DegToRad(float degrees) { - return degrees * (float) Math.PI / 180f; - } - - /// Converts degrees to radians. - /// - /// The degress to convert. - /// The as radians. - public static double DegToRad(double degrees) { - return degrees * Math.PI / 180d; - } - - /// Converts radians to degrees. - /// - /// The radians to convert. - /// The as degrees. - public static float RadToDeg(float radians) { - return radians / (float) Math.PI * 180f; - } - - /// Converts radians to degrees. - /// - /// The radians to convert. - /// The as degrees. - public static double RadToDeg(double radians) { - return radians / Math.PI * 180d; - } - - /// Rounds the value and returns it as an integer. - /// - /// The value to round. - /// The rounded value as an integer. - public static int Round(float x) { - return Math.Sign(x) * (int) (Math.Abs(x) + 0.5f); - } - - /// Rounds the value and returns it as an integer. - /// - /// The value to round. - /// The rounded value as an integer. - public static int Round(double x) { - return Math.Sign(x) * (int) (Math.Abs(x) + 0.5); - } - - /// Clamps the values. - /// - /// The type to compare. - /// The value to clamp. - /// The minimum value (has priority over ). - /// The maximum value. - /// The value between and . - public static T Clamp(T value, T min, T max) where T : IComparable { - if (value.CompareTo(min) < 0) - return min; - else if (value.CompareTo(max) > 0) - return max; - else - return value; - } - } -} diff --git a/WinDirStat.Net.Base/Utils/PathUtils.cs b/WinDirStat.Net.Base/Utils/PathUtils.cs deleted file mode 100644 index 125bbee..0000000 --- a/WinDirStat.Net.Base/Utils/PathUtils.cs +++ /dev/null @@ -1,549 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; - -namespace WinDirStat.Net.Utils { - /// A helper with extra methods for paths, files, and directories. - public static class PathUtils { - - //----------------------------------------------------------------------------- - // Constants - //----------------------------------------------------------------------------- - - /// The stored executable path for the entry assembly. - public static readonly string EntryPath = - Assembly.GetEntryAssembly().Location; - - /// The directory of the entry executable. - public static readonly string EntryDirectory = - Path.GetDirectoryName(EntryPath); - - /// Gets the file name of the entry executable. - public static readonly string EntryFile = - Path.GetFileName(EntryPath); - - /// Gets the file name of the entry executable without its extension. - public static readonly string EntryName = - Path.GetFileNameWithoutExtension(EntryPath); - - /// - /// Provides a platform-specific character used to separate directory levels in a path - /// string that reflects a hierarchical file system organization. - /// - public static readonly char[] DirectorySeparators = { - Path.DirectorySeparatorChar, - Path.AltDirectorySeparatorChar, - }; - - public static readonly string DirectorySeparatorString = - new string(Path.DirectorySeparatorChar, 1); - public static readonly string AltDirectorySeparatorString = - new string(Path.AltDirectorySeparatorChar, 1); - public static readonly string VolumeSeparatorString = - new string(Path.VolumeSeparatorChar, 1); - - /// - /// Provides a platform-specific character used to separate directory levels in a path - /// string that reflects a hierarchical file system organization. - /// - public static readonly string[] DotDirectorySeparators = { - Path.DirectorySeparatorChar + ".", - Path.AltDirectorySeparatorChar + ".", - }; - - /// Gets the path to System32 whether this is an x86 or x64 process. - /// - /// - /// The operating system is not running Windows. - /// - public static string System32 { - get { - return Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.Windows), - Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess - ? "Sysnative" : "System32"); - } - } - - //----------------------------------------------------------------------------- - // File Validity - //----------------------------------------------------------------------------- - - /// Returns true if the file name has valid characters. - public static bool IsValidName(string name) { - return name.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; - } - - /// - /// Returns true if the file name has valid characters for a search pattern. - /// - public static bool IsValidNamePattern(string name) { - name = name.Replace("*", "").Replace("?", ""); - return IsValidName(name); - } - - /// Returns true if the file path has valid characters. - public static bool IsValidPath(string path) { - try { - Path.GetFullPath(path); - return true; - } - catch { - return false; - } - //return name.IndexOfAny(Path.GetInvalidPathChars()) == -1; - } - - /// - /// Returns true if the file path has valid characters and is not rooted. - /// - public static bool IsValidRelativePath(string path) { - if (Path.IsPathRooted(path)) - return false; - return IsValidPath(path); - } - - /// - /// Returns true if the file path has valid characters for a search pattern. - /// - public static bool IsValidPathPattern(string path) { - path = path.Replace("*", "").Replace("?", ""); - return IsValidPath(path); - //return path.IndexOfAny(Path.GetInvalidPathChars()) == -1; - } - - /// - /// Returns true if the file path has valid characters and does not lead to a directory. - /// - public static bool IsValidFile(string path) { - return IsValidPath(path) && !Directory.Exists(path); - } - - /// - /// Returns true if the file path has valid characters, is not rooted. and does not lead to - /// a directory. - /// - public static bool IsValidRelativeFile(string path) { - if (Path.IsPathRooted(path)) - return false; - return IsValidFile(path); - } - - /// - /// Returns true if the file path has valid characters and does not lead to a file. - /// - public static bool IsValidDirectory(string path) { - return IsValidPath(path) && !File.Exists(path); - } - - /// - /// Returns true if the file path has valid characters, is not rooted. and does not lead to - /// a file. - /// - public static bool IsValidRelativeDirectory(string path) { - if (Path.IsPathRooted(path)) - return false; - return IsValidDirectory(path); - } - - - //----------------------------------------------------------------------------- - // File or Directory - //----------------------------------------------------------------------------- - - /// Copies a file or directory. - public static void CopyFileOrDirectory(string sourcePath, string destPath, bool overwrite) { - if (Directory.Exists(sourcePath)) - CopyDirectory(sourcePath, destPath, overwrite); - else - File.Copy(sourcePath, destPath, overwrite); - } - - /// Moves a file or directory. - public static void MoveFileOrDirectory(string sourcePath, string destPath) { - if (Directory.Exists(sourcePath)) - Directory.Move(sourcePath, destPath); - else - File.Move(sourcePath, destPath); - } - - /// Deletes a file or directory. - public static void DeleteFileOrDirectory(string path) { - if (Directory.Exists(path)) - Directory.Delete(path, true); - else - File.Delete(path); - } - - /// Returns true if a file or directory exists at the path. - public static bool Exists(string path) { - return (File.Exists(path) || Directory.Exists(path)); - } - - /// Copies the directory and all subfolders and files. - public static void CopyDirectory(string sourceDir, string destDir, bool merge) { - // Get the subdirectories for the specified directory. - DirectoryInfo dir = new DirectoryInfo(sourceDir); - - if (!dir.Exists) - throw new DirectoryNotFoundException($"Source directory does not exist or could " + - $"not be found: {sourceDir}"); - - DirectoryInfo[] dirs = dir.GetDirectories(); - // If the destination directory doesn't exist, create it. - if (File.Exists(destDir)) - throw new IOException("File already exists at location!"); - else if (!Directory.Exists(destDir)) - Directory.CreateDirectory(destDir); - else if (!merge) - throw new IOException("Directory already exists at location!"); - - // Get the files in the directory and copy them to the new location. - FileInfo[] files = dir.GetFiles(); - foreach (FileInfo file in files) { - string temppath = Path.Combine(destDir, file.Name); - file.CopyTo(temppath, true); - } - - // Copy subdirectories and their contents to new location. - foreach (DirectoryInfo subdir in dirs) { - string temppath = Path.Combine(destDir, subdir.Name); - CopyDirectory(subdir.FullName, temppath, true); - } - } - - - //----------------------------------------------------------------------------- - // File Paths - //----------------------------------------------------------------------------- - - /// Returns a path that can be compared with another normalized path. - public static string NormalizePath(string path) { - return TrimSeparatorDotEnd( - Path.GetFullPath(path) - .TrimEnd(DirectorySeparators) - .ToUpperInvariant()); - } - - /// Returns true if the two paths lead to the same location. - public static bool IsSamePath(string path1, string path2) { - return string.Compare(NormalizePath(path1), NormalizePath(path2), true) == 0; - } - - /// Removes the ending directory separator from the path. - public static string TrimSeparatorEnd(string path) { - return path.TrimEnd(DirectorySeparators); - } - - /// Removes the ending directory separator from the path. - public static string TrimSeparatorDotEnd(string path) { - for (int i = 0; i < DotDirectorySeparators.Length; i++) { - if (path.EndsWith(DotDirectorySeparators[i])) - return path.Substring(0, path.Length - DotDirectorySeparators[i].Length); - } - return TrimSeparatorEnd(path); - } - - private static readonly string DirectorySeparatorCharAsString = new string(Path.DirectorySeparatorChar, 1); - - public static string CombineNoChecks(string path1, string path2) { - if (path2.Length == 0) - return path1; - - if (path1.Length == 0) - return path2; - - if (Path.IsPathRooted(path2)) - return path2; - - char ch = path1[path1.Length - 1]; - if (!IsDirectorySeparator(ch)) - return path1 + DirectorySeparatorString + path2; - return path1 + path2; - } - - public static string AddLongPathPrefix(string path) { - if (!path.StartsWith(@"\\?\")) - return @"\\?\" + path; - return path; - } - - /// - /// A version of that doesn't access the file system. - /// - /// - /// The path to expand. - /// True if environment variables should be expanded. - /*public static string GetFullPath(string path) { - bool notRooted = !Path.IsPathRooted(path); - string currentDirectory = ""; - if (notRooted) - currentDirectory = Directory.GetDirectories() - string root = () - - string dirs = path; - //string name = Path.GetFileName(path); - string outPath = ""; - while (dirs.Length != 0) { - string name = Path.GetFileName(dirs); - if (name == ".") { - - } - - dirs = Path.GetDirectoryName(dirs); - } - - if (expandEnvVars && path.Contains("%")) - path = Environment.ExpandEnvironmentVariables(path); - }*/ - - /*public static IEnumerable EnumerateDirectoryNames(string path) { - while (path.Contains(DirectorySeparators[0]) || path.Contains(DirectorySeparators[1])) { - - } - }*/ - - public static bool IsPathRoot(string path) { - return IsSamePath(Path.GetPathRoot(path), path); - } - - public static string GetRootOrFileName(string path) { - if (IsPathRoot(path)) - return path; - else - return Path.GetFileName(path); - } - - /// Returns a file path with " - Copy" appended to the filename. - public static string GetCopyName(string path) { - string newPath = Path.GetFileNameWithoutExtension(path) + " - Copy"; - string ext = Path.GetExtension(path); - - int index = 1; - string finalPath = newPath + ext; - while (Exists(finalPath)) { - index++; - finalPath = $"{newPath} ({index}){ext}"; - } - return finalPath; - } - - /// Combines the specified paths with the executable directory. - public static string CombineExe(string path1) { - return Path.Combine(EntryDirectory, path1); - } - - /// Combines the specified paths with the executable directory. - public static string CombineExe(string path1, string path2) { - return Path.Combine(EntryDirectory, path1, path2); - } - - /// Combines the specified paths with the executable directory. - public static string CombineExe(string path1, string path2, - string path3) { - return Path.Combine(EntryDirectory, path1, path2, path3); - } - - /// Combines the specified paths with the executable directory. - public static string CombineExe(params string[] paths) { - return Path.Combine(EntryDirectory, Path.Combine(paths)); - } - - public static string GetTempDirectory(params string[] paths) { - return Path.Combine(Path.GetTempPath(), Path.Combine(paths)); - } - - public static string CreateTempDirectory(params string[] paths) { - string path = GetTempDirectory(paths); - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); - return path; - } - - public static void CleanupTempDirectory(bool deleteRoot, params string[] paths) { - string path = GetTempDirectory(paths); - - if (Directory.Exists(path)) { - - if (deleteRoot) - Directory.Delete(path); - } - } - - /// - /// Gets the exact case used on the file system for an existing file or directory name. - /// - /// - /// A relative or absolute path. - /// The name using the correct case if the path exists. - /// - /// - /// This supports drive-lettered paths and UNC paths, but a UNC root will be returned in - /// title case (e.g., \\Server\Share). - /// Source - /// - public static string GetExactName(string path) { - // DirectoryInfo accepts either a file path or a directory path, and most - // of its properties work for either. However, its Exists property only - // works for a directory path. - DirectoryInfo directory = new DirectoryInfo(path); - if (File.Exists(path) || directory.Exists) { - DirectoryInfo parentDirectory = directory.Parent; - FileSystemInfo child = parentDirectory.EnumerateFileSystemInfos( - directory.Name).First(); - return child.Name; - } - else { - throw new FileNotFoundException(path); - } - } - - /// - /// Gets the exact case used on the file system for an existing file or directory path. - /// - /// - /// A relative or absolute path. - /// The full path using the correct case if the path exists. - /// - /// - /// This supports drive-lettered paths and UNC paths, but a UNC root will be returned in - /// title case (e.g., \\Server\Share). - /// Source - /// - public static string GetExactPath(string path) { - // DirectoryInfo accepts either a file path or a directory path, and most - // of its properties work for either. However, its Exists property only - // works for a directory path. - DirectoryInfo directory = new DirectoryInfo(path); - if (File.Exists(path) || directory.Exists) { - List parts = new List(); - - DirectoryInfo parentDirectory = directory.Parent; - while (parentDirectory != null) { - FileSystemInfo entry = parentDirectory.EnumerateFileSystemInfos( - directory.Name).First(); - parts.Add(entry.Name); - - directory = parentDirectory; - parentDirectory = directory.Parent; - } - - // Handle the root part (i.e., drive letter or UNC \\server\share). - string root = directory.FullName; - if (root.Contains(':')) { - // Drive Letter - root = root.ToUpper(); - } - else { - // UNC - string[] rootParts = root.Split(Path.DirectorySeparatorChar); - root = string.Join(DirectorySeparatorString, rootParts.Select(part => - CultureInfo.CurrentCulture.TextInfo.ToTitleCase(part))); - } - - parts.Add(root); - parts.Reverse(); - return Path.Combine(parts.ToArray()); - } - else { - throw new FileNotFoundException(path); - } - } - - public static bool EndsWithSeparator(string path) { - return path.Length > 0 && IsSeparator(path[path.Length - 1]); - } - public static bool EndsWithDirectorySeparator(string path) { - return path.Length > 0 && IsDirectorySeparator(path[path.Length - 1]); - } - public static bool EndsWithVolumeSeparator(string path) { - return path.Length > 0 && IsVolumeSeparator(path[path.Length - 1]); - } - public static string AddVolumeSeparator(string path) { - if (!EndsWithVolumeSeparator(path)) - return path + Path.VolumeSeparatorChar; - return path; - } - public static string AddDirectorySeparator(string path) { - if (!EndsWithDirectorySeparator(path)) - return path + Path.DirectorySeparatorChar; - return path; - } - - public static bool IsSeparator(char c) { - return c == Path.DirectorySeparatorChar || - c == Path.AltDirectorySeparatorChar || - c == Path.VolumeSeparatorChar; - } - public static bool IsDirectorySeparator(char c) { - return c == Path.DirectorySeparatorChar || - c == Path.AltDirectorySeparatorChar; - } - public static bool IsVolumeSeparator(char c) { - return c == Path.VolumeSeparatorChar; - } - - - //----------------------------------------------------------------------------- - // Get Files - //----------------------------------------------------------------------------- - - #region Get/EnumerateAllFiles - - /// Returns an array of all files and subfiles in the directory. - public static string[] GetAllFiles(string path) { - return Directory.GetFiles(path, "*", SearchOption.AllDirectories); - } - - /// - /// Returns an array of all files and subfiles in the directory that match the search - /// pattern. - /// - public static string[] GetAllFiles(string path, string pattern) { - return Directory.GetFiles(path, pattern, SearchOption.AllDirectories); - } - - /// Enumerates all files and subfiles in the directory. - public static IEnumerable EnumerateAllFiles(string path) { - return Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories); - } - - /// - /// Enumerates all files and subfiles in the directory that match the search pattern. - /// - public static IEnumerable EnumerateAllFiles(string path, string pattern) { - return Directory.EnumerateFiles(path, pattern, SearchOption.AllDirectories); - } - - #endregion - - //----------------------------------------------------------------------------- - // Directory - //----------------------------------------------------------------------------- - - /// Returns true if the directory has no files in it. - public static bool IsDirectoryEmpty(string directory) { - return !Directory.EnumerateFileSystemEntries(directory).Any(); - } - - /// - /// Deletes all empty directories and subdirectories within this directory. - /// - public static void DeleteAllEmptyDirectories(string directory) { - foreach (string dir in Directory.EnumerateDirectories(directory)) { - if (IsDirectoryEmpty(dir)) { - Directory.Delete(dir); - } - else { - DeleteAllEmptyDirectories(dir); - if (IsDirectoryEmpty(dir)) - Directory.Delete(dir); - } - } - } - } -} diff --git a/WinDirStat.Net.Base/Utils/Volatiles/IVolatile.cs b/WinDirStat.Net.Base/Utils/Volatiles/IVolatile.cs deleted file mode 100644 index 295aa00..0000000 --- a/WinDirStat.Net.Base/Utils/Volatiles/IVolatile.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Utils { - /// An interface for a volatile container type. - public interface IVolatile { - - #region Properties - - /// Gets the value. - object Value { get; } - /// Gets the lock context. - object LockObj { get; } - - #endregion - - #region Locking - - /// Locks the value. - void Lock(); - /// Unlocks the value. - void Unlock(); - - #endregion - - #region Volatile Operators - - /// Sets the value. - object Set(object o); - - #endregion - - } -} diff --git a/WinDirStat.Net.Base/Utils/Volatiles/Volatile.cs b/WinDirStat.Net.Base/Utils/Volatiles/Volatile.cs deleted file mode 100644 index 6d81e72..0000000 --- a/WinDirStat.Net.Base/Utils/Volatiles/Volatile.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Utils { - /// A mutable volatile . - public class Volatile : IVolatile { - - #region Fields - - /// The value. - protected T value; - /// The lock context. - protected readonly object lockObj; - - #endregion - - #region Constructors - - /// Constructs the default . - public Volatile() { - lockObj = new object(); - } - /// Constructs the with the specified value. - /// - /// The value to use. - public Volatile(T value) : this() { - this.value = value; - } - /// Constructs the with the specified lock. - /// - /// The lock context to use. - public Volatile(object lockObj) { - if (lockObj == null) - throw new ArgumentNullException(nameof(lockObj)); - if (lockObj.GetType().IsValueType) - throw new ArgumentException("Cannot use a boxed a value type as a lock context!"); - this.lockObj = lockObj; - } - /// Constructs the with the specified value and lock. - /// - /// The value to use. - /// The lock context to use. - public Volatile(T value, object lockObj) : this(lockObj) { - this.value = value; - } - - #endregion - - #region Locking - - /// Locks the value. - public void Lock() { - Monitor.Enter(lockObj); - } - /// Unlocks the value. - public void Unlock() { - Monitor.Exit(lockObj); - } - - #endregion - - #region Properties - - /// Gets the value. - public T Value { - get { lock (lockObj) return value; } - //set { lock (lockObj) this.value = value; } - } - /// Gets the value. - object IVolatile.Value => Value; - /// Gets the lock context. - public object LockObj => lockObj; - - #endregion - - #region Volatile Operators - - /// Sets the value. - public T Set(T newValue) { - lock (lockObj) - return value = newValue; - } - /// Sets the value. - object IVolatile.Set(object newValue) { - lock (lockObj) - return value = (T) newValue; - } - - #endregion - - #region Conversion Operators - - /// Gets the of the . - public static implicit operator T(Volatile value) { - return value.Value; - } - - #endregion - - #region Overrides - - /// Determines whether the specified object is equal to the current object. - public override bool Equals(object obj) { - if (obj is IVolatile vol) - return value.Equals(vol.Value); - return value.Equals(obj); - } - /// Returns the hash code for this instance. - public override int GetHashCode() => value.GetHashCode(); - /// Converts the value of this instance to its equivalent string representation. - public override string ToString() => value.ToString(); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Utils/Volatiles/VolatileBoolean.cs b/WinDirStat.Net.Base/Utils/Volatiles/VolatileBoolean.cs deleted file mode 100644 index 22d7877..0000000 --- a/WinDirStat.Net.Base/Utils/Volatiles/VolatileBoolean.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.Contracts; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Utils { - /// A mutable volatile that supports compound assignments. - public class VolatileBoolean : Volatile { - - #region Constructors - - /// Constructs the default . - public VolatileBoolean() { } - /// Constructs the with the specified value. - /// - /// The value to use. - public VolatileBoolean(bool value) : base(value) { } - /// Constructs the with the specified lock. - /// - /// The lock context to use. - public VolatileBoolean(object lockObj) : base(lockObj) { } - /// Constructs the with the specified value and lock. - /// - /// The value to use. - /// The lock context to use. - public VolatileBoolean(bool value, object lockObj) : base(value, lockObj) { } - - #endregion - - #region Volatile Operators - - /// Toggles the value. - public bool Toggle() { - lock (lockObj) - return value = !value; - } - - #endregion - - #region Volatile Bitwise Operators - - /// Bitwise AND's the value. - public bool BitwiseAnd(bool b) { - lock (lockObj) - return value &= b; - } - /// Bitwise OR's the value. - public bool BitwiseOr(bool b) { - lock (lockObj) - return value |= b; - } - /// Bitwise XOR's the value. - public bool BitwiseXor(bool b) { - lock (lockObj) - return value ^= b; - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Utils/Volatiles/VolatileCompound.cs b/WinDirStat.Net.Base/Utils/Volatiles/VolatileCompound.cs deleted file mode 100644 index a6b7492..0000000 --- a/WinDirStat.Net.Base/Utils/Volatiles/VolatileCompound.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Utils { - /// A mutable volatile . - public class VolatileCompound : IVolatile { - - #region Fields - - /// The value. - protected T value; - /// The lock context. - protected readonly object lockObj; - - #endregion - - #region Constructors - - /// Constructs the default . - public VolatileCompound() { - lockObj = new object(); - } - /// Constructs the with the specified value. - /// - /// The value to use. - public VolatileCompound(T value) : this() { - this.value = value; - } - /// Constructs the with the specified lock. - /// - /// The lock context to use. - public VolatileCompound(object lockObj) { - if (lockObj == null) - throw new ArgumentNullException(nameof(lockObj)); - if (lockObj.GetType().IsValueType) - throw new ArgumentException("Cannot use a boxed a value type as a lock context!"); - this.lockObj = lockObj; - } - /// Constructs the with the specified value and lock. - /// - /// The value to use. - /// The lock context to use. - public VolatileCompound(T value, object lockObj) : this(lockObj) { - this.value = value; - } - - #endregion - - #region Locking - - /// Locks the value. - public void Lock() { - Monitor.Enter(lockObj); - } - /// Unlocks the value. - public void Unlock() { - Monitor.Exit(lockObj); - } - - #endregion - - #region Properties - - /// Gets the value. - public T Value { get { lock (lockObj) return value; } } - /// Gets the value. - object IVolatile.Value => Value; - /// Gets the lock context. - public object LockObj => lockObj; - - #endregion - - #region VolatileCompound Operators - - /// Sets the value. - public T Set(T newValue) { - lock (lockObj) - return value = newValue; - } - /// Sets the value. - object IVolatile.Set(object newValue) { - lock (lockObj) - return value = (T) newValue; - } - - #endregion - - #region Conversion Operators - - /// Gets the of the . - public static implicit operator T(VolatileCompound value) { - return value.Value; - } - - #endregion - - #region Overrides - - /// Determines whether the specified object is equal to the current object. - public override bool Equals(object obj) { - if (obj is IVolatile vol) - return value.Equals(vol.Value); - return value.Equals(obj); - } - /// Returns the hash code for this instance. - public override int GetHashCode() => value.GetHashCode(); - /// Converts the value of this instance to its equivalent string representation. - public override string ToString() => value.ToString(); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Utils/Volatiles/VolatileDouble.cs b/WinDirStat.Net.Base/Utils/Volatiles/VolatileDouble.cs deleted file mode 100644 index d7abc79..0000000 --- a/WinDirStat.Net.Base/Utils/Volatiles/VolatileDouble.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; - -namespace WinDirStat.Net.Utils { - /// A mutable volatile that supports compound assignments. - public class VolatileDouble : Volatile { - - #region Constructors - - /// Constructs the default . - public VolatileDouble() { } - /// Constructs the with the specified value. - /// - /// The value to use. - public VolatileDouble(double value) : base(value) { } - /// Constructs the with the specified lock. - /// - /// The lock context to use. - public VolatileDouble(object lockObj) : base(lockObj) { } - /// Constructs the with the specified value and lock. - /// - /// The value to use. - /// The lock context to use. - public VolatileDouble(double value, object lockObj) : base(value, lockObj) { } - - #endregion - - #region Volatile Operators - - /// Adds to the value. - public double Add(double x) { - lock (lockObj) - return value += x; - } - /// Subtracts from the value. - public double Sub(double x) { - lock (lockObj) - return value -= x; - } - /// Multiplies the value. - public double Mul(double x) { - lock (lockObj) - return value *= x; - } - /// Divides the value. - public double Div(double x) { - lock (lockObj) - return value /= x; - } - /// Negates the value. - public double Negate() { - lock (lockObj) - return value = -value; - } - - #endregion - - #region Volatile Floating Operators - - /// Floors the value. - public double Floor() { - lock (lockObj) - return value = (double) Math.Floor(value); - } - /// Ceilings the value. - public double Ceiling() { - lock (lockObj) - return value = (double) Math.Ceiling(value); - } - /// Rounds the value. - public double Round() { - lock (lockObj) - return value = (double) Math.Round(value); - } - /// Truncates the value. - public double Truncate() { - lock (lockObj) - return value = (double) Math.Truncate(value); - } - /// Squares the value. - public double Sqr() { - lock (lockObj) - return value *= value; - } - /// Square roots the value. - public double Sqrt() { - lock (lockObj) - return value = (double) Math.Sqrt(value); - } - /// Powers the value. - public double Pow(double y) { - lock (lockObj) - return value = (double) Math.Pow(value, y); - } - /// Logs the value. - public double Log(double newBase) { - lock (lockObj) - return value = (double) Math.Log(value, newBase); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Utils/Volatiles/VolatileInt16.cs b/WinDirStat.Net.Base/Utils/Volatiles/VolatileInt16.cs deleted file mode 100644 index ff2ac8a..0000000 --- a/WinDirStat.Net.Base/Utils/Volatiles/VolatileInt16.cs +++ /dev/null @@ -1,81 +0,0 @@ - -namespace WinDirStat.Net.Utils { - /// A mutable volatile that supports compound assignments. - public class VolatileInt16 : Volatile { - - #region Constructors - - /// Constructs the default . - public VolatileInt16() { } - /// Constructs the with the specified value. - /// - /// The value to use. - public VolatileInt16(short value) : base(value) { } - /// Constructs the with the specified lock. - /// - /// The lock context to use. - public VolatileInt16(object lockObj) : base(lockObj) { } - /// Constructs the with the specified value and lock. - /// - /// The value to use. - /// The lock context to use. - public VolatileInt16(short value, object lockObj) : base(value, lockObj) { } - - #endregion - - #region Volatile Operators - - /// Adds to the value. - public short Add(short i) { - lock (lockObj) - return value += i; - } - /// Subtracts from the value. - public short Sub(short i) { - lock (lockObj) - return value -= i; - } - /// Multiplies the value. - public short Mul(short i) { - lock (lockObj) - return value *= i; - } - /// Divides the value. - public short Div(short i) { - lock (lockObj) - return value /= i; - } - /// Negates the value. - public short Negate() { - lock (lockObj) - return value = (short) -value; - } - - #endregion - - #region Volatile Bitwise Operators - - /// Bitwise AND's the value. - public short BitwiseAnd(short i) { - lock (lockObj) - return value &= i; - } - /// Bitwise OR's the value. - public short BitwiseOr(short i) { - lock (lockObj) - return value |= i; - } - /// Bitwise XOR's the value. - public short BitwiseXor(short i) { - lock (lockObj) - return value ^= i; - } - /// Bitwise negates the value. - public short BitwiseNegate() { - lock (lockObj) - return value = unchecked((short) ~value); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Utils/Volatiles/VolatileInt32.cs b/WinDirStat.Net.Base/Utils/Volatiles/VolatileInt32.cs deleted file mode 100644 index 45c9b0f..0000000 --- a/WinDirStat.Net.Base/Utils/Volatiles/VolatileInt32.cs +++ /dev/null @@ -1,81 +0,0 @@ - -namespace WinDirStat.Net.Utils { - /// A mutable volatile that supports compound assignments. - public class VolatileInt32 : Volatile { - - #region Constructors - - /// Constructs the default . - public VolatileInt32() { } - /// Constructs the with the specified value. - /// - /// The value to use. - public VolatileInt32(int value) : base(value) { } - /// Constructs the with the specified lock. - /// - /// The lock context to use. - public VolatileInt32(object lockObj) : base(lockObj) { } - /// Constructs the with the specified value and lock. - /// - /// The value to use. - /// The lock context to use. - public VolatileInt32(int value, object lockObj) : base(value, lockObj) { } - - #endregion - - #region Volatile Operators - - /// Adds to the value. - public int Add(int i) { - lock (lockObj) - return value += i; - } - /// Subtracts from the value. - public int Sub(int i) { - lock (lockObj) - return value -= i; - } - /// Multiplies the value. - public int Mul(int i) { - lock (lockObj) - return value *= i; - } - /// Divides the value. - public int Div(int i) { - lock (lockObj) - return value /= i; - } - /// Negates the value. - public int Negate() { - lock (lockObj) - return value = -value; - } - - #endregion - - #region Volatile Bitwise Operators - - /// Bitwise AND's the value. - public int BitwiseAnd(int i) { - lock (lockObj) - return value &= i; - } - /// Bitwise OR's the value. - public int BitwiseOr(int i) { - lock (lockObj) - return value |= i; - } - /// Bitwise XOR's the value. - public int BitwiseXor(int i) { - lock (lockObj) - return value ^= i; - } - /// Bitwise negates the value. - public int BitwiseNegate() { - lock (lockObj) - return value = ~value; - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Utils/Volatiles/VolatileInt64.cs b/WinDirStat.Net.Base/Utils/Volatiles/VolatileInt64.cs deleted file mode 100644 index 5d2f894..0000000 --- a/WinDirStat.Net.Base/Utils/Volatiles/VolatileInt64.cs +++ /dev/null @@ -1,81 +0,0 @@ - -namespace WinDirStat.Net.Utils { - /// A mutable volatile that supports compound assignments. - public class VolatileInt64 : Volatile { - - #region Constructors - - /// Constructs the default . - public VolatileInt64() { } - /// Constructs the with the specified value. - /// - /// The value to use. - public VolatileInt64(long value) : base(value) { } - /// Constructs the with the specified lock. - /// - /// The lock context to use. - public VolatileInt64(object lockObj) : base(lockObj) { } - /// Constructs the with the specified value and lock. - /// - /// The value to use. - /// The lock context to use. - public VolatileInt64(long value, object lockObj) : base(value, lockObj) { } - - #endregion - - #region Volatile Operators - - /// Adds to the value. - public long Add(long i) { - lock (lockObj) - return value += i; - } - /// Subtracts from the value. - public long Sub(long i) { - lock (lockObj) - return value -= i; - } - /// Multiplies the value. - public long Mul(long i) { - lock (lockObj) - return value *= i; - } - /// Divides the value. - public long Div(long i) { - lock (lockObj) - return value /= i; - } - /// Negates the value. - public long Negate() { - lock (lockObj) - return value = -value; - } - - #endregion - - #region Volatile Bitwise Operators - - /// Bitwise AND's the value. - public long BitwiseAnd(long i) { - lock (lockObj) - return value &= i; - } - /// Bitwise OR's the value. - public long BitwiseOr(long i) { - lock (lockObj) - return value |= i; - } - /// Bitwise XOR's the value. - public long BitwiseXor(long i) { - lock (lockObj) - return value ^= i; - } - /// Bitwise negates the value. - public long BitwiseNegate() { - lock (lockObj) - return value = ~value; - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/Utils/Volatiles/VolatileSingle.cs b/WinDirStat.Net.Base/Utils/Volatiles/VolatileSingle.cs deleted file mode 100644 index 8273b5a..0000000 --- a/WinDirStat.Net.Base/Utils/Volatiles/VolatileSingle.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; - -namespace WinDirStat.Net.Utils { - /// A mutable volatile that supports compound assignments. - public class VolatileSingle : Volatile { - - #region Constructors - - /// Constructs the default . - public VolatileSingle() { } - /// Constructs the with the specified value. - /// - /// The value to use. - public VolatileSingle(float value) : base(value) { } - /// Constructs the with the specified lock. - /// - /// The lock context to use. - public VolatileSingle(object lockObj) : base(lockObj) { } - /// Constructs the with the specified value and lock. - /// - /// The value to use. - /// The lock context to use. - public VolatileSingle(float value, object lockObj) : base(value, lockObj) { } - - #endregion - - #region Volatile Operators - - /// Adds to the value. - public float Add(float x) { - lock (lockObj) - return value += x; - } - /// Subtracts from the value. - public float Sub(float x) { - lock (lockObj) - return value -= x; - } - /// Multiplies the value. - public float Mul(float x) { - lock (lockObj) - return value *= x; - } - /// Divides the value. - public float Div(float x) { - lock (lockObj) - return value /= x; - } - /// Negates the value. - public float Negate() { - lock (lockObj) - return value = -value; - } - - #endregion - - #region Volatile Floating Operators - - /// Floors the value. - public float Floor() { - lock (lockObj) - return value = (float) Math.Floor(value); - } - /// Ceilings the value. - public float Ceiling() { - lock (lockObj) - return value = (float) Math.Ceiling(value); - } - /// Rounds the value. - public float Round() { - lock (lockObj) - return value = (float) Math.Round(value); - } - /// Truncates the value. - public float Truncate() { - lock (lockObj) - return value = (float) Math.Truncate(value); - } - /// Squares the value. - public float Sqr() { - lock (lockObj) - return value *= value; - } - /// Square roots the value. - public float Sqrt() { - lock (lockObj) - return value = (float) Math.Sqrt(value); - } - /// Powers the value. - public float Pow(float y) { - lock (lockObj) - return value = (float) Math.Pow(value, y); - } - /// Logs the value. - public float Log(float newBase) { - lock (lockObj) - return value = (float) Math.Log(value, newBase); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Commands/IRelayCommand.cs b/WinDirStat.Net.Base/ViewModel/Commands/IRelayCommand.cs deleted file mode 100644 index 6a49972..0000000 --- a/WinDirStat.Net.Base/ViewModel/Commands/IRelayCommand.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.ComponentModel; -using System.Windows.Input; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.ViewModel { - /// An interface for working with any type of RelayCommand. - public interface IRelayCommand : ICommand { - - #region CanExecuteChanged - - /// Raises the event. - void RaiseCanExecuteChanged(); - - #endregion - - #region Execute (No Parameter) - - /// Executes the method without a parameter. - void Execute(); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Commands/IRelayUICommand.cs b/WinDirStat.Net.Base/ViewModel/Commands/IRelayUICommand.cs deleted file mode 100644 index cdc4523..0000000 --- a/WinDirStat.Net.Base/ViewModel/Commands/IRelayUICommand.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.ComponentModel; -using System.Windows.Input; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.ViewModel { - /// An interface for working with generic and non-generic RelayUICommands. - public interface IRelayUICommand : IRelayCommand { - string Text { get; } - IImage Icon { get; } - IShortcut Shortcut { get; } - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Commands/RelayUICommand.Generic.cs b/WinDirStat.Net.Base/ViewModel/Commands/RelayUICommand.Generic.cs deleted file mode 100644 index d3da8f9..0000000 --- a/WinDirStat.Net.Base/ViewModel/Commands/RelayUICommand.Generic.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -#if WPF -using GalaSoft.MvvmLight.CommandWpf; -#else -using GalaSoft.MvvmLight.Command; -#endif - -namespace WinDirStat.Net.ViewModel { - public class RelayUICommand : RelayCommand, IRelayUICommand { - - #region Fields - - private string text; - private IImage icon; - private readonly IShortcut keyGesture; - - #endregion - - #region Constructors - - public RelayUICommand(string text, IImage icon, Action execute) - : this(text, icon, null, execute, null) - { - } - - public RelayUICommand(string text, IImage icon, Action execute, - Func canExecute) - : this(text, icon, null, execute, canExecute) - { - } - - public RelayUICommand(string text, IImage icon, IShortcut keyGesture, - Action execute) - : this(text, icon, keyGesture, execute, null) - { - } - - public RelayUICommand(string text, IImage icon, IShortcut keyGesture, - Action execute, Func canExecute) - : base(execute, canExecute) - { - this.text = text; - this.icon = icon; - this.keyGesture = keyGesture; - } - - #endregion - - #region Properties - - public string Text { - get => text; - set { - if (text != value) { - text = value; - RaisePropertyChanged(); - } - } - } - - public IImage Icon { - get => icon; - set { - if (icon != value) { - icon = value; - RaisePropertyChanged(); - } - } - } - - public IShortcut Shortcut { - get => keyGesture; - } - - #endregion - - #region Events - - /// Called when the or property has changed. - public event PropertyChangedEventHandler PropertyChanged; - - #endregion - - #region RaisePropertyChanged - - /// Raises the event. - protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Commands/RelayUICommand.cs b/WinDirStat.Net.Base/ViewModel/Commands/RelayUICommand.cs deleted file mode 100644 index 094bdfa..0000000 --- a/WinDirStat.Net.Base/ViewModel/Commands/RelayUICommand.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -#if WPF -using GalaSoft.MvvmLight.CommandWpf; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -#else -using GalaSoft.MvvmLight.Command; -#endif - -namespace WinDirStat.Net.ViewModel { - public class RelayUICommand : RelayCommand, IRelayUICommand { - - #region Fields - - private string text; - private IImage icon; - private readonly IShortcut keyGesture; - - #endregion - - #region Constructors - - public RelayUICommand(string text, IImage icon, Action execute) - : this(text, icon, null, execute, null) - { - } - - public RelayUICommand(string text, IImage icon, Action execute, - Func canExecute) - : this(text, icon, null, execute, canExecute) - { - } - - public RelayUICommand(string text, IImage icon, IShortcut keyGesture, - Action execute) - : this(text, icon, keyGesture, execute, null) - { - } - - public RelayUICommand(string text, IImage icon, IShortcut keyGesture, - Action execute, Func canExecute) - : base(execute, canExecute) - { - this.text = text; - this.icon = icon; - this.keyGesture = keyGesture; - } - - #endregion - - #region Properties - - public string Text { - get => text; - set { - if (text != value) { - text = value; - RaisePropertyChanged(); - } - } - } - - public IImage Icon { - get => icon; - set { - if (icon != value) { - icon = value; - RaisePropertyChanged(); - } - } - } - - public IShortcut Shortcut { - get => keyGesture; - } - - #endregion - - #region Events - - /// Called when the or property has changed. - public event PropertyChangedEventHandler PropertyChanged; - - #endregion - - #region RaisePropertyChanged - - /// Raises the event. - protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Comparers/DriveComparer.cs b/WinDirStat.Net.Base/ViewModel/Comparers/DriveComparer.cs deleted file mode 100644 index 95ca664..0000000 --- a/WinDirStat.Net.Base/ViewModel/Comparers/DriveComparer.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.ViewModel.Drives; - -namespace WinDirStat.Net.ViewModel.Comparers { - /// The sort mode for use in the drive select list. - [Serializable] - public enum DriveSortMode { - None, - Name, - Total, - Free, - UsedTotalBar, - UsedTotalPercent, - [Browsable(false)] - Count, - } - - /// The comparer for s. - public class DriveComparer : SortComparer { - - #region Constructors - - /// Constructs the default . - public DriveComparer() - : base(DriveSortMode.Name, ListSortDirection.Ascending) - { - } - - #endregion - - #region SortComparer Overrides - - /// A secondary comparison that's called when the sort mode comparison returns 0. - /// - /// The first item to compare. - /// The second item to compare. - /// The comparison result. - protected override Comparison GetSortComparison(DriveSortMode mode) { - switch (mode) { - case DriveSortMode.None: - case DriveSortMode.Name: - return SortByNameAndDriveType; - case DriveSortMode.Total: - return SortByTotal; - case DriveSortMode.Free: - return SortByFree; - case DriveSortMode.UsedTotalBar: - case DriveSortMode.UsedTotalPercent: - return SortByPercent; - default: - throw new ArgumentException($"Invalid {typeof(DriveSortMode).Name} ({mode})!", nameof(mode)); - } - } - - /// Gets the comparison method for the specified sort mode. - /// - /// The mode to get the comparison of. - /// The comparison to use. - protected override int SecondaryCompare(DriveItemViewModel a, DriveItemViewModel b) { - return string.Compare(a.Model.Name, b.Model.Name, true); - } - - #endregion - - #region Comparisons - - /// Scores the drives by type so that some are ordered before others. - private static int GetDriveTypeScore(DriveType type) { - switch (type) { - case DriveType.Fixed: return 0; - case DriveType.Removable: return 1; - case DriveType.CDRom: return 2; - case DriveType.Network: return 3; - case DriveType.NoRootDirectory: return 4; - case DriveType.Ram: return 5; - default: return 6; - } - } - - private static int SortByNameAndDriveType(DriveItemViewModel a, DriveItemViewModel b) { - int diff = GetDriveTypeScore(a.Model.DriveType) - GetDriveTypeScore(b.Model.DriveType); - if (diff == 0) - return SortByName(a, b); - return diff; - } - private static int SortByName(DriveItemViewModel a, DriveItemViewModel b) { - return string.Compare(a.Model.Name, b.Model.Name, true); - } - private static int SortByTotal(DriveItemViewModel a, DriveItemViewModel b) { - return a.Model.TotalSize.CompareTo(b.Model.TotalSize); - } - private static int SortByFree(DriveItemViewModel a, DriveItemViewModel b) { - return a.Model.FreeSpace.CompareTo(b.Model.FreeSpace); - } - private static int SortByPercent(DriveItemViewModel a, DriveItemViewModel b) { - return a.Model.Percent.CompareTo(b.Model.Percent); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Comparers/ExtensionComparer.cs b/WinDirStat.Net.Base/ViewModel/Comparers/ExtensionComparer.cs deleted file mode 100644 index ed6534f..0000000 --- a/WinDirStat.Net.Base/ViewModel/Comparers/ExtensionComparer.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.ViewModel.Extensions; - -namespace WinDirStat.Net.ViewModel.Comparers { - /// The sort mode for use in the file types list. - [Serializable] - public enum ExtensionSortMode { - None, - Extension, - Color, - Description, - Bytes, - Percent, - Files, - [Browsable(false)] - Count, - } - - /// The comparer for s. - public class ExtensionComparer : SortComparer { - - #region Constructors - - /// Constructs the default . - public ExtensionComparer() - : base(ExtensionSortMode.Bytes, ListSortDirection.Descending) - { - } - - #endregion - - #region SortComparer Overrides - - /// A secondary comparison that's called when the sort mode comparison returns 0. - /// - /// The first item to compare. - /// The second item to compare. - /// The comparison result. - protected override Comparison GetSortComparison(ExtensionSortMode mode) { - switch (mode) { - case ExtensionSortMode.None: - case ExtensionSortMode.Bytes: - case ExtensionSortMode.Percent: - case ExtensionSortMode.Color: return SortBySize; - case ExtensionSortMode.Extension: return SortByExtension; - case ExtensionSortMode.Description: return SortByDescription; - case ExtensionSortMode.Files: return SortByFiles; - default: - throw new ArgumentException($"Invalid {typeof(ExtensionSortMode).Name} ({mode})!", nameof(mode)); - } - } - - /// Gets the comparison method for the specified sort mode. - /// - /// The mode to get the comparison of. - /// The comparison to use. - protected override int SecondaryCompare(ExtensionItemViewModel a, ExtensionItemViewModel b) { - return string.Compare(a.Model.Extension, b.Model.Extension, true); - } - - #endregion - - #region Comparisons - - private static int SortByExtension(ExtensionItemViewModel a, ExtensionItemViewModel b) { - return string.Compare(a.Model.Extension, b.Model.Extension, true); - } - private static int SortByDescription(ExtensionItemViewModel a, ExtensionItemViewModel b) { - return string.Compare(a.TypeName, b.TypeName, true); - } - private static int SortBySize(ExtensionItemViewModel a, ExtensionItemViewModel b) { - return a.Model.Size.CompareTo(b.Model.Size); - } - private static int SortByFiles(ExtensionItemViewModel a, ExtensionItemViewModel b) { - return a.Model.FileCount - b.Model.FileCount; - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Comparers/FileComparer.cs b/WinDirStat.Net.Base/ViewModel/Comparers/FileComparer.cs deleted file mode 100644 index e1d1e30..0000000 --- a/WinDirStat.Net.Base/ViewModel/Comparers/FileComparer.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.ViewModel.Files; - -namespace WinDirStat.Net.ViewModel.Comparers { - /// The sort mode for use in the file tree. - [Serializable] - public enum FileSortMode { - None, - Name, - Subtree, - Percent, - Size, - Items, - Files, - Subdirs, - LastWrite, - LastAccess, - Creation, - Attributes, - [Browsable(false)] - Count, - } - - /// The comparer for s. - public class FileComparer : SortComparer { - - #region Constructors - - /// Constructs the default . - public FileComparer() - : base(FileSortMode.Size, ListSortDirection.Descending) - { - } - - #endregion - - #region SortComparer Overrides - - /// A secondary comparison that's called when the sort mode comparison returns 0. - /// - /// The first item to compare. - /// The second item to compare. - /// The comparison result. - protected override Comparison GetSortComparison(FileSortMode mode) { - switch (mode) { - case FileSortMode.None: - case FileSortMode.Size: - case FileSortMode.Percent: - case FileSortMode.Subtree: return SortBySize; - case FileSortMode.Name: return SortByName; - case FileSortMode.Items: return SortByItems; - case FileSortMode.Files: return SortByFiles; - case FileSortMode.Subdirs: return SortBySubdirs; - case FileSortMode.LastWrite: return SortByLastWrite; - //case FileSortMode.LastAccess: return SortByLastAccess; - //case FileSortMode.Creation: return SortByCreation; - case FileSortMode.Attributes: return SortByAttributes; - default: - throw new ArgumentException($"Invalid {typeof(FileSortMode).Name} ({mode})!", nameof(mode)); - } - } - - /// Gets the comparison method for the specified sort mode. - /// - /// The mode to get the comparison of. - /// The comparison to use. - protected override int SecondaryCompare(FileItemViewModel a, FileItemViewModel b) { - return string.Compare(a.Model.Name, b.Model.Name, true); - } - - #endregion - - #region Comparisons - - private static int SortByName(FileItemViewModel a, FileItemViewModel b) { - return string.Compare(a.Model.Name, b.Model.Name, true); - } - private static int SortBySize(FileItemViewModel a, FileItemViewModel b) { - return a.Model.Size.CompareTo(b.Model.Size); - } - private static int SortByItems(FileItemViewModel a, FileItemViewModel b) { - return a.Model.ItemCount - b.Model.ItemCount; - } - private static int SortByFiles(FileItemViewModel a, FileItemViewModel b) { - return a.Model.FileCount - b.Model.FileCount; - } - private static int SortBySubdirs(FileItemViewModel a, FileItemViewModel b) { - return a.Model.SubdirCount - b.Model.SubdirCount; - } - private static int SortByAttributes(FileItemViewModel a, FileItemViewModel b) { - return a.Model.SortAttributes.CompareTo(b.Model.SortAttributes); - } - private static int SortByLastWrite(FileItemViewModel a, FileItemViewModel b) { - return a.Model.LastWriteTimeUtc.CompareTo(b.Model.LastWriteTimeUtc); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Comparers/SortComparer.cs b/WinDirStat.Net.Base/ViewModel/Comparers/SortComparer.cs deleted file mode 100644 index bd6f19d..0000000 --- a/WinDirStat.Net.Base/ViewModel/Comparers/SortComparer.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using GalaSoft.MvvmLight; - -namespace WinDirStat.Net.ViewModel.Comparers { - /// A helper class for view model comparers. - /// The type of the view model. - /// The type that representings the sort mode. - public abstract class SortComparer : ObservableObject, IComparer, IComparer { - - #region Fields - - /// The current sort direction. - private ListSortDirection direction; - /// The current sort mode. - private TSortMode mode; - /// The current sort comparison. - private Comparison comparison; - - #endregion - - #region Constructor - - /// - /// Constructs the with the specified sort mode in ascending order. - /// - /// - /// The sort mode to start with. - protected SortComparer(TSortMode mode) { - Mode = mode; - } - - /// - /// Constructs the with the specified sort mode and direction. - /// - /// - /// The sort mode to start with. - /// The sort direction to start with. - protected SortComparer(TSortMode mode, ListSortDirection direction) { - Mode = mode; - Direction = direction; - } - - #endregion - - #region IComparer - - /// Compares the two items based on the sort mode and direction. - /// - /// The first item to compare. - /// The second item to compare. - /// The comparison result. - public int Compare(T a, T b) { - int diff = comparison(a, b); - // Always sort alphabetically after initial sort - if (diff == 0) - return SecondaryCompare(a, b); - if (direction == ListSortDirection.Ascending) - return diff; - else - return -diff; - } - /// Compares the two items based on the sort mode and direction. - /// - /// The first item to compare. - /// The second item to compare. - /// The comparison result. - int IComparer.Compare(object a, object b) { - return Compare((T) a, (T) b); - } - - #endregion - - #region Sort Settings - - /// Gets the mode that determines the primary comparison method. - public TSortMode Mode { - get => mode; - set { - if (!mode.Equals(value)) { - mode = value; - comparison = GetSortComparison(mode); - RaisePropertyChanged(); - } - } - } - /// Gets the direction of the sorting. - public ListSortDirection Direction { - get => direction; - set { - if (direction != value) { - direction = value; - RaisePropertyChanged(); - RaisePropertyChanged(nameof(IsDescending)); - } - } - } - /// Gets if the sort direction is in descending order. - public bool IsDescending { - get => direction == ListSortDirection.Descending; - set { - if (IsDescending != value) { - if (value) - direction = ListSortDirection.Descending; - else - direction = ListSortDirection.Ascending; - RaisePropertyChanged(nameof(Direction)); - RaisePropertyChanged(); - } - } - } - - #endregion - - #region Abstract Methods - - /// A secondary comparison that's called when the sort mode comparison returns 0. - /// - /// The first item to compare. - /// The second item to compare. - /// The comparison result. - protected abstract int SecondaryCompare(T a, T b); - - /// Gets the comparison method for the specified sort mode. - /// - /// The mode to get the comparison of. - /// The comparison to use. - protected abstract Comparison GetSortComparison(TSortMode mode); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/ConfigureViewModel.cs b/WinDirStat.Net.Base/ViewModel/ConfigureViewModel.cs deleted file mode 100644 index cff5950..0000000 --- a/WinDirStat.Net.Base/ViewModel/ConfigureViewModel.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services; - -namespace WinDirStat.Net.ViewModel { - /// The view model for the configure dialog. - public partial class ConfigureViewModel : ViewModelWindowBase { - - #region Fields - - // Services - /// Gets the program settings service. - public SettingsService Settings { get; } - /// Gets the UI service. - public IUIService UI { get; } - /// Gets the dialog service. - public IWindowDialogService Dialogs { get; } - - #endregion - - #region Constructors - - /// Constructrs the . - public ConfigureViewModel(SettingsService settings, - IUIService ui, - IWindowDialogService dialog) - { - Settings = settings; - UI = ui; - Dialogs = dialog; - } - - #endregion - - #region Override Properties - - /// Gets the title to display for the window. - public override string Title => "WinDirStat.Net - Settings"; - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/DriveSelectViewModel.Commands.cs b/WinDirStat.Net.Base/ViewModel/DriveSelectViewModel.Commands.cs deleted file mode 100644 index 6da8e36..0000000 --- a/WinDirStat.Net.Base/ViewModel/DriveSelectViewModel.Commands.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Model.Drives; - -#if WPF -using GalaSoft.MvvmLight.CommandWpf; -#else -using GalaSoft.MvvmLight.Command; -#endif - -namespace WinDirStat.Net.ViewModel { - partial class DriveSelectViewModel { - - public RelayCommand OK { - get => GetCommand(OnOK); - } - - public RelayCommand SelectFolder { - get => GetCommand(OnSelectFolder); - } - - private void OnOK() { - // Apply the settings for future use - Settings.DriveSelectMode = mode; - Settings.SelectedDrives = SelectedDrives.Select(d => d.Name).ToArray(); - Settings.SelectedFolderPath = folderPath; - Result = new DriveSelectResult(Scanning, - Settings.DriveSelectMode, - Settings.SelectedDrives, - Settings.SelectedFolderPath); - } - - private void OnSelectFolder() { - string newFolder = Dialogs.ShowFolderBrowser(WindowOwner, "WinDirStat.Net - Select Folder", false); - if (newFolder != null) { - FolderPath = newFolder; - } - } - - } -} diff --git a/WinDirStat.Net.Base/ViewModel/DriveSelectViewModel.Methods.cs b/WinDirStat.Net.Base/ViewModel/DriveSelectViewModel.Methods.cs deleted file mode 100644 index 45f4979..0000000 --- a/WinDirStat.Net.Base/ViewModel/DriveSelectViewModel.Methods.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Model.Drives; -using WinDirStat.Net.ViewModel.Drives; - -namespace WinDirStat.Net.ViewModel { - partial class DriveSelectViewModel { - - public void Loaded() { - SelectedDrives.Clear(); - Drives.Model.Refresh(); - Mode = Settings.DriveSelectMode; - FolderPath = Settings.SelectedFolderPath; - var drivesToSelect = Drives.Where(d => Settings.SelectedDrives.Any(n => d.Name == n)); - foreach (DriveItemViewModel drive in drivesToSelect) - SelectedDrives.Add(drive); - } - - public void SortDrives() { - Drives.Sort(DriveComparer.Compare); - } - - public void ListGotFocus() { - Mode = DriveSelectMode.Individual; - } - - } -} diff --git a/WinDirStat.Net.Base/ViewModel/DriveSelectViewModel.cs b/WinDirStat.Net.Base/ViewModel/DriveSelectViewModel.cs deleted file mode 100644 index dcd634f..0000000 --- a/WinDirStat.Net.Base/ViewModel/DriveSelectViewModel.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; -using WinDirStat.Net.Model.Drives; -using WinDirStat.Net.Services; -using WinDirStat.Net.ViewModel; -using WinDirStat.Net.ViewModel.Comparers; -using WinDirStat.Net.ViewModel.Drives; - -namespace WinDirStat.Net.ViewModel { - /// The view model for the drive select dialog. - public partial class DriveSelectViewModel : ViewModelWindowBase { - - #region Fields - - // Services - /// Gets the program settings service. - public SettingsService Settings { get; } - /// Gets the UI service. - public IUIService UI { get; } - /// Gets the dialog service. - public IWindowDialogService Dialogs { get; } - /// Gets the icon cache service. - public IIconCacheService IconCache { get; } - /// Gets the scanning service. - public ScanningService Scanning { get; } - - // Collections - /// Gets the drive collection. - public DriveItemViewModelCollection Drives { get; } - /// Gets the comparer for the drives. - public DriveComparer DriveComparer { get; } - - // Settings - /// The root path selection mode. - private DriveSelectMode mode; - /// Gets the selected individual drives. - public ObservableCollection SelectedDrives { get; } - /// The current folder path. - private string folderPath; - - // State - /// The result of the drive selection. - private DriveSelectResult result; - /// True if the current mode's selection is valid. - private bool validSelection; - - #endregion - - #region Constructors - - /// Constructrs the . - public DriveSelectViewModel(SettingsService settings, - IUIService ui, - IWindowDialogService dialog, - IIconCacheService iconCache, - ScanningService scanning) - { - Settings = settings; - UI = ui; - Dialogs = dialog; - IconCache = iconCache; - Scanning = scanning; - - Drives = new DriveItemViewModelCollection(this); - DriveComparer = new DriveComparer(); - - SelectedDrives = new ObservableCollection(); - SelectedDrives.CollectionChanged += OnSelectedDrivesChanged; - } - - #endregion - - #region Override Properties - - /// Gets the title to display for the window. - public override string Title => "WinDirStat.Net - Drive Select"; - - #endregion - - #region Properties - - /// Gets or sets the root path selection mode. - public DriveSelectMode Mode { - get => mode; - set { - if (mode != value) { - mode = value; - ValidateSelection(); - RaisePropertyChanged(); - } - } - } - - /// Gets or sets the current folder path. - public string FolderPath { - get => folderPath; - set { - if (folderPath != value) { - folderPath = value; - if (mode == DriveSelectMode.Folder) - ValidateSelection(); - RaisePropertyChanged(); - } - } - } - - /// Gets or sets if the current selection is valid. - public bool IsValidSelection { - get => validSelection; - private set { - if (validSelection != value) { - validSelection = value; - RaisePropertyChanged(); - } - } - } - - /// Gets the result root paths. - public DriveSelectResult Result { - get => result; - private set => Set(ref result, value); - } - - #endregion - - #region Validation - - /// Validates the current mode's selection. - private void ValidateSelection() { - switch (mode) { - case DriveSelectMode.All: - IsValidSelection = true; - break; - case DriveSelectMode.Individual: - IsValidSelection = SelectedDrives.Count > 0; - break; - case DriveSelectMode.Folder: - try { - IsValidSelection = Directory.Exists(Path.GetFullPath(folderPath)); - } - catch { - IsValidSelection = false; - } - break; - } - } - - #endregion - - #region Event Handlers - - /// Validates the selection when the drive selection changes. - private void OnSelectedDrivesChanged(object sender, NotifyCollectionChangedEventArgs e) { - if (mode == DriveSelectMode.Individual) - ValidateSelection(); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Drives/DriveItemViewModel.cs b/WinDirStat.Net.Base/ViewModel/Drives/DriveItemViewModel.cs deleted file mode 100644 index c04a7f7..0000000 --- a/WinDirStat.Net.Base/ViewModel/Drives/DriveItemViewModel.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; -using WinDirStat.Net.Model.Drives; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Utils; - -namespace WinDirStat.Net.ViewModel.Drives { - /// The view model that represents a drive item. - public class DriveItemViewModel : ObservableObject { - - #region Fields - - /// The collection containing this drive item view model. - private readonly DriveItemViewModelCollection drives; - /// The model that this view model represents. - public DriveItem Model { get; } - - /// The display icon for the drive. - private IImage icon; - /// The display name for the drive. - private string displayName; - - #endregion - - #region Constructors - - /// Constructs the see . - /// - /// The collection containing this drive item view model. - /// The model that this view model represents. - public DriveItemViewModel(DriveItemViewModelCollection drives, DriveItem model) { - this.drives = drives; - Model = model; - - IIconAndName iconName = IconCache.CacheIconAndDisplayName(Name); - if (iconName != null) { - Icon = iconName.Icon; - DisplayName = iconName.Name; - } - else { - Icon = IconCache.VolumeIcon; - DisplayName = $"({PathUtils.TrimSeparatorEnd(Name)})"; - } - } - - #endregion - - #region Properties - - /// Gets the display icon for the drive. - public IImage Icon { - get => icon; - private set => Set(ref icon, value); - } - - /// Gets the display name for the drive. - public string DisplayName { - get => displayName; - private set => Set(ref displayName, value); - } - - /// Gets the name/path of the drive. - public string Name => Model.Name; - /// Gets the total size of the drive. - public long TotalSize => Model.TotalSize; - /// Gets the freespace on the drive in bytes. - public long FreeSpace => Model.FreeSpace; - /// Gets the type of the drive. - public DriveType DriveType => Model.DriveType; - /// Gets the partition format of the drive. - public string DriveFormat => Model.DriveFormat; - /// Gets the used space on the drive in bytes. - public long UsedSpace => Model.UsedSpace; - /// Gets the used percentage of the drive. - public double Percent => Model.Percent; - - /// Gets the icon cache service. - private IIconCacheService IconCache => drives.IconCache; - - /// Gets the program settings service. - private SettingsService Settings => drives.Settings; - - /// Gets the icon cache mode setting. - private IconCacheMode CacheMode => drives.Settings.IconCacheMode; - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Drives/DriveItemViewModelCollection.cs b/WinDirStat.Net.Base/ViewModel/Drives/DriveItemViewModelCollection.cs deleted file mode 100644 index c2d329b..0000000 --- a/WinDirStat.Net.Base/ViewModel/Drives/DriveItemViewModelCollection.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Model.Drives; -using WinDirStat.Net.Services; - -namespace WinDirStat.Net.ViewModel.Drives { - /// A collection manager for s. - public class DriveItemViewModelCollection - : ObservablePropertyCollectionObject, IReadOnlyList - { - #region Fields - - /// Gets the drive select view model that contains this collection. - public DriveSelectViewModel ViewModel { get; } - /// Gets the model collection that this view model represents. - public DriveItems Model { get; } - - // Services - /// Gets the scanning service. - public ScanningService Scanning { get; } - /// Gets the icon cache service. - public IIconCacheService IconCache { get; } - /// Gets the program settings service. - public SettingsService Settings { get; } - /// Gets the UI service. - public IUIService UI { get; } - - /// The list of sorted drive items. - private readonly List drives; - - #endregion - - #region Constructors - - /// Constructs the . - /// - /// The main view model containing this collection. - public DriveItemViewModelCollection(DriveSelectViewModel viewModel) { - ViewModel = viewModel; - Scanning = ViewModel.Scanning; - Model = Scanning.Drives; - IconCache = ViewModel.IconCache; - Settings = ViewModel.Settings; - UI = ViewModel.UI; - - drives = new List(); - - Model.CollectionChanged += OnModelCollectionChanged; - } - - #endregion - - #region Event Handlers - - private void OnModelCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - UI.Invoke(() => { - switch (e.Action) { - case NotifyCollectionChangedAction.Reset: - drives.Clear(); - for (int i = 0; i < Model.Count; i++) { - DriveItem newItem = Model[i]; - DriveItemViewModel newItemViewModel = new DriveItemViewModel(this, newItem); - drives.Add(newItemViewModel); - } - Sort(ViewModel.DriveComparer.Compare); - //RaiseCollectionChanged(NotifyCollectionChangedAction.Reset); - break; - case NotifyCollectionChangedAction.Add: - //List newItemViewModels = new List(); - for (int i = 0; i < e.NewItems.Count; i++) { - DriveItem newItem = (DriveItem) e.NewItems[i]; - DriveItemViewModel newItemViewModel = new DriveItemViewModel(this, newItem); - drives.Add(newItemViewModel); - //newItemViewModels.Add(newItemViewModel); - } - Sort(ViewModel.DriveComparer.Compare); - //RaiseCollectionChanged(NotifyCollectionChangedAction.Add, newItemViewModels, e.NewStartingIndex); - break; - case NotifyCollectionChangedAction.Remove: - //List oldItemViewModels = new List(); - for (int i = 0; i < e.OldItems.Count; i++) { - DriveItem oldItem = (DriveItem) e.OldItems[i]; - DriveItemViewModel oldItemViewModel = drives.Find(d => d.Model == oldItem); - //oldItemViewModel.Dispose(); - drives.Remove(oldItemViewModel); - //oldItemViewModels.Add(oldItemViewModel); - } - Sort(ViewModel.DriveComparer.Compare); - //RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, oldItemViewModels, e.OldStartingIndex); - break; - } - }); - } - - #endregion - - #region Properties - - /// Gets the number of drives. - public int Count => drives.Count; - - /// Gets the drive item at the specified index in the collection. - public DriveItemViewModel this[int index] => drives[index]; - - #endregion - - #region Sort - - /// Sorts the collection based on the comparison. - /// - /// The comparison to sort with. - public void Sort(Comparison comparison) { - drives.Sort(comparison); - RaiseCollectionChanged(NotifyCollectionChangedAction.Reset); - } - - #endregion - - #region IEnumerator Implementation - - /// Gets the enumerator for the drive items. - IEnumerator IEnumerable.GetEnumerator() { - return drives.GetEnumerator(); - } - /// Gets the enumerator for the drive items. - IEnumerator IEnumerable.GetEnumerator() { - return drives.GetEnumerator(); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Extensions/ExtensionItemViewModel.cs b/WinDirStat.Net.Base/ViewModel/Extensions/ExtensionItemViewModel.cs deleted file mode 100644 index 1c52a2e..0000000 --- a/WinDirStat.Net.Base/ViewModel/Extensions/ExtensionItemViewModel.cs +++ /dev/null @@ -1,191 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; -using WinDirStat.Net.Model.Extensions; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.ViewModel.Extensions { - /// The view model that represents an . - public class ExtensionItemViewModel : ObservableObject, IDisposable { - - #region Constants - - /// The used to represent a non-file. - public static readonly ExtensionItemViewModel NotAFile = new ExtensionItemViewModel(); - - #endregion - - #region Fields - - /// The collection containing this item. - private readonly ExtensionItemViewModelCollection extensions; - /// Gets the model that this view model represents. - public ExtensionItem Model { get; } - - /// The icon of the associated file type. - private IImage icon; - /// The type name of the associated file type. - private string typeName; - /// The cache state for the icon. - private IconCacheState cacheState; - /// True if events have been hooked to the model. - private bool eventsHooked; - /// The preview image for the file palette color. - private IImage preview; - - #endregion - - #region Constructors - - /// - /// Constructs an used to represent a non-file. - /// - private ExtensionItemViewModel() { - Model = ExtensionItem.NotAFile; - } - - /// Constructs an . - /// - /// The collection containing this item. - /// The model that this view model item represents. - public ExtensionItemViewModel(ExtensionItemViewModelCollection extensions, ExtensionItem model) { - this.extensions = extensions; - Model = model; - icon = IconCache.FileIcon; - if (IsEmptyExtension || Extension.Contains(" ")) { - // Extensions with spaces have no rights, so says Windows - typeName = "File"; - cacheState = IconCacheState.Cached; - } - else { - typeName = model.Extension.TrimStart('.').ToUpper() + " File"; - if (CacheMode >= IconCacheMode.FileType) - LoadIcon(); - } - HookEvents(); - } - - /// Disposes of the . - /*~ExtensionItemViewModel() { - Dispose(); - }*/ - - #endregion - - #region Event Handlers - - private void OnModelChanged(ExtensionItem sender, ExtensionItemEventArgs e) { - switch (e.Action) { - case ExtensionItemAction.ColorChanged: - Preview = Settings.GetFilePalettePreview(e.Index); - break; - case ExtensionItemAction.GetViewModel: - e.ViewModel = this; - break; - } - } - - #endregion - - #region CacheIcon - - /// Attempts to load the icon if it has not already been loaded. - public void LoadIcon() { - if (cacheState == IconCacheState.NotCached) { - cacheState = IconCacheState.Caching; - IconCache.CacheFileTypeAsync(Extension, OnCacheIconAndTypeName); - } - } - - /// The callback for asynchronously caching the file type icon and type name. - /// - /// The resulting icon and type name. - private void OnCacheIconAndTypeName(IIconAndName iconName) { - if (iconName != null) { - Icon = iconName.Icon; - TypeName = iconName.Name; - } - // Even if "I failed, I failed, I failed", we're not gonna reattempt this - cacheState = IconCacheState.Cached; - } - - #endregion - - #region Properties - - /// Gets the name of the extension with the dot. - public string Extension => Model.Extension; - /// Gets the total size of all the files that use this extension. - public long Size => Model.Size; - /// Gets the number of files that use this extension. - public int FileCount => Model.FileCount; - /// Gets this extension's size relative to the total used space. - public double Percent => Model.Percent; - /// Gets if this extension is the empty extension with nothing after the dot. - public bool IsEmptyExtension => Model.IsEmptyExtension; - - /// Gets the icon of the associated file type. - public IImage Icon { - get => icon; - private set => Set(ref icon, value); - } - - /// Gets the type name of the associated file type. - public string TypeName { - get => typeName; - private set => Set(ref typeName, value); - } - - /// Gets the preview image for the file palette color. - public IImage Preview { - get => preview; - internal set => Set(ref preview, value); - } - - /// Gets the cache state for the icon. - public IconCacheState CacheState { - get => cacheState; - private set => Set(ref cacheState, value); - } - - /// Gets the icon cache service. - private IIconCacheService IconCache => extensions.IconCache; - - /// Gets the program settings service. - private SettingsService Settings => extensions.Settings; - - /// Gets the icon cache mode setting. - private IconCacheMode CacheMode => extensions.Settings.IconCacheMode; - - #endregion - - #region IDisposable Implementation - - /// Disposes of the . - public void Dispose() { - UnhookEvents(); - } - - /// Hooks up events to the model changed event. - private void HookEvents() { - if (!eventsHooked) { - eventsHooked = true; - Model.Changed += OnModelChanged; - } - } - - /// Unhooks events from the model changed event. - private void UnhookEvents() { - if (eventsHooked) { - eventsHooked = false; - Model.Changed -= OnModelChanged; - } - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Extensions/ExtensionItemViewModelCollection.cs b/WinDirStat.Net.Base/ViewModel/Extensions/ExtensionItemViewModelCollection.cs deleted file mode 100644 index 8d87939..0000000 --- a/WinDirStat.Net.Base/ViewModel/Extensions/ExtensionItemViewModelCollection.cs +++ /dev/null @@ -1,208 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Model.Extensions; -using WinDirStat.Net.Services; -using WinDirStat.Net.Utils; -using static WinDirStat.Net.Model.Extensions.ExtensionItem; - -namespace WinDirStat.Net.ViewModel.Extensions { - /// A collection manager for s. - public class ExtensionItemViewModelCollection - : ObservablePropertyCollectionObject, IReadOnlyList - { - #region Fields - - /// Gets the main view model that contains this collection. - public MainViewModel ViewModel { get; } - public ScanningService Scanning { get; } - public ExtensionItems Model { get; } - public IIconCacheService IconCache { get; } - /// Gets the images service. - public ImagesServiceBase Images { get; } - public SettingsService Settings { get; } - public IUIService UI { get; } - - /// The collection of mapped extension items. - private readonly Dictionary extensions; - /// The list of sorted extension items. - private readonly List sortedExtensions; - /// - /// True if the file tree scanner is not open, and the collection should hide all extensions. - /// - private bool isNotOpen; - - #endregion - - #region Constructors - - /// Constructs the . - /// - /// The main view model containing this collection. - public ExtensionItemViewModelCollection(MainViewModel viewModel) { - ViewModel = viewModel; - Scanning = ViewModel.Scanning; - Model = ViewModel.Scanning.Extensions; - IconCache = ViewModel.IconCache; - Images = ViewModel.Images; - Settings = ViewModel.Settings; - UI = ViewModel.UI; - - isNotOpen = false; - extensions = new Dictionary(); - sortedExtensions = new List(); - - ViewModel.Scanning.PropertyChanged += OnScanningPropertyChanged; - Model.CollectionChanged += OnModelCollectionChanged; - } - - #endregion - - #region Properties - - /// Gets the number of extensions. This value is always zero while scanning/refreshing. - public int Count => (isNotOpen ? 0 : extensions.Count); - - /// Gets if the scanner is not open and this collection should hide its items. - private bool IsNotOpen { - get => isNotOpen; - set { - if (isNotOpen != value) { - isNotOpen = value; - if (extensions.Count > 0) { - UI.Invoke(() => { - RaisePropertyChanged(nameof(Count)); - RaiseCollectionChanged(NotifyCollectionChangedAction.Reset); - }); - } - } - } - } - - #endregion - - #region Event Handlers - - private void OnScanningPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { - switch (e.PropertyName) { - case nameof(ScanningService.IsOpen): - IsNotOpen = !Scanning.IsOpen; - break; - } - } - - private void OnModelCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - // We must be sorting, nothing to do here - if (!IsNotOpen && e.Action == NotifyCollectionChangedAction.Reset) - return; - - Debug.Assert(IsNotOpen, "Cannot change collection while not scanning!"); - - switch (e.Action) { - case NotifyCollectionChangedAction.Reset: - sortedExtensions.Clear(); - for (int i = 0; i < sortedExtensions.Count; i++) { - ExtensionItemViewModel oldItemViewModel = sortedExtensions[i]; - oldItemViewModel.Dispose(); - } - extensions.Clear(); - for (int i = 0; i < Model.Count; i++) { - ExtensionItem newItem = Model[i]; - ExtensionItemViewModel newItemViewModel = new ExtensionItemViewModel(this, newItem); - sortedExtensions.Add(newItemViewModel); - extensions.Add(newItem.Extension, newItemViewModel); - } - break; - case NotifyCollectionChangedAction.Add: - for (int i = 0; i < e.NewItems.Count; i++) { - ExtensionItem newItem = (ExtensionItem) e.NewItems[i]; - ExtensionItemViewModel newItemViewModel = new ExtensionItemViewModel(this, newItem); - sortedExtensions.Add(newItemViewModel); - extensions.Add(newItem.Extension, newItemViewModel); - } - break; - case NotifyCollectionChangedAction.Remove: - for (int i = 0; i < e.OldItems.Count; i++) { - ExtensionItem oldItem = (ExtensionItem) e.OldItems[i]; - ExtensionItemViewModel oldItemViewModel = extensions[oldItem.Extension]; - oldItemViewModel.Dispose(); - sortedExtensions.Remove(oldItemViewModel); - extensions.Remove(oldItem.Extension); - } - break; - } - } - - #endregion - - #region Sort - - /// Sorts the collection based on the comparison. - /// - /// The comparison to sort with. - public void Sort(Comparison comparison) { - sortedExtensions.Sort(comparison); - RaiseCollectionChanged(NotifyCollectionChangedAction.Reset); - } - - #endregion - - #region Accessors - - /// Gets the extension item at the specified index in the collection. - public ExtensionItemViewModel this[int index] { - get { - if (IsNotOpen) - throw new IndexOutOfRangeException(nameof(index)); - return sortedExtensions[index]; - } - } - - /// Gets the extension item in the collection with the specified extension. - public ExtensionItemViewModel this[string extension] { - get => extensions[NormalizeExtension(extension)]; - } - - /// Gets if the collection contains the extension. - /// - /// The extension to check for. - /// True if the collection contains the extension. - public bool ContainsExtension(string extension) { - return extensions.ContainsKey(NormalizeExtension(extension)); - } - - /// Tries to get the extension item associated with the extension. - /// - /// The extension of the item to look for. - /// The output item result. - /// True if the extension was found. - public bool TryGetItem(string extension, out ExtensionItemViewModel item) { - return extensions.TryGetValue(NormalizeExtension(extension), out item); - } - - #endregion - - #region IEnumeratable Implementation - - /// Gets the enumerator for the sorted extension list. - public IEnumerator GetEnumerator() { - if (IsNotOpen) - return Enumerator.Empty(); - return sortedExtensions.GetEnumerator(); - } - - /// Gets the enumerator for the sorted extension list. - IEnumerator IEnumerable.GetEnumerator() { - if (IsNotOpen) - return Enumerator.Empty(); - return sortedExtensions.GetEnumerator(); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Files/Collection/FileItemViewModelCollection.cs b/WinDirStat.Net.Base/ViewModel/Files/Collection/FileItemViewModelCollection.cs deleted file mode 100644 index d1e21d2..0000000 --- a/WinDirStat.Net.Base/ViewModel/Files/Collection/FileItemViewModelCollection.cs +++ /dev/null @@ -1,394 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics; -using System.Linq; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Utils; - -namespace WinDirStat.Net.ViewModel.Files { - /// The internal modifiable collection. - internal class FileItemViewModelCollection - : ObservableCollectionObject, IList, IReadOnlyFileItemViewModelCollection - { - #region Fields - - /// The owner of this collection. - private readonly FileItemViewModel parent; - /// The collection of file item view models. - private readonly List list = new List(); - - #endregion - - #region Constructors - - /// Constructs a for empty use. - public FileItemViewModelCollection() { - // Empty collection for readonly use only - } - - /// Constructs a for normal use. - /// - /// The owner of this collection. - public FileItemViewModelCollection(FileItemViewModel parent) { - this.parent = parent; - } - - #endregion - - #region RaiseCollectionReset - - /// - /// Raises a special collection reset event, which allows the to - /// properly make changes to the list. - /// - /// - /// The new current list of the collection. - /// The old list of the collection. - private void RaiseCollectionReset(List list, List oldList) { - Debug.Assert(!IsRaisingEvent); - IsRaisingEvent = true; - try { - parent.OnChildrenReset(list, oldList); - InvokeCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - } - finally { - IsRaisingEvent = false; - } - } - - /// Raises a new event. - /// - /// The arguments for the event. - protected override void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e) { - //Debug.Assert(!isRaisingEvent); - ThrowOnReentrancy(); - IsRaisingEvent = true; - try { - parent.OnChildrenChanged(e); - InvokeCollectionChanged(e); - } - finally { - IsRaisingEvent = false; - } - } - - #endregion - - #region Throw Helpers - - /// Throws an exception if the item is not valid for adding to the collection. - /// - /// The item to check. - private void ThrowIfValueIsNullOrHasParent(FileItemViewModel item) { - if (item == null) - throw new ArgumentNullException(nameof(item)); - if (item.Parent != null) - throw new ArgumentException("The item already has a parent", nameof(item)); - } - - #endregion - - #region Properties - - /// Gets or sets the item at the specified index in the collection. - public FileItemViewModel this[int index] { - get => list[index]; - set { - ThrowOnReentrancy(); - var oldItem = list[index]; - if (oldItem == value) - return; - ThrowIfValueIsNullOrHasParent(value); - list[index] = value; - RaiseCollectionChanged(NotifyCollectionChangedAction.Replace, value, oldItem, index); - } - } - - /// Gets the number of items in the collection. - public int Count => list.Count; - - #endregion - - #region Sorting - - /// Sorts the collection based on the comparison. - /// - /// The comparison to sort with. - public void Sort(Comparison comparison) { - if (list.Count > 0) { - List oldList = list.GetFullRange(); - list.Sort(comparison); - RaiseCollectionReset(list, oldList); - } - } - - #endregion - - #region Accessors - - /// Checks if the collection contains the specified view model item. - /// - /// The view model item to check for. - /// True if the collection contains the item. - public bool Contains(FileItemViewModel item) { - return IndexOf(item) >= 0; - } - - /// Checks if the collection contains the specified model item. - /// - /// The model item to check for. - /// True if the collection contains the item. - public bool Contains(FileItem item) { - return IndexOf(item) >= 0; - } - - /// Gets the index of the specified view model item in the collection. - /// - /// The item to get the index of. - /// The index of the item if it exists in the collection, otherwise -1. - public int IndexOf(FileItemViewModel item) { - if (item == null || item.Parent != parent) - return -1; - else - return list.IndexOf(item); - } - - /// Gets the index of the specified model item in the collection. - /// - /// The item to get the index of. - /// The index of the item if it exists in the collection, otherwise -1. - public int IndexOf(FileItemBase item) { - if (item == null) - return -1; - else - return list.FindIndex(n => n.Model == item); - } - - /// Finds the view model item that contains this model item. - /// - /// The model item to look for. - /// The view model item that contains this model item, null if none was found. - public FileItemViewModel Find(FileItemBase item) { - return list.Find(v => v.Model == item); - } - - /// Converts the collection to an array. - /// - /// The new array of the elements. - public FileItemViewModel[] ToArray() { - return list.ToArray(); - } - - /// Copies the collection to the specified array. - /// - /// The array to copy the items to. - /// The index to start copying items to in the array. - public void CopyTo(FileItemViewModel[] array, int arrayIndex) { - list.CopyTo(array, arrayIndex); - } - - #endregion - - #region Add - - /// Adds the item to the end of collection. - /// - /// The item to add. - public void Add(FileItemViewModel item) { - ThrowOnReentrancy(); - ThrowIfValueIsNullOrHasParent(item); - //item.Parent = parent; - list.Add(item); - RaiseCollectionChanged(NotifyCollectionChangedAction.Add, item, list.Count - 1); - } - - /*public void AddSilent(FileItemViewModel item) { - ThrowOnReentrancy(); - ThrowIfValueIsNullOrHasParent(item); - list.Add(item); - }*/ - - /// Adds the items to the end of collection. - /// - /// The items to add. - public void AddRange(IEnumerable items) { - InsertRange(list.Count, items); - } - - #endregion - - #region Insert - - /// Inserts the item at the specified index in the collection. - /// - /// The index to insert at. - /// The item to insert. - public void Insert(int index, FileItemViewModel item) { - ThrowOnReentrancy(); - ThrowIfValueIsNullOrHasParent(item); - //item.Parent = parent; - list.Insert(index, item); - RaiseCollectionChanged(NotifyCollectionChangedAction.Add, item, index); - } - - /// Inserts the items at the specified index in the collection. - /// - /// The index to insert at. - /// The items to insert. - public void InsertRange(int index, IEnumerable items) { - if (items == null) - throw new ArgumentNullException(nameof(items)); - ThrowOnReentrancy(); - List newItems = items.ToList(); - if (newItems.Count == 0) - return; - foreach (FileItemViewModel item in newItems) { - ThrowIfValueIsNullOrHasParent(item); - //item.Parent = parent; - } - list.InsertRange(index, newItems); - RaiseCollectionChanged(NotifyCollectionChangedAction.Add, newItems, index); - } - - #endregion - - #region Remove - - /// Removes the items at the specified index in the collection. - /// - /// The index to remove the item at. - public void RemoveAt(int index) { - ThrowOnReentrancy(); - var oldItem = list[index]; - //oldItem.Parent = null; - list.RemoveAt(index); - RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, oldItem, index); - } - - /// Removes the itemss at the specified index in the collection. - /// - /// The index to remove the items at. - /// The number of items to remove. - public void RemoveRange(int index, int count) { - ThrowOnReentrancy(); - if (count == 0) - return; - var oldItems = list.GetRange(index, count); - //for (int i = 0; i < oldItems.Count; i++) - // oldItems[i].Parent = null; - list.RemoveRange(index, count); - RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, oldItems, index); - } - - /// Removes the specified view model item from the collection. - /// - /// The view model item to remove. - /// True if the item was found and removed. - public bool Remove(FileItemViewModel item) { - int pos = IndexOf(item); - if (pos >= 0) { - RemoveAt(pos); - return true; - } - else { - return false; - } - } - - /// Removes the specified model item from the collection. - /// - /// The model item to remove. - /// True if the item was found and removed. - public bool Remove(FileItemBase item) { - int pos = list.FindIndex(n => n.Model == item); - if (pos >= 0) { - RemoveAt(pos); - return true; - } - else { - return false; - } - } - - /*public void RemoveAll(Predicate match) { - if (match == null) - throw new ArgumentNullException(nameof(match)); - ThrowOnReentrancy(); - int firstToRemove = 0; - for (int i = 0; i < list.Count; i++) { - bool removeItem; - IsRaisingEvent = true; - try { - removeItem = match(list[i]); - } - finally { - IsRaisingEvent = false; - } - if (!removeItem) { - if (firstToRemove < i) { - RemoveRange(firstToRemove, i - firstToRemove); - i = firstToRemove - 1; - } - else { - firstToRemove = i + 1; - } - Debug.Assert(firstToRemove == i + 1); - } - } - if (firstToRemove < list.Count) { - RemoveRange(firstToRemove, list.Count - firstToRemove); - } - }*/ - - #endregion - - #region Move - - /*public void Move(int index, int oldIndex) { - ThrowOnReentrancy(); - FileItemViewModel item = list[oldIndex]; - list.RemoveAt(oldIndex); - list.Insert(index, item); - RaiseCollectionChanged(NotifyCollectionChangedAction.Move, item, index, oldIndex); - }*/ - - #endregion - - #region Clear - - /// Clears the collection. - public void Clear() { - ThrowOnReentrancy(); - if (list.Count > 0) { - //var oldList = new List(list); - //list.Clear(); - var oldList = list.GetFullRange(); - //for (int i = 0; i < oldList.Count; i++) - // oldList[i].Parent = null; - list.Clear(); - RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, oldList, 0); - } - } - - #endregion - - #region Explicit Interface Implementation - - /// Gets if the collection is readonly - it is not. - bool ICollection.IsReadOnly => false; - - /// Gets the enumerator for the collection. - IEnumerator IEnumerable.GetEnumerator() { - return list.GetEnumerator(); - } - - /// Gets the enumerator for the collection. - IEnumerator IEnumerable.GetEnumerator() { - return list.GetEnumerator(); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Files/Collection/IReadOnlyFileItemViewModelCollection.cs b/WinDirStat.Net.Base/ViewModel/Files/Collection/IReadOnlyFileItemViewModelCollection.cs deleted file mode 100644 index 45a4cc3..0000000 --- a/WinDirStat.Net.Base/ViewModel/Files/Collection/IReadOnlyFileItemViewModelCollection.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.ViewModel.Files { - /// - /// The public interface for the readonly part of the collection. - /// - public interface IReadOnlyFileItemViewModelCollection - : INotifyCollectionChanged, IReadOnlyList - { - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModel.Flags.cs b/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModel.Flags.cs deleted file mode 100644 index 81109ce..0000000 --- a/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModel.Flags.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.ViewModel.Files { - partial class FileItemViewModel { - - private FileItemViewModelFlags flags = FileItemViewModelFlags.None; - -#pragma warning disable 0649, IDE1006 - /*private bool isVisible { - get => flags.HasFlag(FileNodeViewFlags.Visible); - set => flags.SetFlag(FileNodeViewFlags.Visible, value); - }*/ - private bool isHidden { - get => flags.HasFlag(FileItemViewModelFlags.Hidden); - set => flags = flags.SetFlag(FileItemViewModelFlags.Hidden, value); - } - private bool isSelected { - get => flags.HasFlag(FileItemViewModelFlags.Selected); - set => flags = flags.SetFlag(FileItemViewModelFlags.Selected, value); - } - private bool isExpanded { - get => flags.HasFlag(FileItemViewModelFlags.Expanded); - set => flags = flags.SetFlag(FileItemViewModelFlags.Expanded, value); - } - private bool isEditing { - get => flags.HasFlag(FileItemViewModelFlags.Editing); - set => flags = flags.SetFlag(FileItemViewModelFlags.Editing, value); - } - private bool isEventsHooked { - get => flags.HasFlag(FileItemViewModelFlags.EventsHooked); - set => flags = flags.SetFlag(FileItemViewModelFlags.EventsHooked, value); - } - private bool isWaitingForExtensionIcon { - get => flags.HasFlag(FileItemViewModelFlags.WaitingForExtensionIcon); - set => flags = flags.SetFlag(FileItemViewModelFlags.WaitingForExtensionIcon, value); - } - private bool exists { - get => flags.HasFlag(FileItemViewModelFlags.Exists); - set => flags = flags.SetFlag(FileItemViewModelFlags.Exists, value); - } -#pragma warning restore 0649, IDE1006 - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModel.FlatList.cs b/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModel.FlatList.cs deleted file mode 100644 index b6d9c85..0000000 --- a/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModel.FlatList.cs +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -namespace WinDirStat.Net.ViewModel.Files { - // This part of SharpTreeNode controls the 'flat list' data structure, which emulates - // a big flat list containing the whole tree; allowing access by visible index. - partial class FileItemViewModel { - /// The parent in the flat list - internal FileItemViewModel listParent; - /// Left/right nodes in the flat list - private FileItemViewModel left, right; - - internal FileTreeFlattener treeFlattener; - - /// Subtree height in the flat list tree - private byte height = 1; - - /// Length in the flat list, including children (children within the flat list). -1 = invalidated - private int totalListLength = -1; - - private int Balance { - get { return Height(right) - Height(left); } - } - - static int Height(FileItemViewModel node) { - return node != null ? node.height : 0; - } - - internal FileItemViewModel GetListRoot() { - FileItemViewModel node = this; - while (node.listParent != null) - node = node.listParent; - return node; - } - - #region Debugging - [Conditional("DEBUG")] - void CheckRootInvariants() { - GetListRoot().CheckInvariants(); - } - - [Conditional("DATACONSISTENCYCHECK")] - void CheckInvariants() { - Debug.Assert(left == null || left.listParent == this); - Debug.Assert(right == null || right.listParent == this); - Debug.Assert(height == 1 + Math.Max(Height(left), Height(right))); - Debug.Assert(Math.Abs(this.Balance) <= 1); - Debug.Assert(totalListLength == -1 || totalListLength == (left != null ? left.totalListLength : 0) + (isVisible ? 1 : 0) + (right != null ? right.totalListLength : 0)); - if (left != null) left.CheckInvariants(); - if (right != null) right.CheckInvariants(); - } - - [Conditional("DEBUG")] - static void DumpTree(FileItemViewModel node) { - node.GetListRoot().DumpTree(); - } - - [Conditional("DEBUG")] - void DumpTree() { - Debug.Indent(); - if (left != null) - left.DumpTree(); - Debug.Unindent(); - Debug.WriteLine("{0}, totalListLength={1}, height={2}, Balance={3}, isVisible={4}", ToString(), totalListLength, height, Balance, isVisible); - Debug.Indent(); - if (right != null) - right.DumpTree(); - Debug.Unindent(); - } - #endregion - - #region GetNodeByVisibleIndex / GetVisibleIndexForNode - internal static FileItemViewModel GetNodeByVisibleIndex(FileItemViewModel root, int index) { - root.GetTotalListLength(); // ensure all list lengths are calculated - Debug.Assert(index >= 0); - Debug.Assert(index < root.totalListLength); - FileItemViewModel node = root; - while (true) { - if (node.left != null && index < node.left.totalListLength) { - node = node.left; - } - else { - if (node.left != null) { - index -= node.left.totalListLength; - } - if (node.isVisible) { - if (index == 0) - return node; - index--; - } - node = node.right; - } - } - } - - internal static int GetVisibleIndexForNode(FileItemViewModel node) { - int index = node.left != null ? node.left.GetTotalListLength() : 0; - while (node.listParent != null) { - if (node == node.listParent.right) { - if (node.listParent.left != null) - index += node.listParent.left.GetTotalListLength(); - if (node.listParent.isVisible) - index++; - } - node = node.listParent; - } - return index; - } - #endregion - - #region Balancing - /// - /// Balances the subtree rooted in and recomputes the 'height' field. - /// This method assumes that the children of this node are already balanced and have an up-to-date 'height' value. - /// - /// The new root node - static FileItemViewModel Rebalance(FileItemViewModel node) { - Debug.Assert(node.left == null || Math.Abs(node.left.Balance) <= 1); - Debug.Assert(node.right == null || Math.Abs(node.right.Balance) <= 1); - // Keep looping until it's balanced. Not sure if this is stricly required; this is based on - // the Rope code where node merging made this necessary. - while (Math.Abs(node.Balance) > 1) { - // AVL balancing - // note: because we don't care about the identity of concat nodes, this works a little different than usual - // tree rotations: in our implementation, the "this" node will stay at the top, only its children are rearranged - if (node.Balance > 1) { - if (node.right.Balance < 0) { - node.right = node.right.RotateRight(); - } - node = node.RotateLeft(); - // If 'node' was unbalanced by more than 2, we've shifted some of the inbalance to the left node; so rebalance that. - node.left = Rebalance(node.left); - } - else if (node.Balance < -1) { - if (node.left.Balance > 0) { - node.left = node.left.RotateLeft(); - } - node = node.RotateRight(); - // If 'node' was unbalanced by more than 2, we've shifted some of the inbalance to the right node; so rebalance that. - node.right = Rebalance(node.right); - } - } - Debug.Assert(Math.Abs(node.Balance) <= 1); - node.height = (byte) (1 + Math.Max(Height(node.left), Height(node.right))); - node.totalListLength = -1; // mark for recalculation - // since balancing checks the whole tree up to the root, the whole path will get marked as invalid - return node; - } - - internal int GetTotalListLength() { - if (totalListLength >= 0) - return totalListLength; - int length = (isVisible ? 1 : 0); - if (left != null) { - length += left.GetTotalListLength(); - } - if (right != null) { - length += right.GetTotalListLength(); - } - return totalListLength = length; - } - - FileItemViewModel RotateLeft() { - /* Rotate tree to the left - * - * this right - * / \ / \ - * A right ===> this C - * / \ / \ - * B C A B - */ - FileItemViewModel b = right.left; - FileItemViewModel newTop = right; - - if (b != null) b.listParent = this; - this.right = b; - newTop.left = this; - newTop.listParent = this.listParent; - this.listParent = newTop; - // rebalance the 'this' node - this is necessary in some bulk insertion cases: - newTop.left = Rebalance(this); - return newTop; - } - - FileItemViewModel RotateRight() { - /* Rotate tree to the right - * - * this left - * / \ / \ - * left C ===> A this - * / \ / \ - * A B B C - */ - FileItemViewModel b = left.right; - FileItemViewModel newTop = left; - - if (b != null) b.listParent = this; - this.left = b; - newTop.right = this; - newTop.listParent = this.listParent; - this.listParent = newTop; - newTop.right = Rebalance(this); - return newTop; - } - - static void RebalanceUntilRoot(FileItemViewModel pos) { - while (pos.listParent != null) { - if (pos == pos.listParent.left) { - pos = pos.listParent.left = Rebalance(pos); - } - else { - Debug.Assert(pos == pos.listParent.right); - pos = pos.listParent.right = Rebalance(pos); - } - pos = pos.listParent; - } - FileItemViewModel newRoot = Rebalance(pos); - if (newRoot != pos && pos.treeFlattener != null) { - Debug.Assert(newRoot.treeFlattener == null); - newRoot.treeFlattener = pos.treeFlattener; - pos.treeFlattener = null; - newRoot.treeFlattener.root = newRoot; - } - Debug.Assert(newRoot.listParent == null); - newRoot.CheckInvariants(); - } - #endregion - - #region Insertion - static void InsertNodeAfter(FileItemViewModel pos, FileItemViewModel newNode) { - // newNode might be the model root of a whole subtree, so go to the list root of that subtree: - newNode = newNode.GetListRoot(); - if (pos.right == null) { - pos.right = newNode; - newNode.listParent = pos; - } - else { - // insert before pos.right's leftmost: - pos = pos.right; - while (pos.left != null) - pos = pos.left; - Debug.Assert(pos.left == null); - pos.left = newNode; - newNode.listParent = pos; - } - RebalanceUntilRoot(pos); - } - #endregion - - #region Removal - void RemoveNodes(FileItemViewModel start, FileItemViewModel end) { - // Removes all nodes from start to end (inclusive) - // All removed nodes will be reorganized in a separate tree, do not delete - // regions that don't belong together in the tree model! - - List removedSubtrees = new List(); - FileItemViewModel oldPos; - FileItemViewModel pos = start; - do { - // recalculate the endAncestors every time, because the tree might have been rebalanced - HashSet endAncestors = new HashSet(); - for (FileItemViewModel tmp = end; tmp != null; tmp = tmp.listParent) - endAncestors.Add(tmp); - - removedSubtrees.Add(pos); - if (!endAncestors.Contains(pos)) { - // we can remove pos' right subtree in a single step: - if (pos.right != null) { - removedSubtrees.Add(pos.right); - pos.right.listParent = null; - pos.right = null; - } - } - FileItemViewModel succ = pos.Successor(); - DeleteNode(pos); // this will also rebalance out the deletion of the right subtree - - oldPos = pos; - pos = succ; - } while (oldPos != end); - - // merge back together the removed subtrees: - FileItemViewModel removed = removedSubtrees[0]; - for (int i = 1; i < removedSubtrees.Count; i++) { - removed = ConcatTrees(removed, removedSubtrees[i]); - } - } - - static FileItemViewModel ConcatTrees(FileItemViewModel first, FileItemViewModel second) { - FileItemViewModel tmp = first; - while (tmp.right != null) - tmp = tmp.right; - InsertNodeAfter(tmp, second); - return tmp.GetListRoot(); - } - - FileItemViewModel Successor() { - if (right != null) { - FileItemViewModel node = right; - while (node.left != null) - node = node.left; - return node; - } - else { - FileItemViewModel node = this; - FileItemViewModel oldNode; - do { - oldNode = node; - node = node.listParent; - // loop while we are on the way up from the right part - } while (node != null && node.right == oldNode); - return node; - } - } - - static void DeleteNode(FileItemViewModel node) { - FileItemViewModel balancingNode; - if (node.left == null) { - balancingNode = node.listParent; - node.ReplaceWith(node.right); - node.right = null; - } - else if (node.right == null) { - balancingNode = node.listParent; - node.ReplaceWith(node.left); - node.left = null; - } - else { - FileItemViewModel tmp = node.right; - while (tmp.left != null) - tmp = tmp.left; - // First replace tmp with tmp.right - balancingNode = tmp.listParent; - tmp.ReplaceWith(tmp.right); - tmp.right = null; - Debug.Assert(tmp.left == null); - Debug.Assert(tmp.listParent == null); - // Now move node's children to tmp: - tmp.left = node.left; node.left = null; - tmp.right = node.right; node.right = null; - if (tmp.left != null) tmp.left.listParent = tmp; - if (tmp.right != null) tmp.right.listParent = tmp; - // Then replace node with tmp - node.ReplaceWith(tmp); - if (balancingNode == node) - balancingNode = tmp; - } - Debug.Assert(node.listParent == null); - Debug.Assert(node.left == null); - Debug.Assert(node.right == null); - node.height = 1; - node.totalListLength = -1; - if (balancingNode != null) - RebalanceUntilRoot(balancingNode); - } - - void ReplaceWith(FileItemViewModel node) { - if (listParent != null) { - if (listParent.left == this) { - listParent.left = node; - } - else { - Debug.Assert(listParent.right == this); - listParent.right = node; - } - if (node != null) - node.listParent = listParent; - listParent = null; - } - else { - // this was a root node - Debug.Assert(node != null); // cannot delete the only node in the tree - node.listParent = null; - if (treeFlattener != null) { - Debug.Assert(node.treeFlattener == null); - node.treeFlattener = this.treeFlattener; - this.treeFlattener = null; - node.treeFlattener.root = node; - } - } - } - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModel.TreeNode.cs b/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModel.TreeNode.cs deleted file mode 100644 index 6fe0575..0000000 --- a/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModel.TreeNode.cs +++ /dev/null @@ -1,771 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using WinDirStat.Net.Services; - -namespace WinDirStat.Net.ViewModel.Files { - partial class FileItemViewModel { - - private bool isVisible = true; - /*private bool isHidden; - private bool isSelected; - private bool isExpanded; - private bool isEditing;*/ - - /*private BitField16 flags = new BitField16 { - //[0] = true, - }; - -#pragma warning disable 0649, IDE1006 - private bool isVisible { - get => flags[0]; - set => flags[0] = value; - } - private bool isHidden { - get => flags[1]; - set => flags[1] = value; - } - private bool isSelected { - get => flags[2]; - set => flags[2] = value; - } - private bool isExpanded { - get => flags[3]; - set => flags[3] = value; - } - private bool isEditing { - get => flags[4]; - set => flags[4] = value; - } - private bool isEventsHooked { - get => flags[5]; - set => flags[5] = value; - } -#pragma warning restore 0649, IDE1006*/ - - //private bool canExpandRecursively = true; - //private bool lazyLoading; - //private bool? isChecked; - - private void UpdateIsVisible(bool parentIsVisible, bool updateFlattener) { - bool newIsVisible = parentIsVisible && !isHidden; - if (isVisible != newIsVisible) { - isVisible = newIsVisible; - - // invalidate the augmented data - FileItemViewModel node = this; - while (node != null && node.totalListLength >= 0) { - node.totalListLength = -1; - node = node.listParent; - } - // Remember the removed nodes: - List removedNodes = null; - if (updateFlattener && !newIsVisible) { - removedNodes = VisibleDescendantsAndSelf().ToList(); - } - // also update the model children: - UpdateChildIsVisible(false); - - // Validate our invariants: - if (updateFlattener) - CheckRootInvariants(); - - // Tell the flattener about the removed nodes: - if (removedNodes != null) { - var flattener = GetListRoot().treeFlattener; - if (flattener != null) { - if (!SuppressRefresh) - flattener.NodesRemoved(GetVisibleIndexForNode(this), removedNodes); - foreach (var n in removedNodes) - n.OnIsVisibleChanged(); - } - } - // Tell the flattener about the new nodes: - if (updateFlattener && newIsVisible) { - var flattener = GetListRoot().treeFlattener; - if (flattener != null) { - if (!SuppressRefresh) - flattener.NodesInserted(GetVisibleIndexForNode(this), VisibleDescendantsAndSelf()); - foreach (var n in VisibleDescendantsAndSelf()) - n.OnIsVisibleChanged(); - } - } - } - } - - protected void OnIsVisibleChanged() { } - - private void UpdateChildIsVisible(bool updateFlattener) { - if (children != null && children.Count > 0) { - bool showChildren = isVisible && isExpanded; - foreach (FileItemViewModel child in children) { - child.UpdateIsVisible(showChildren, updateFlattener); - } - } - } - - #region Main - - public IReadOnlyFileItemViewModelCollection Children { - get { - if (Model.IsContainerType) { - if (children == null) - children = new FileItemViewModelCollection(this); - return children; - } - return EmptyChildren; - } - } - - //public IBrush Foreground => IBrush.Black; - - public int Level => Parent != null ? Parent.Level + 1 : 0; - - public bool IsRoot => Parent == null; - - public bool IsHidden { - get => isHidden; - set { - if (isHidden != value) { - isHidden = value; - if (parent != null) - UpdateIsVisible(parent.isVisible && parent.isExpanded, true); - RaisePropertyChanged(); - if (Parent != null) - Parent.RaisePropertyChanged(nameof(ShowExpander)); - } - } - } - - /// - /// Return true when this node is not hidden and when all parent nodes are expanded and not hidden. - /// - public bool IsVisible => isVisible; - - public bool IsSelected { - get => isSelected; - set { - if (isSelected != value) { - isSelected = value; - RaisePropertyChanged(); - } - } - } - - #endregion - - #region OnChildrenChanged - - internal protected void RaiseChildrenReset() { - Stopwatch watch = Stopwatch.StartNew(); - GetListRoot().treeFlattener.NodesReset(); - Console.WriteLine($"Took {watch.ElapsedMilliseconds}ms to reset"); - } - - internal protected void OnChildrenReset(List newList, List oldList) { - foreach (FileItemViewModel node in oldList) { - Debug.Assert(node.parent == this); - - //if (node.isHidden) - // continue; - - node.Parent = null; - //Debug.WriteLine("Removing {0} from {1}", node, this); - FileItemViewModel removeEnd = node; - while (removeEnd.children != null && removeEnd.children.Count > 0) - removeEnd = removeEnd.children.Last(); - - List removedNodes = null; - int visibleIndexOfRemoval = 0; - if (node.isVisible) { - visibleIndexOfRemoval = GetVisibleIndexForNode(node); - removedNodes = node.VisibleDescendantsAndSelf().ToList(); - } - - RemoveNodes(node, removeEnd); - } - - FileItemViewModel insertionPos = null; - - foreach (FileItemViewModel node in newList) { - Debug.Assert(node.Model.Parent != null); - Debug.Assert(node.parent == null); - node.Parent = this; - node.UpdateIsVisible(isVisible && isExpanded, false); - //Debug.WriteLine("Inserting {0} after {1}", node, insertionPos); - - while (insertionPos != null && insertionPos.children != null && insertionPos.children.Count > 0) { - insertionPos = insertionPos.children.Last(); - } - InsertNodeAfter(insertionPos ?? this, node); - - insertionPos = node; - } - - if (!SuppressRefresh) { - var flattener = GetListRoot().treeFlattener; - if (flattener != null) { - flattener.NodesReset(); - } - } - - RaisePropertyChanged(nameof(ShowExpander)); - if (newList.Count > 0) { - if (oldList.Count > 0) { - if (newList[newList.Count - 1] != oldList[oldList.Count - 1]) { - oldList[oldList.Count - 1].RaisePropertyChanged(nameof(IsLast)); - newList[newList.Count - 1].RaisePropertyChanged(nameof(IsLast)); - } - } - else { - newList[newList.Count - 1].RaisePropertyChanged(nameof(IsLast)); - } - } - else if (oldList.Count > 0) { - oldList[oldList.Count - 1].RaisePropertyChanged(nameof(IsLast)); - } - //RaiseIsLastChangedIfNeeded(e); - } - internal protected void OnChildrenChanged(NotifyCollectionChangedEventArgs e) { - Debug.WriteLine(e.Action); - if (e.OldItems != null) { - foreach (FileItemViewModel node in e.OldItems) { - Debug.Assert(node.parent == this); - - //if (node.isHidden) - // continue; - - node.Parent = null; - //Debug.WriteLine("Removing {0} from {1}", node, this); - FileItemViewModel removeEnd = node; - while (removeEnd.children != null && removeEnd.children.Count > 0) - removeEnd = removeEnd.children.Last(); - - List removedNodes = null; - int visibleIndexOfRemoval = 0; - if (node.isVisible) { - visibleIndexOfRemoval = GetVisibleIndexForNode(node); - removedNodes = node.VisibleDescendantsAndSelf().ToList(); - } - - RemoveNodes(node, removeEnd); - - if (removedNodes != null && !SuppressRefresh) { - var flattener = GetListRoot().treeFlattener; - if (flattener != null) { - flattener.NodesRemoved(visibleIndexOfRemoval, removedNodes); - } - } - } - } - if (e.NewItems != null) { - FileItemViewModel insertionPos; - if (e.NewStartingIndex == 0) - insertionPos = null; - else - insertionPos = children[e.NewStartingIndex - 1]; - - foreach (FileItemViewModel node in e.NewItems) { - Debug.Assert(node.Model.Parent != null); - Debug.Assert(node.parent == null); - node.Parent = this; - node.UpdateIsVisible(isVisible && isExpanded, false); - //Debug.WriteLine("Inserting {0} after {1}", node, insertionPos); - - while (insertionPos != null && insertionPos.children != null && insertionPos.children.Count > 0) { - insertionPos = insertionPos.children.Last(); - } - InsertNodeAfter(insertionPos ?? this, node); - - insertionPos = node; - if (node.isVisible && !SuppressRefresh) { - var flattener = GetListRoot().treeFlattener; - if (flattener != null) { - flattener.NodesInserted(GetVisibleIndexForNode(node), node.VisibleDescendantsAndSelf()); - } - } - } - } - - RaisePropertyChanged(nameof(ShowExpander)); - RaiseIsLastChangedIfNeeded(e); - } - #endregion - - #region Expanding / LazyLoading - - public bool ShowExpander { - get => Model.HasChildren; - } - - public bool IsExpanded { - get => isExpanded; - set { - if (isExpanded != value) { - isExpanded = value; - if (isExpanded) { - OnExpanding(); - } - else { - OnCollapsing(); - } - UpdateChildIsVisible(true); - RaisePropertyChanged(); - } - } - } - - //protected virtual void OnExpanding() { } - //protected virtual void OnCollapsing() { } - - /*public bool LazyLoading { - get => lazyLoading; - set { - lazyLoading = value; - if (lazyLoading) { - IsExpanded = false; - if (canExpandRecursively) { - canExpandRecursively = false; - RaisePropertyChanged("CanExpandRecursively"); - } - } - RaisePropertyChanged("LazyLoading"); - RaisePropertyChanged("ShowExpander"); - } - }*/ - - /// - /// Gets whether this node can be expanded recursively. - /// If not overridden, this property returns false if the node is using lazy-loading, and true otherwise. - /// - public bool CanExpandRecursively { - get => false;// ItemCount <= 500; - } - - /*public bool ShowIcon { - get { return Icon != null; } - } - - protected void LoadChildren() { - throw new NotSupportedException(GetType().Name + " does not support lazy loading"); - } - - /// - /// Ensures the children were initialized (loads children if lazy loading is enabled) - /// - public void EnsureLazyChildren() { - if (LazyLoading) { - LazyLoading = false; - LoadChildren(); - } - }*/ - - #endregion - - #region Ancestors / Descendants - - public IEnumerable Descendants() { - return FileTreeTraversal.PreOrder(this.Children, n => n.Children); - } - - public IEnumerable VirtualDescendants() { - return FileTreeTraversal.PreOrder(this.Children, n => n.Children); - } - - public IEnumerable DescendantsAndSelf() { - return FileTreeTraversal.PreOrder(this, n => n.Children); - } - - public IEnumerable VisibleDescendants() { - return FileTreeTraversal.PreOrder(this.Children.Where(c => c.isVisible), n => n.Children.Where(c => c.isVisible)); - } - - public IEnumerable VisibleDescendantsAndSelf() { - return FileTreeTraversal.PreOrder(this, n => n.Children.Where(c => c.isVisible)); - } - - public IEnumerable Ancestors() { - for (FileItemViewModel n = this.Parent; n != null; n = n.Parent) - yield return n; - } - - public IEnumerable AncestorsAndSelf() { - for (FileItemViewModel n = this; n != null; n = n.Parent) - yield return n; - } - - #endregion - - #region Editing - - public bool IsEditable { - get => false; - } - - public bool IsEditing { - get => isEditing; - set { - if (isEditing != value) { - isEditing = value; - RaisePropertyChanged(); - } - } - } - - public string LoadEditText() { - return null; - } - - public bool SaveEditText(string value) { - return true; - } - - #endregion - - #region Checkboxes (Disabled) - - /*public bool IsCheckable { - get => false; - } - - public bool? IsChecked { - get => isChecked; - set { - SetIsChecked(value, true); - } - } - - void SetIsChecked(bool? value, bool update) { - if (isChecked != value) { - isChecked = value; - - if (update) { - if (IsChecked != null) { - foreach (var child in Descendants()) { - if (child.IsCheckable) { - child.SetIsChecked(IsChecked, false); - } - } - } - - foreach (var parent in Ancestors()) { - if (parent.IsCheckable) { - if (!parent.TryValueForIsChecked(true)) { - if (!parent.TryValueForIsChecked(false)) { - parent.SetIsChecked(null, false); - } - } - } - } - } - - RaisePropertyChanged("IsChecked"); - } - } - - bool TryValueForIsChecked(bool? value) { - if (Children.Where(n => n.IsCheckable).All(n => n.IsChecked == value)) { - SetIsChecked(value, false); - return true; - } - return false; - }*/ - - #endregion - - #region Cut / Copy / Paste / Delete (Disabled) - - /// - /// Gets whether the node should render transparently because it is 'cut' (but not actually removed yet). - /// - /*public bool IsCut { - get => false; - }*/ - /* - static List cuttedNodes = new List(); - static IDataObject cuttedData; - static EventHandler requerySuggestedHandler; // for weak event - - static void StartCuttedDataWatcher() - { - requerySuggestedHandler = new EventHandler(CommandManager_RequerySuggested); - CommandManager.RequerySuggested += requerySuggestedHandler; - } - - static void CommandManager_RequerySuggested(object sender, EventArgs e) - { - if (cuttedData != null && !Clipboard.IsCurrent(cuttedData)) { - ClearCuttedData(); - } - } - - static void ClearCuttedData() - { - foreach (var node in cuttedNodes) { - node.IsCut = false; - } - cuttedNodes.Clear(); - cuttedData = null; - } - - //static public IEnumerable PurifyNodes(IEnumerable nodes) - //{ - // var list = nodes.ToList(); - // var array = list.ToArray(); - // foreach (var node1 in array) { - // foreach (var node2 in array) { - // if (node1.Descendants().Contains(node2)) { - // list.Remove(node2); - // } - // } - // } - // return list; - //} - - bool isCut; - - public bool IsCut - { - get { return isCut; } - private set - { - isCut = value; - RaisePropertyChanged("IsCut"); - } - } - - internal bool InternalCanCut() - { - return InternalCanCopy() && InternalCanDelete(); - } - - internal void InternalCut() - { - ClearCuttedData(); - cuttedData = Copy(ActiveNodesArray); - Clipboard.SetDataObject(cuttedData); - - foreach (var node in ActiveNodes) { - node.IsCut = true; - cuttedNodes.Add(node); - } - } - - internal bool InternalCanCopy() - { - return CanCopy(ActiveNodesArray); - } - - internal void InternalCopy() - { - Clipboard.SetDataObject(Copy(ActiveNodesArray)); - } - - internal bool InternalCanPaste() - { - return CanPaste(Clipboard.GetDataObject()); - } - - internal void InternalPaste() - { - Paste(Clipboard.GetDataObject()); - - if (cuttedData != null) { - DeleteCore(cuttedNodes.ToArray()); - ClearCuttedData(); - } - } - */ - - /*public bool CanDelete(WinDirNode[] nodes) { - return false; - } - - public void Delete(WinDirNode[] nodes) { - throw new NotSupportedException(GetType().Name + " does not support deletion"); - } - - public void DeleteWithoutConfirmation(WinDirNode[] nodes) { - throw new NotSupportedException(GetType().Name + " does not support deletion"); - } - - public bool CanCut(WinDirNode[] nodes) { - return CanCopy(nodes) && CanDelete(nodes); - } - - public void Cut(WinDirNode[] nodes) { - var data = GetDataObject(nodes); - if (data != null) { - // TODO: default cut implementation should not immediately perform deletion, but use 'IsCut' - Clipboard.SetDataObject(data, copy: true); - DeleteWithoutConfirmation(nodes); - } - } - - public bool CanCopy(WinDirNode[] nodes) { - return false; - } - - public void Copy(WinDirNode[] nodes) { - var data = GetDataObject(nodes); - if (data != null) - Clipboard.SetDataObject(data, copy: true); - } - - protected IDataObject GetDataObject(WinDirNode[] nodes) { - return null; - } - - public bool CanPaste(IDataObject data) { - return false; - } - - public void Paste(IDataObject data) { - throw new NotSupportedException(GetType().Name + " does not support copy/paste"); - }*/ - #endregion - - #region Drag and Drop (Disabled) - /*public void StartDrag(DependencyObject dragSource, WinDirNode[] nodes) { - // The default drag implementation works by reusing the copy infrastructure. - // Derived classes should override this method - var data = GetDataObject(nodes); - if (data == null) - return; - DragDropEffects effects = DragDropEffects.Copy; - if (CanDelete(nodes)) - effects |= DragDropEffects.Move; - DragDropEffects result = DragDrop.DoDragDrop(dragSource, data, effects); - if (result == DragDropEffects.Move) { - DeleteWithoutConfirmation(nodes); - } - } - - /// - /// Gets the possible drop effects. - /// If the method returns more than one of (Copy|Move|Link), the tree view will choose one effect based - /// on the allowed effects and keyboard status. - /// - public DragDropEffects GetDropEffect(DragEventArgs e, int index) { - // Since the default drag implementation uses Copy(), - // we'll use Paste() in our default drop implementation. - if (CanPaste(e.Data)) { - // If Ctrl is pressed -> copy - // If moving is not allowed -> copy - // Otherwise: move - if ((e.KeyStates & DragDropKeyStates.ControlKey) != 0 || (e.AllowedEffects & DragDropEffects.Move) == 0) - return DragDropEffects.Copy; - return DragDropEffects.Move; - } - return DragDropEffects.None; - } - - internal void InternalDrop(DragEventArgs e, int index) { - if (LazyLoading) { - EnsureLazyChildren(); - index = Children.Count; - } - - Drop(e, index); - } - - public void Drop(DragEventArgs e, int index) { - // Since the default drag implementation uses Copy(), - // we'll use Paste() in our default drop implementation. - Paste(e.Data); - }*/ - #endregion - - #region IsLast (for TreeView lines) - - public bool IsLast { - get => Parent == null || Parent.Children[Parent.Children.Count - 1] == this; - } - - void RaiseIsLastChangedIfNeeded(NotifyCollectionChangedEventArgs e) { - switch (e.Action) { - case NotifyCollectionChangedAction.Add: - if (e.NewStartingIndex == Children.Count - 1) { - if (Children.Count > 1) { - Children[Children.Count - 2].RaisePropertyChanged("IsLast"); - } - Children[Children.Count - 1].RaisePropertyChanged("IsLast"); - } - break; - case NotifyCollectionChangedAction.Remove: - if (e.OldStartingIndex == Children.Count) { - if (Children.Count > 0) { - Children[Children.Count - 1].RaisePropertyChanged("IsLast"); - } - } - break; - } - } - - #endregion - - #region INotifyPropertyChanged Members (Disabled) - - /*public event PropertyChangedEventHandler PropertyChanged { - add { } - remove { } - //add => PropertyChanged += value; - //remove => PropertyChanged -= value; - }*/ - /*public event PropertyChangedEventHandler PropertyChanged; - - protected internal void RaisePropertyChanged(string name) { - //visualInfo?.RaisePropertyChanged(this, new PropertyChangedEventArgs(name)); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); - } - - protected internal void RaisePropertiesChanged(params string[] names) { - for (int i = 0; i < names.Length; i++) - RaisePropertyChanged(names[i]); - } - - protected internal void AutoRaisePropertyChanged([CallerMemberName] string name = null) { - //visualInfo?.RaisePropertyChanged(this, new PropertyChangedEventArgs(name)); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); - }*/ - - #endregion - - #region Model (Disabled) - /// - /// Gets the underlying model object. - /// - /// - /// This property calls the virtual helper method. - /// I didn't make the property itself virtual because deriving classes - /// may wish to replace it with a more specific return type, - /// but C# doesn't support variance in override declarations. - /// - /*public object Model { - get => GetModel(); - } - - protected virtual object GetModel() { - return null; - }*/ - #endregion - - /// - /// Gets called when the item is double-clicked. - /// - public void ActivateItem() { - } - - public override string ToString() { - // used for keyboard navigation - return Name ?? string.Empty; - } - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModel.cs b/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModel.cs deleted file mode 100644 index cfdbf93..0000000 --- a/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModel.cs +++ /dev/null @@ -1,657 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Utils; -using WinDirStat.Net.ViewModel.Extensions; - -namespace WinDirStat.Net.ViewModel.Files { - /// A view model for displaying models. - public partial class FileItemViewModel : ObservableObject, IDisposable { - - #region Constants - - /// The collection used for empty children to avoid wasting memory. - private static readonly FileItemViewModelCollection EmptyChildren = new FileItemViewModelCollection(); - - #endregion - - #region Fields - - /// The loaded, visible children of the view model item. - private FileItemViewModelCollection children; - /// The parent of the view model item. - private FileItemViewModel parent; - /// The loaded icon of the view model item. - private IImage icon; - /// The loaded display name of the view model item. Only used with certain types. - private string displayName; - - /// The main view model containing this item. - public MainViewModel ViewModel { get; } - /// The model this item represents. - public FileItemBase Model { get; } - /// The extension item view model associated with this item. - public ExtensionItemViewModel ExtensionItem { get; } - - #endregion - - #region Constructors - - /// Constructs the . - /// - /// The main view model containing this item. - /// The model this item represents. - public FileItemViewModel(MainViewModel viewModel, FileItemBase model) { - ViewModel = viewModel; - Model = model; - if (model.Type == FileItemType.File) - ExtensionItem = model.ExtensionItem.GetViewModel(); - else - ExtensionItem = ExtensionItemViewModel.NotAFile; - Debug.Assert(ExtensionItem != null); - - exists = model.Exists; - HookEvents(); - LoadIcon(); - } - - /// Disposes of the . - /*~FileItemViewModel() { - Dispose(); - }*/ - - #endregion - - #region Properties - - /// Gets the parent of the item. - public FileItemViewModel Parent { - get => parent; - private set => Set(ref parent, value); - } - /// Gets the icon of the item. - public IImage Icon { - get => icon; - private set => Set(ref icon, value); - } - - /// Gets the overlay icon if there is one. - public IImage OverlayIcon { - get { - if (!Exists) - return Images.Missing; - else if (IsShortcut) - return IconCache.ShortcutIcon; - return null; - } - } - - /// Gets the display name of the item. (This may be null) - public string DisplayName { - get => displayName; - private set { - if (Set(ref displayName, value)) - RaisePropertyChanged(nameof(Header)); - } - } - - /// Gets the extension of the item. - public string Extension => Model.Extension; - - /// Gets the name of the file. - public string Name => Model.Name; - - /// Gets the path of the file. - public string FullName { - get { - if (Model.Parent != null || Model.IsAbsoluteRootType) - return Model.FullName; - return ""; - } - } - - /// Gets the type of this file item. - public FileItemType Type => Model.Type; - - /// Gets the total size of the file and all of its children. - public long Size => Model.Size; - - /// Gets this file's size relative to the parent's size. - public double Percent { - get { - if (Model.Parent != null || Model.IsAbsoluteRootType) - return Model.Percent; - return 0d; - } - } - - /// - /// Gets the local time of when the file was last written to. - /// If this is a container, it returns the most recent time of all children. - /// - public DateTime LastWriteTime => Model.LastWriteTime; - - /// - /// Gets the number of files and directories this folder contains. Returns -1 if this is not a - /// container. - /// - public int ItemCount => Model.ItemCount; - /// - /// Gets the number of files this folder contains. Returns -1 if this is not a container. - /// - public int FileCount => Model.FileCount; - /// - /// Gets the number of directories this folder contains. Returns -1 if this is not a container. - /// - public int SubdirCount => Model.SubdirCount; - - /// Gets the attributes for this file. - public FileAttributes Attributes => Model.Attributes; - - /// Gets the attributes for this file. - public string AttributesString => Model.AttributesString; - - /// Gets if the item should display a shortcut overlay. - public bool IsShortcut => Model.IsShortcut; - - /// Gets the root view model item containing this view model item. - public FileItemViewModel Root { - get { - if (parent == null) - return this; - return parent.Root; - } - } - - /// Gets the display tooltip for the view model item. - public string ToolTip { - get { - if (Model.Type == FileItemType.Computer) - return StringConstants.ComputerName; - if (Model.Parent != null || Model.IsAbsoluteRootType) - return Model.FullName; - return ""; - } - } - - /// Gets the display header for the view model item. - public string Header { - get { - if (Type == FileItemType.Volume || Type == FileItemType.Computer) - return displayName ?? $"({PathUtils.TrimSeparatorEnd(Name)})"; - else - return Model.Name; - } - } - - /// Gets if file still exists in the system. - public bool Exists { - get => exists; - private set { - if (exists != value) { - exists = value; - RaisePropertyChanged(); - RaisePropertyChanged(nameof(OverlayIcon)); - } - } - } - - /// Gets the method for how icons are cached and displayed. - private IconCacheMode CacheMode => ViewModel.Settings.IconCacheMode; - - /// Gets the UI service. - private IUIService UI => ViewModel.UI; - - /// Gets the images service. - private ImagesServiceBase Images => ViewModel.Images; - - /// Gets the icon cache service. - private IIconCacheService IconCache => ViewModel.IconCache; - - /// Gets if the UI refreshing should be supressed due to validation. - private bool SuppressRefresh => ViewModel.SuppressFileTreeRefresh; - - #endregion - - #region CacheIcon - - /// Caches the file's icon. - private void LoadIcon(bool basicLoad = false) { - IconCacheMode cacheMode = CacheMode; - if (cacheMode == IconCacheMode.None) - return; - IIconAndName iconName; - switch (Type) { - case FileItemType.File: - if (cacheMode >= IconCacheMode.FileType) { - SetIcon(ExtensionItem.Icon); - if (cacheMode >= IconCacheMode.Individual) { - IconCache.CacheIconAsync(FullName, OnCacheFileIcon); - } - else if (ExtensionItem.CacheState != IconCacheState.Cached) { - // Hook an event to wait for the cache state to change - isWaitingForExtensionIcon = true; - ExtensionItem.PropertyChanged += OnExtensionItemPropertyChanged; - } - } - else { - SetIcon(IconCache.FileIcon); - } - break; - case FileItemType.Directory: - SetIcon(IconCache.FolderIcon); - if (cacheMode >= IconCacheMode.Individual) - IconCache.CacheIconAsync(FullName, OnCacheFolderIcon); - break; - case FileItemType.Volume: - if (cacheMode >= IconCacheMode.Individual) { - iconName = IconCache.CacheIconAndDisplayName(FullName); - SetIconAndDisplayName(iconName, IconCache.VolumeIcon, Name); - } - else { - SetIcon(IconCache.VolumeIcon); - } - break; - case FileItemType.Computer: - if (CacheMode != IconCacheMode.None) { - iconName = IconCache.CacheSpecialFolder(Environment.SpecialFolder.MyComputer); - SetIconAndDisplayName(iconName, null, Name); - } - break; - case FileItemType.FileCollection: - SetIcon(Images.FileCollection); - break; - case FileItemType.FreeSpace: - SetIcon(Images.FreeSpace); - break; - case FileItemType.Unknown: - SetIcon(Images.UnknownSpace); - break; - } - } - - /// - /// The callback for when a property of the extension item has changed. - /// This is only used to wait for the file type icon to be cached. - /// - private void OnExtensionItemPropertyChanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == nameof(ExtensionItem.CacheState)) { - if (ExtensionItem.CacheState == IconCacheState.Cached) { - SetIcon(ExtensionItem.Icon); - // Unhook event - isWaitingForExtensionIcon = false; - ExtensionItem.PropertyChanged -= OnExtensionItemPropertyChanged; - } - } - } - - /// Sets the icon and raises the associated property change. - /// - /// The icon to use. - /// True if the was non-null and was assigned. - private bool SetIcon(IImage icon) { - if (icon != null) { - this.icon = icon; - RaisePropertyChanged(nameof(Icon)); - return true; - } - return false; - } - - /// Sets the icon and raises the associated property change. - /// - /// The icon to use. - /// The default icon to use if the result is null. - /// True if the was non-null and was assigned. - private bool SetIcon(IImage icon, IImage defaultIcon) { - if (icon != null) { - this.icon = icon; - RaisePropertyChanged(nameof(Icon)); - return true; - } - else if (defaultIcon != null) { - icon = defaultIcon; - RaisePropertyChanged(nameof(Icon)); - } - return false; - } - - /// Sets the icon and display name and raises the associated property changes. - /// - /// The icon and name to use. - /// The default icon to use if the result is null. - /// The default name to use if the result is null. - /// True if the was non-null and was assigned. - private bool SetIconAndDisplayName(IIconAndName iconName, IImage defaultIcon, string defaultName) { - if (iconName != null) { - icon = iconName.Icon; - displayName = iconName.Name; - RaisePropertyChanged(nameof(Icon)); - RaisePropertyChanged(nameof(DisplayName)); - RaisePropertyChanged(nameof(Header)); - return true; - } - else { - if (defaultIcon != null) { - icon = defaultIcon; - RaisePropertyChanged(nameof(Icon)); - } - if (defaultName != null) { - displayName = defaultName; - RaisePropertyChanged(nameof(DisplayName)); - RaisePropertyChanged(nameof(Header)); - } - } - return false; - } - - /// The callback for caching a an individual file icon. - /// - /// The newly cached icon. - private void OnCacheFileIcon(IImage icon) { - SetIcon(icon, ExtensionItem.Icon); - } - - /// The callback for caching a an individual folder icon. - /// - /// The newly cached icon. - private void OnCacheFolderIcon(IImage icon) { - SetIcon(icon, IconCache.FolderIcon); - } - - /*private void OnCacheIconAndDisplayName(IconAndName iconName) { - this.icon = icon ?? IconCache.FileIcon; - if (icon == null) { - if (Type == FileItemType.Volume) - icon = IconCache.VolumeIcon; - } - else { - displayName = Name; - } - RaisePropertyChanged(nameof(Icon)); - RaisePropertyChanged(nameof(Header)); - }*/ - - #endregion - - #region Sort - - /// Sorts the children and all subchildren based on the comparison. - /// - /// The comparison to sort with. - public void Sort(Comparison comparison) { - Sort(comparison, true); - } - - /// Sorts the children based on the comparison. - /// - /// The comparison to sort with. - /// True if all subchildren should be recursively sorted. - private void Sort(Comparison comparison, bool recursive) { - // We don't wanna go locking empty children. - if (Model is FolderItem folder && !folder.IsEmpty) { - List modelChildren = folder.Children; - lock (modelChildren) { - children.Sort(comparison); - if (recursive) { - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemViewModel child = children[i]; - if (child.Model.IsContainerType) { - child.Sort(comparison, true); - } - } - } - } - } - } - - #endregion - - #region Children - - /// Ensures that the chidren collection is created and ready for population. - private void EnsureChildren() { - if (children == null) - children = new FileItemViewModelCollection(this); - } - - /// The callback for when the model has changed in some way. - private void OnModelChanged(FileItemBase sender, FileItemEventArgs e) { - switch (e.Action) { - case FileItemAction.Invalidated: - case FileItemAction.Done: - //case FileItemAction.Refreshed: - break; - case FileItemAction.Exists: - Exists = Model.Exists; - break; - case FileItemAction.Validated: - case FileItemAction.ValidatedSortOrder: - OnModelValidated(e.Action == FileItemAction.ValidatedSortOrder); - break; - case FileItemAction.ChildrenAdded: - OnModelChildrenAdded(e.Children, e.Index); - break; - case FileItemAction.ChildrenRemoved: - OnModelChildrenRemoved(e.Children); - break; - case FileItemAction.ChildrenCleared: - OnModelChildrenCleared(); - break; - case FileItemAction.GetViewModel: - e.ViewModel = this; - break; - } - } - - /// Raises changes in the view model due to model validation. - private void OnModelValidated(bool sortOrder) { - UI.Invoke(() => { - RaisePropertyChanged(nameof(Percent)); - RaisePropertyChanged(nameof(Size)); - RaisePropertyChanged(nameof(LastWriteTime)); - if (Model.IsContainerType) { - RaisePropertyChanged(nameof(ItemCount)); - RaisePropertyChanged(nameof(FileCount)); - RaisePropertyChanged(nameof(SubdirCount)); - } - if (children != null) { - int count = children.Count; - for (int i = 0; i < count; i++) - children[i].RaisePropertyChanged(nameof(Percent)); - if (sortOrder && isExpanded) - children.Sort(ViewModel.FileComparer.Compare); - } - }); - } - - /// Adds new children to the view model collection. - private void OnModelChildrenAdded(List newChildren, int index) { - if (isExpanded) { - UI.Invoke(() => { - EnsureChildren(); - int count = newChildren.Count; - for (int i = 0; i < count; i++) { - children.Add(new FileItemViewModel(ViewModel, newChildren[i])); - } - children.Sort(ViewModel.FileComparer.Compare); - }); - } - else if (newChildren.Count == Model.ChildCount) { - // We had no children before - UI.Invoke(() => RaisePropertyChanged(nameof(ShowExpander))); - } - } - - /// Removes old children from the view model collection. - private void OnModelChildrenRemoved(List oldChildren) { - if (isExpanded) { - UI.Invoke(() => { - int count = oldChildren.Count; - for (int i = 0; i < count; i++) { - int index = children.IndexOf(oldChildren[i]); - FileItemViewModel oldItem = children[index]; - oldItem.UnhookEvents(); - children.RemoveAt(index); - //children.Remove(e.Children[i]); - } - }); - } - else if (oldChildren.Count > 0 && Model.ChildCount == 0) { - // We have no children now - UI.Invoke(() => RaisePropertyChanged(nameof(ShowExpander))); - } - } - - /// Clears all children from the view model collection. - private void OnModelChildrenCleared() { - UI.Invoke(() => { - if (isExpanded) { - if (children != null) - children.Clear(); - } - RaisePropertyChanged(nameof(ShowExpander)); - }); - } - - #endregion - - #region Expanding - - - public static FileItemViewModel ExpandTo(FileItemBase item) { - Stack ancestores = new Stack(); - - while (item.GetViewModel() == null) { - ancestores.Push(item); - item = item.Parent; - } - - FileItemViewModel view = item.GetViewModel(); - while (ancestores.Count > 0) { - item = ancestores.Pop(); - view = view.ExpandFind(item); - } - return view; - } - - protected void OnExpanding() { - if (Model is FolderItem folder && !folder.IsEmpty) { - List modelChildren = folder.Children; - lock (modelChildren) { - EnsureChildren(); - int count = modelChildren.Count; - for (int i = 0; i < count; i++) - children.Add(new FileItemViewModel(ViewModel, modelChildren[i])); - children.Sort(ViewModel.FileComparer.Compare); - } - } - } - private FileItemViewModel ExpandFind(FileItemBase node) { - FileItemViewModel result = null; - if (Model is FolderItem folder && !folder.IsEmpty) { - List modelChildren = folder.Children; - lock (modelChildren) { - int count = modelChildren.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = modelChildren[i]; - FileItemViewModel view = new FileItemViewModel(ViewModel, child); - if (child == node) - result = view; - children.Add(view); - } - children.Sort(ViewModel.FileComparer.Compare); - } - } - UpdateChildIsVisible(true); - return result; - } - protected void OnCollapsing() { - if (Model is FolderItem folder && !folder.IsEmpty) { - List children = folder.Children; - lock (children) { - int count = this.children.Count; - for (int i = 0; i < count; i++) - this.children[i].UnhookEvents(); - this.children.Clear(); - } - } - } - - #endregion - - #region IDisposable Implementation - - /// Disposes of the . - public void Dispose() { - UnhookEvents(); - } - - /// Hooks the required events for the view model. - private void HookEvents() { - if (!isEventsHooked) { - isEventsHooked = true; - Model.Changed += OnModelChanged; - } - } - - /// Unhooks all events from the view model. - private void UnhookEvents() { - if (isEventsHooked) { - isEventsHooked = false; - Model.Changed -= OnModelChanged; - } - if (isWaitingForExtensionIcon) { - isWaitingForExtensionIcon = false; - ExtensionItem.PropertyChanged -= OnExtensionItemPropertyChanged; - } - // Recursively unhook all events, we forgot to do that in the last implementation - if (children != null) { - int count = children.Count; - for (int i = 0; i < count; i++) { - children[i].UnhookEvents(); - } - } - } - - #endregion - - - public FileItemViewModel FindView(FileItemBase node, bool expand) { - Stack ancestors = new Stack(); - - while (node.Parent != null && node != Model) { - ancestors.Push(node); - node = node.Parent; - } - - FileItemViewModel view = this; - while (ancestors.Count > 0) { - node = ancestors.Pop(); - if (!view.IsExpanded) { - if (!expand) { - return null; - } - else { - view.isExpanded = true; - view = view.ExpandFind(node); - } - } - else { - view = view.children.Find(node); - } - } - return view; - } - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModelFlags.cs b/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModelFlags.cs deleted file mode 100644 index f02cacb..0000000 --- a/WinDirStat.Net.Base/ViewModel/Files/FileItemViewModelFlags.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.ViewModel.Files { - /// Flags for the state. - [Serializable] - [Flags] - public enum FileItemViewModelFlags : byte { - /// No flags. - None = 0, - - //Visible = (1 << 0), - /// True if the item is hidden. - Hidden = (1 << 0), - /// True if the item is selected. - Selected = (1 << 1), - /// True if the item is expanded. - Expanded = (1 << 2), - /// True if the item is being edited. - Editing = (1 << 3), - /// True if the item has its events hooked to the model. - EventsHooked = (1 << 4), - /// True if the item is waiting on the extension's icon to cache. - WaitingForExtensionIcon = (1 << 5), - /// The file still exists in the system. - Exists = (1 << 6), - - } - - /// Extensions methods for . - internal static class FileItemViewModelExtensions { - - public static FileItemViewModelFlags SetFlag(this FileItemViewModelFlags flags, FileItemViewModelFlags flag, bool value) { - if (value) - return flags | flag; - else - return flags & ~flag; - } - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Files/FileTreeFlattener.cs b/WinDirStat.Net.Base/ViewModel/Files/FileTreeFlattener.cs deleted file mode 100644 index 80ed1d1..0000000 --- a/WinDirStat.Net.Base/ViewModel/Files/FileTreeFlattener.cs +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics; - -namespace WinDirStat.Net.ViewModel.Files { - /// A flattener for a tree. - public sealed class FileTreeFlattener : ObservableCollectionObject, IList { - - #region Fields - - /// - /// The root node of the flat list tree. - /// This is not necessarily the root of the model! - /// - internal FileItemViewModel root; - private readonly bool includeRoot; - private readonly object syncRoot = new object(); - - #endregion - - #region Constructors - - /// Constructs the . - /// - /// The root item of the list. - /// True if the root is visible in the list. - public FileTreeFlattener(FileItemViewModel modelRoot, bool includeRoot) { - this.root = modelRoot; - while (root.listParent != null) - root = root.listParent; - root.treeFlattener = this; - this.includeRoot = includeRoot; - } - - #endregion - - #region Nodes Events - - /// Raises a collection reset event. - public void NodesReset() { - RaiseCollectionChanged(NotifyCollectionChangedAction.Reset); - } - - /// Raises a collection add event. - /// - /// The index the nodes were added at. - /// The nodes that were added. - public void NodesInserted(int index, IEnumerable nodes) { - if (!includeRoot) index--; - foreach (FileItemViewModel node in nodes) { - RaiseCollectionChanged(NotifyCollectionChangedAction.Add, node, index++); - } - } - - /// Raises a collection remove event. - /// - /// The index the nodes were removed at. - /// The nodes that were removed. - public void NodesRemoved(int index, IEnumerable nodes) { - if (!includeRoot) index--; - foreach (FileItemViewModel node in nodes) { - RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, node, index); - } - } - - /// Raises a collection move event. - /// - /// The index the nodes were moved at. - /// The nodes that were moved. - public void NodesMoved(int index, int oldIndex, IEnumerable nodes) { - if (!includeRoot) index--; - foreach (FileItemViewModel node in nodes) { - RaiseCollectionChanged(NotifyCollectionChangedAction.Move, node, index++, oldIndex++); - } - } - - #endregion - - #region Stop - - /// Stops the list and detaches it from the . - public void Stop() { - Debug.Assert(root.treeFlattener == this); - root.treeFlattener = null; - } - - #endregion - - #region IList Implementation - - /// Gets the item at the specified index in the list. - /// - /// The index of the item. - public object this[int index] { - get { - if (index < 0 || index >= this.Count) - throw new ArgumentOutOfRangeException(); - return FileItemViewModel.GetNodeByVisibleIndex(root, includeRoot ? index : index + 1); - } - set => throw new NotSupportedException(); - } - - /// Gets the number of visible items in the list. - public int Count { - get => includeRoot ? root.GetTotalListLength() : root.GetTotalListLength() - 1; - } - - /// Gets the index of the item in the list. - /// - /// The item to get the index of. - /// The index of the item if found, otherwise -1. - public int IndexOf(object item) { - if (item is FileItemViewModel node && node.IsVisible && node.GetListRoot() == root) { - if (includeRoot) - return FileItemViewModel.GetVisibleIndexForNode(node); - else - return FileItemViewModel.GetVisibleIndexForNode(node) - 1; - } - else { - return -1; - } - } - - /// Returns true if the list contains the specified item. - /// - /// The item to check for. - /// True if the item was found. - public bool Contains(object item) { - return IndexOf(item) >= 0; - } - - /// Copies the list to an array. - /// - /// The array to copy to. - /// The starting index in the array to copy to. - public void CopyTo(Array array, int arrayIndex) { - for (int i = 0; i < Count; i++) - array.SetValue(this[i], arrayIndex++); - } - - - /// Gets the enumerator for this list. - /// - /// The enumerator for all visible elements in the list. - public IEnumerator GetEnumerator() { - for (int i = 0; i < Count; i++) - yield return this[i]; - } - - #endregion - - #region NotSupported IList/ICollection Implementation - - bool ICollection.IsSynchronized => false; - - object ICollection.SyncRoot => syncRoot; - - bool IList.IsReadOnly => true; - - bool IList.IsFixedSize => false; - - void IList.Insert(int index, object item) => throw new NotSupportedException(); - - void IList.RemoveAt(int index) => throw new NotSupportedException(); - - int IList.Add(object item) => throw new NotSupportedException(); - - void IList.Clear() => throw new NotSupportedException(); - - void IList.Remove(object item) => throw new NotSupportedException(); - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Files/FileTreeTraversal.cs b/WinDirStat.Net.Base/ViewModel/Files/FileTreeTraversal.cs deleted file mode 100644 index cb2685e..0000000 --- a/WinDirStat.Net.Base/ViewModel/Files/FileTreeTraversal.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; - -namespace WinDirStat.Net.ViewModel.Files { - /// - /// Static helper methods for traversing trees. - /// - internal static class FileTreeTraversal { - /// - /// Converts a tree data structure into a flat list by traversing it in pre-order. - /// - /// The root element of the tree. - /// The function that gets the children of an element. - /// Iterator that enumerates the tree structure in pre-order. - public static IEnumerable PreOrder(T root, Func> recursion) { - return PreOrder(new T[] { root }, recursion); - } - - /// - /// Converts a tree data structure into a flat list by traversing it in pre-order. - /// - /// The root elements of the forest. - /// The function that gets the children of an element. - /// Iterator that enumerates the tree structure in pre-order. - public static IEnumerable PreOrder(IEnumerable input, Func> recursion) { - Stack> stack = new Stack>(); - try { - stack.Push(input.GetEnumerator()); - while (stack.Count > 0) { - while (stack.Peek().MoveNext()) { - T element = stack.Peek().Current; - yield return element; - IEnumerable children = recursion(element); - if (children != null) { - stack.Push(children.GetEnumerator()); - } - } - stack.Pop().Dispose(); - } - } - finally { - while (stack.Count > 0) { - stack.Pop().Dispose(); - } - } - } - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Graph/FileGraphViewModel.cs b/WinDirStat.Net.Base/ViewModel/Graph/FileGraphViewModel.cs deleted file mode 100644 index d8a5095..0000000 --- a/WinDirStat.Net.Base/ViewModel/Graph/FileGraphViewModel.cs +++ /dev/null @@ -1,257 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Rendering; -using WinDirStat.Net.Services; -using WinDirStat.Net.Structures; - -namespace WinDirStat.Net.ViewModel.Graph { - /// The view model for a file treemap display. - public partial class FileGraphViewModel : ViewModelBaseEx { - - #region Private Enums - - /// The modes for highlighting the graph view. - protected enum HighlightMode { - None, - Extension, - Selection, - } - - #endregion - - #region Fields - - public SettingsService Settings { get; } - public TreemapRenderer Treemap { get; } - public UIService UI { get; } - - - private Point2I treemapSize; - private WriteableBitmap treemap; - private Point2I highlightSize; - private WriteableBitmap highlight; - private WriteableBitmap disabledTreemap; - private WriteableBitmap disabledHighlight; - - /// True if the graph is currently dimmed. - private volatile bool isDimmed; - /// True if the running render thread has finished rendering the treemap. - private volatile bool treemapRendered; - /// True if the running render thread is rendering the treemap. - private volatile bool fullRender; - - /// The root treemap item. - private FileItemBase rootItem; - /// The hovered treemap item. - private FileItemBase hoverItem; - - /// The selected file items to highlight. - private FileItemBase[] selection; - /// The extension to highlight. - private string extension; - /// The current mode for highlighting. - private HighlightMode highlightMode; - - /// True if rendering should be done on a separate thread. - private bool renderAsynchronously; - - /// True if resizing is in progress. - private bool resizing; - /// The timer to delay rendering while resizing. - private readonly UITimer resizeTimer; - - /// The thread where the asynchronous rendering is done. - private Thread renderThread; - - /// The current mouse position of inside the graph. - private Point2I mousePosition; - /// True if the mouse is inside the graph. - private bool isMouseOver; - - #endregion - - #region Constructors - - /// Constructs the . - public FileGraphViewModel(SettingsService settings, - TreemapRendererFactory treemapFactory, - UIService ui) - { - Settings = settings; - Treemap = treemapFactory.Create(); - UI = ui; - - Settings.PropertyChanged += OnSettingsPropertyChanged; - - resizeTimer = UI.CreateTimer(TimeSpan.FromSeconds(0.05), true, OnResizeTick); - } - - #endregion - - #region Events Handlers - - private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - case nameof(SettingsService.TreemapOptions): - case nameof(SettingsService.FilePalette): - RenderAsync(); - break; - case nameof(SettingsService.HighlightColor): - if (highlightMode != HighlightMode.None) - RenderHighlight(treemapSize); - break; - case nameof(SettingsService.RenderPriority): - if (renderThread != null && renderThread.IsAlive) - renderThread.Priority = Settings.RenderPriority; - break; - } - } - - private void OnResizeTick() { - - } - - #endregion - - #region Private Properties - - /// Gets if anything is in the process of being rendered. - private bool IsRendering => renderThread?.IsAlive ?? false; - /// Gets if the treemap is in the process of being rendered. - private bool IsRenderingTreemap => renderThread?.IsAlive ?? false && fullRender; - - /// Gets the treemap highlight color. - private Rgba32Color Options => Settings.HighlightColor; - - #endregion - - #region Properties - - #endregion - - #region Rendering - - private void UpdateDimmed() { - IsDimmed = IsRenderingTreemap || resizing || !IsEnabled; - } - - /// Clears the current render. - private void Clear() { - AbortRender(); - treemap = null; - highlight = null; - treemapSize = Point2I.Zero; - highlightSize = Point2I.Zero; - } - - /// Aborts the current render in progress. - public void AbortRender(bool waitForExit = true) { - if (renderThread != null) { - renderThread.Abort(); - renderThread = null; - UpdateDimmed(); - } - } - - private void RenderHighlightAsync() { - fullRender = !treemapRendered; - RenderAsyncImpl(); - } - - private void RenderAsync() { - fullRender = true; - RenderAsyncImpl(); - } - - private void RenderAsyncImpl() { - if (IsEnabled && rootItem != null) { - AbortRender(); - treemapRendered = false; - //IsDimmed = true; - Point2I size = new Point2I((int) ActualWidth, (int) ActualHeight); - renderThread = new Thread(() => RenderThread(size)) { - Priority = Settings.RenderPriority, - Name = "File GraphView Render", - }; - renderThread.Start(); - UpdateDimmed(); - } - } - - private void RenderThread(Point2I size) { - try { - if (size.X != 0 && size.Y != 0) { - if (fullRender) { - RenderTreemap(size); - } - treemapRendered = true; - if (highlightMode != HighlightMode.None) { - RenderHighlight(size); - } - } - UI.Invoke(() => { - // Let the control know we're not rendering anymore - renderThread = null; - imageTreemap.Source = treemap; - if (highlightMode != HighlightMode.None) - imageHighlight.Source = highlight; - UpdateDimmed(); - }); - } - catch (ThreadAbortException) { } - catch (Exception ex) { - Stopwatch sw = Stopwatch.StartNew(); - UI.Invoke(() => { - Console.WriteLine(ex.ToString()); - renderThread = null; - UpdateDimmed(); - UpdateHover(); - }); - Console.WriteLine($"Took {sw.ElapsedMilliseconds}ms to invoke EXCEPTION Dispatcher"); - } - } - - private void RenderTreemap(Point2I size) { - Stopwatch sw = Stopwatch.StartNew(); - if (treemap == null || treemapSize.X != size.X || treemapSize.Y != size.Y) { - treemapSize = size; - UI.Invoke(() => { - treemap = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); - }); - } - Treemap.DrawTreemap(treemap, new Rectangle2I(size), rootItem); - //Treemap.DrawTreemap(treemap, new Rectangle2I(size), fileRoot, options); - Console.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render treemap"); - } - private void RenderHighlight(Point2I size) { - Stopwatch sw = Stopwatch.StartNew(); - if (highlight == null || highlightSize.X != size.X || highlightSize.Y != size.Y) { - highlightSize = size; - UI.Invoke(() => { - highlight = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); - }); - Trace.WriteLine($"Took {sw.ElapsedMilliseconds}ms to setup highlight bitmap"); - } - sw.Restart(); - if (highlightMode == HighlightMode.Extension) { - Treemap.HighlightExtensions(highlight, new Rectangle2I(size), rootItem, Settings.HighlightColor, extension); - } - else if (highlightMode == HighlightMode.Selection) { - Treemap.HighlightItems(highlight, new Rectangle2I(size), Settings.HighlightColor, selection); - } - Trace.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render highlight"); - Trace.WriteLine(""); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/Graph/GraphViewModel.cs b/WinDirStat.Net.Base/ViewModel/Graph/GraphViewModel.cs deleted file mode 100644 index b29ad0d..0000000 --- a/WinDirStat.Net.Base/ViewModel/Graph/GraphViewModel.cs +++ /dev/null @@ -1,419 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using GalaSoft.MvvmLight; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Rendering; -using WinDirStat.Net.Services; -using WinDirStat.Net.Structures; - -namespace WinDirStat.Net.ViewModel.Graph { - /// The base view model for a treemap display. - public partial class GraphViewModel : ViewModelBase { - - #region Private Enums - - /// The modes for highlighting the graph view. - protected enum HighlightMode { - None, - Extension, - Selection, - } - - #endregion - - #region Fields - - private readonly object volatileLock = new object(); - - private readonly SettingsService settings; - private readonly TreemapRenderer treemap; - private readonly UIService ui; - - - private Point2I treemapSize; - private Point2I highlightSize; - - private WriteableBitmap treemapImage; - private WriteableBitmap highlightImage; - private WriteableBitmap disabledTreemapImage; - private WriteableBitmap disabledHighlightImage; - - private ImageSource treemapDisplayImage; - private ImageSource highlightDisplayImage; - - private Point2I dimensions; - - - /// The root treemap item. - private volatile ITreemapItem rootItem; - - // Hover - /// The hovered treemap item. - private ITreemapItem hoverItem; - /// The current mouse position of inside the graph. - private Point2I mousePosition; - /// True if the mouse is inside the graph. - private bool isMouseOver; - - // Highlight - /// The selected treemap items to highlight. - private ITreemapItem[] selection; - /// The extension to highlight. - private string extension; - /// The current mode for highlighting. - private HighlightMode highlightMode; - - // Display - /// True if the graph is currently dimmed. - private volatile bool isDimmed; - /// True if the graph is enabled. - private volatile bool isEnabled; - - // Rendering - /// True if rendering should be done on a separate thread. - private bool renderAsynchronously; - /// True if the running render thread has finished rendering the treemap. - private volatile bool treemapRendered; - /// True if the running render thread is rendering the treemap. - private volatile bool fullRender; - /// True if resizing is in progress. - private volatile bool resizing; - /// The timer to delay rendering while resizing. - private readonly UITimer resizeTimer; - /// The thread where the asynchronous rendering is done. - private Thread renderThread; - - private Rgb24Color highlightColor; - - #endregion - - #region Constructors - - /// Constructs the . - public GraphViewModel(SettingsService settings, - TreemapRendererFactory treemapFactory, - UIService ui) - { - this.settings = settings; - treemap = treemapFactory.Create(); - this.ui = ui; - - this.settings.PropertyChanged += OnSettingsPropertyChanged; - - resizeTimer = this.ui.CreateTimer(TimeSpan.FromSeconds(0.05), true, OnResizeTick); - isEnabled = true; - } - - #endregion - - #region Events Handlers - - private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - /*case nameof(SettingsService.TreemapOptions): - case nameof(SettingsService.FilePalette): - Render(); - break; - case nameof(SettingsService.HighlightColor): - if (highlightMode != HighlightMode.None) - RenderHighlight(treemapSize); - break;*/ - case nameof(SettingsService.RenderPriority): - ui.Invoke(() => { - if (renderThread != null && renderThread.IsAlive) - renderThread.Priority = settings.RenderPriority; - }); - break; - } - } - - private void OnResizeTick() { - - } - - #endregion - - #region Private Properties - - /// Gets if anything is in the process of being rendered. - private bool IsRenderingAsync => renderThread?.IsAlive ?? false; - /// Gets if the treemap is in the process of being rendered. - private bool IsRenderingTreemap => renderThread?.IsAlive ?? false && fullRender; - - /// Gets or sets the treemap highlight color. - public Rgba32Color HighlightColor { - get => highlightColor; - set => Set(ref highlightColor, value); - } - - #endregion - - #region Properties - - /// Gets if the graph view should be dimmed due to rendering or being disabled. - public bool IsDimmed { - get => isDimmed; - protected set { - if (isDimmed != value) { - isDimmed = value; - - if (isDimmed) - HoverItem = null; - else if (isMouseOver) - UpdateHover(); - - RaisePropertyChanged(); - } - } - } - - /// Gets if the graph view is visually enabled. - public bool IsEnabled { - get => isEnabled; - private set { - if (isEnabled != value) { - isEnabled = value; - UpdateDimmed(); - if (!isEnabled) { - AbortRender(); - disabledTreemapImage = treemapImage; - disabledHighlightImage = highlightImage; - TreemapImage = disabledTreemapImage; - HighlightImage = disabledHighlightImage; - } - else { - disabledTreemapImage = null; - disabledHighlightImage = null; - RaisePropertyChanged(nameof(TreemapImage)); - // GraphView will render if (!IsEnabled and RootItem != null) - Render(); - } - RaisePropertyChanged(); - } - } - } - - /// Gets or sets the dimensions of the graph view. - public Point2I Dimensions { - get => dimensions; - set => Set(ref dimensions, value); - } - - /// Gets or sets the current mouse position inside the graph. - public Point2I MousePosition { - get => mousePosition; - set => Set(ref mousePosition, value); - } - - /// ets or sets if the mouse is inside the graph. - public bool IsMouseOver { - get => isMouseOver; - set => Set(ref isMouseOver, value); - } - - /// Gets the image to display the treemap. - public ImageSource TreemapImage { - get => treemapDisplayImage; - private set => Set(ref treemapDisplayImage, value); - } - - /// Gets the image to display the highlight. - public ImageSource HighlightImage { - get => highlightDisplayImage; - private set => Set(ref highlightDisplayImage, value); - } - - public ITreemapItem HoverItem { - get => hoverItem; - set => Set(ref hoverItem, value); - } - - public ITreemapItem RootItem { - get => rootItem; - set { - if (rootItem != value) { - rootItem = value; - - if (rootItem == null) { - AbortRender(); - } - - HighlightNone(); - HoverItem = null; - if (rootItem != null) - Render(); - else - Clear(); - - RaisePropertyChanged(); - } - } - } - - #endregion - - #region Rendering - - public void Refresh() { - Render(); - } - - private void Render() { - if (renderAsynchronously) - RenderAsyncImpl(); - else - RenderImpl(); - } - - private void RenderHighlight() { - fullRender = !treemapRendered; - if (IsRenderingAsync) { - RenderAsyncImpl(); - } - else if (!isDimmed && rootItem != null) { - RenderImpl(); - } - } - - /// Updates the dimmed settings. - private void UpdateDimmed() { - IsDimmed = IsRenderingTreemap || resizing || !IsEnabled; - } - - /// Clears the current render. - private void Clear() { - AbortRender(); - treemapImage = null; - highlightImage = null; - treemapSize = Point2I.Zero; - highlightSize = Point2I.Zero; - } - - /// Aborts the current render in progress. - public void AbortRender(bool waitForExit = true) { - if (renderThread != null) { - renderThread.Abort(); - renderThread = null; - UpdateDimmed(); - } - } - - private void RenderImpl() { - if (IsEnabled && rootItem != null) { - AbortRender(); - treemapRendered = false; - Point2I size = dimensions; - renderThread = null; - RenderThread(size); - } - } - - private void RenderAsyncImpl() { - if (IsEnabled && rootItem != null) { - AbortRender(); - treemapRendered = false; - //IsDimmed = true; - Point2I size = dimensions; - renderThread = new Thread(() => RenderThread(size)) { - Priority = settings.RenderPriority, - Name = "File GraphView Render", - }; - renderThread.Start(); - UpdateDimmed(); - } - } - - private void RenderThread(Point2I size) { - try { - if (size.X != 0 && size.Y != 0) { - if (fullRender) { - RenderTreemap(size); - } - treemapRendered = true; - if (highlightMode != HighlightMode.None) { - RenderHighlight(size); - } - } - ui.Invoke(() => { - // Let the control know we're not rendering anymore - renderThread = null; - TreemapImage = treemapImage; - if (highlightMode != HighlightMode.None) - HighlightImage = highlightImage; - UpdateDimmed(); - }); - } - catch (ThreadAbortException) { } - catch (Exception ex) { - Stopwatch sw = Stopwatch.StartNew(); - ui.Invoke(() => { - Console.WriteLine(ex.ToString()); - renderThread = null; - UpdateDimmed(); - UpdateHover(); - }); - Console.WriteLine($"Took {sw.ElapsedMilliseconds}ms to invoke EXCEPTION Dispatcher"); - } - } - - private void RenderTreemap(Point2I size) { - Stopwatch sw = Stopwatch.StartNew(); - if (treemapImage == null || treemapSize.X != size.X || treemapSize.Y != size.Y) { - treemapSize = size; - ui.Invoke(() => { - treemapImage = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); - }); - } - treemap.DrawTreemap(treemapImage, new Rectangle2I(size), rootItem); - //Treemap.DrawTreemap(treemap, new Rectangle2I(size), fileRoot, options); - Console.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render treemap"); - } - private void RenderHighlight(Point2I size) { - Stopwatch sw = Stopwatch.StartNew(); - if (highlightImage == null || highlightSize.X != size.X || highlightSize.Y != size.Y) { - highlightSize = size; - ui.Invoke(() => { - highlightImage = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); - }); - Trace.WriteLine($"Took {sw.ElapsedMilliseconds}ms to setup highlight bitmap"); - } - sw.Restart(); - if (highlightMode == HighlightMode.Extension) { - treemap.HighlightExtensions(highlightImage, new Rectangle2I(size), (FileItemBase) rootItem, settings.HighlightColor, extension); - } - else if (highlightMode == HighlightMode.Selection) { - treemap.HighlightItems(highlightImage, new Rectangle2I(size), settings.HighlightColor, selection); - } - Trace.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render highlight"); - Trace.WriteLine(""); - } - - #endregion - - #region Hover - - private void UpdateHover() { - if (rootItem == null) { - HoverItem = null; - return; - } - if (hoverItem != null) { - Rectangle2I rc = HoverItem.Rectangle; - if (rc.Contains(mousePosition)) - return; // Hover is the same - } - HoverItem = TreemapRenderer.FindItemAtPoint(rootItem, mousePosition); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/MainViewModel.Commands.cs b/WinDirStat.Net.Base/ViewModel/MainViewModel.Commands.cs deleted file mode 100644 index 4b6bfd8..0000000 --- a/WinDirStat.Net.Base/ViewModel/MainViewModel.Commands.cs +++ /dev/null @@ -1,361 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Input; -using WinDirStat.Net.Model.Drives; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.ViewModel { - partial class MainViewModel { - - #region File Menu - - public IRelayUICommand Open { - get => GetCommand("Open...", Images.Open, Shortcuts.Open, - OnOpen); - } - public IRelayUICommand Save { - get => GetCommand("Save...", Images.Save, Shortcuts.Save, - OnSave, CanExecuteIsOpen); - } - public IRelayUICommand Reload { - get => GetCommand("Reload", Images.Reload, Shortcuts.Reload, - OnReload, CanExecuteIsOpen); - } - public IRelayUICommand Close { - get => GetCommand("Close", Images.Close, Shortcuts.Close, - OnClose, CanExecuteIsOpen); - } - public IRelayCommand Cancel { - get => GetCommand("Cancel", (IImage) null, Shortcuts.Cancel, - OnCancel, CanExecuteIsScanning); - } - public IRelayUICommand Elevate { - get => GetCommand("Elevate", Images.Elevate, Shortcuts.Elevate, - OnElevate, CanExecuteElevate); - } - public IRelayUICommand Exit { - get => GetCommand("Exit", Images.Exit, Shortcuts.Exit, - OnExit); - } - - #endregion - - #region Context Menu/Toolbar - - public IRelayUICommand Expand { - get => GetCommand("Expand", Images.Expand, Shortcuts.Expand, - OnExpand, CanExecuteExpand); - } - public IRelayUICommand Collapse { - get => GetCommand("Collapse", Images.Expand, Shortcuts.Expand, - OnExpand, CanExecuteExpand); - } - - public IRelayUICommand OpenItem { - get => GetCommand("Open Item", Images.Run, Shortcuts.OpenItem, - OnOpenItem, CanExecuteOpenItem); - } - public IRelayUICommand CopyPath { - get => GetCommand("Copy Path", Images.CopyPath, Shortcuts.CopyPath, - OnCopyPath, CanExecuteIsSelectionSingleFileType); - } - public IRelayUICommand Explore { - get => GetCommand("Explore Here", Images.Explore, Shortcuts.Explore, - OnExplore, CanExecuteExplore); - } - public IRelayUICommand CommandPrompt { - get => GetCommand("Command Prompt Here", Images.Cmd, Shortcuts.CommandPrompt, - OnCommandPrompt, CanExecuteCommandPrompt); - } - public IRelayUICommand PowerShell { - get => GetCommand("PowerShell Here", Images.PowerShell, Shortcuts.PowerShell, - OnPowerShell, CanExecuteIsSelectionSingleFileType); - } - public IRelayUICommand RefreshSelected { - get => GetCommand("Refresh Selected", Images.RefreshSelected, Shortcuts.RefreshSelected, - OnRefreshSelected, CanExecuteRefreshSelected); - } - public IRelayUICommand DeleteRecycle { - get => GetCommand("Delete (to Recycle Bin)", Images.RecycleBin, Shortcuts.DeleteRecycle, - OnDeleteRecycle, CanExecuteDeleteSingle); - } - public IRelayUICommand DeletePermanently { - get => GetCommand("Delete (Permanently!)", Images.Delete, Shortcuts.DeletePermanently, - OnDeletePermanently, CanExecuteDeleteSingle); - } - public IRelayUICommand Properties { - get => GetCommand("Properties", Images.Properties, Shortcuts.Properties, - OnProperties, CanExecuteOpenItem); - } - - #endregion - - #region Options Menu - - public IRelayUICommand ShowFreeSpace { - get => GetCommand("Show Free Space", Images.FreeSpace, Shortcuts.Properties, - OnShowFreeSpace); - } - public IRelayUICommand ShowUnknown { - get => GetCommand("Show Unknown", Images.UnknownSpace, Shortcuts.Properties, - OnShowUnknown); - } - public IRelayUICommand ShowTotalSpace { - get => GetCommand("Show Total Space", Images.ShowTotalSpace, Shortcuts.Properties, - OnShowTotalSpace); - } - public IRelayUICommand ShowFileTypes { - get => GetCommand("Show File Types", Images.FileCollection, Shortcuts.Properties, - OnShowFileTypes); - } - public IRelayUICommand ShowTreemap { - get => GetCommand("Show Treemap", Images.ShowTreemap, Shortcuts.Properties, - OnShowTreemap); - } - public IRelayUICommand ShowToolBar { - get => GetCommand("Show Toolbar", (IImage) null, Shortcuts.Properties, - OnShowToolBar); - } - public IRelayUICommand ShowStatusBar { - get => GetCommand("Show Statusbar", (IImage) null, Shortcuts.Properties, - OnShowStatusBar); - } - public IRelayUICommand Configure { - get => GetCommand("Configure WinDirStat...", Images.Settings, - OnConfigure); - } - - #endregion - - #region Other - - public IRelayUICommand EmptyRecycleBin { - get => GetCommand("Empty Recycle Bins", Images.EmptyRecycleBin, - OnEmptyRecycleBin, CanExecuteEmptyRecycleBin); - } - - #endregion - - - #region CanExecute - - private bool CanExecuteIsOpen() { - return IsOpen; - } - private bool CanExecuteIsScanning() { - return IsScanning; - } - - private bool CanExecuteHasSelection() { - return SelectedFiles.Count > 0; - } - private bool CanExecuteIsSingleSelection() { - return SelectedFiles.Count == 1; - } - - private bool CanExecuteIsSelectionFileType() { - return SelectedFiles.Count > 0 && !SelectedFiles.Any(f => !f.Model.IsFileType); - } - private bool CanExecuteIsSelectionSingleFileType() { - return SelectedFiles.Count == 1 && SelectedFiles[0].Model.IsFileType; - } - private bool CanExecuteCommandPrompt() { - return CanExecuteIsSelectionSingleFileType(); - } - private bool CanExecuteCopyPath() { - return CanExecuteIsSelectionSingleFileType(); - } - - private bool CanExecuteExpand() { - return SelectedFiles.Count == 1; - } - private bool CanExecuteOpenItem() { - return SelectedFiles.Count == 1 && (SelectedFile.Model.IsFileType || - SelectedFile.Model.IsAbsoluteRootType); - } - private bool CanExecuteExplore() { - return SelectedFiles.Count == 1 && (SelectedFile.Model.IsFileType || - SelectedFile.Model.Type == FileItemType.FileCollection || - SelectedFile.Model.IsAbsoluteRootType); - } - private bool CanExecuteDelete() { - return SelectedFiles.Count > 0 && !SelectedFiles.Any(f => !f.Model.IsFileType || f.Model.IsAnyRootType); - } - private bool CanExecuteDeleteSingle() { - return SelectedFiles.Count == 1 && SelectedFile.Model.IsFileType && !SelectedFile.Model.IsAnyRootType; - } - private bool CanExecuteRefreshSelected() { - return IsOpen && SelectedFiles.Count > 0 && !SelectedFiles.Any(f => !f.Model.IsFileType && !f.Model.IsContainerType); - } - private bool CanExecuteEmptyRecycleBin() { - return allRecycleBinInfo.ItemCount != 0 && allRecycleBinInfo.Size != 0; - } - private bool CanExecuteElevate() { - return !OS.IsElevated; - } - - #endregion - - #region File Menu - - private void OnOpen() { - DriveSelectResult result = Dialogs.ShowDriveSelect(WindowOwner); - if (result != null) { - Scanning.CloseAsync(() => Scanning.ScanAsync(result)); - } - } - private void OnSave() { - // TODO: Implement saving scanned file tree - } - private void OnReload() { - Scanning.ReloadAsync(); - } - private void OnClose() { - Scanning.Close(false); - } - private void OnCancel() { - Scanning.Cancel(false); - } - private void OnElevate() { - // Dialog warn progress will be lost. - // If yes, close then start new process. - MessageResult result = MessageResult.Yes; - if (Scanning.ScanState != ScanState.NotStarted) { - result = Dialogs.ShowWarning(WindowOwner, - "Elevating the process will start a new instance and all progress will be lost. Would you like to continue?", - "Elevate", MessageButton.YesNo); - } - if (result == MessageResult.Yes) { - try { - OS.StartNewElevated(); - UI.Shutdown(); - Dispose(); - } - catch { - Dialogs.ShowError(WindowOwner, "Failed to start elevated process!", "Error"); - } - } - } - private void OnExit() { - UI.Shutdown(); - Dispose(); - } - - #endregion - - #region Context Menu/Toolbar - - private void OnExpand() { - SelectedFile.IsExpanded = !SelectedFile.IsExpanded; - } - private void OnOpenItem() { - if (SelectedFile.Type == FileItemType.Computer) - OS.ExploreComputer(); - OS.RunItem(SelectedFile.FullName); - } - private void OnCopyPath() { - Clipboard.SetText($"\"{SelectedFile.FullName}\""); - } - private void OnExplore() { - switch (SelectedFile.Type) { - case FileItemType.Computer: - OS.ExploreComputer(); - break; - case FileItemType.File: - OS.ExploreFile(SelectedFile.FullName); - break; - default: - OS.ExploreFolder(SelectedFile.FullName); - break; - } - } - private void OnCommandPrompt() { - string directory = SelectedFile.FullName; - if (SelectedFile.Type == FileItemType.File) - directory = SelectedFile.Parent.FullName; - OS.OpenCommandPrompt(directory); - } - private void OnPowerShell() { - string directory = SelectedFile.FullName; - if (SelectedFile.Type == FileItemType.File) - directory = SelectedFile.Parent.FullName; - OS.OpenPowerShell(directory); - } - private void OnRefreshSelected() { - HashSet filesToRefresh = new HashSet(); - IsolateRefreshableFiles(filesToRefresh, SelectedFiles.Select(f => f.Model)); - if (filesToRefresh.Count > 0) - Scanning.RefreshFilesAsync(filesToRefresh); - } - private void OnDeleteRecycle() { - Scanning.RecycleFile(SelectedFile.Model); - } - private void OnDeletePermanently() { - Scanning.DeleteFile(SelectedFile.Model); - } - private void OnProperties() { - OS.OpenProperties(SelectedFile.FullName); - } - - private void IsolateRefreshableFiles(HashSet filesToRefresh, IEnumerable files) { - foreach (FileItemBase file in files) { - if (file.IsFileType) { - filesToRefresh.Add(file); - } - else if (file.IsContainerType) { - IsolateRefreshableFiles(filesToRefresh, file.Children); - } - } - } - - #endregion - - #region Options - - private void OnShowFreeSpace() { - Settings.ShowFreeSpace = !Settings.ShowFreeSpace; - } - private void OnShowUnknown() { - Settings.ShowUnknown = !Settings.ShowUnknown; - } - private void OnShowTotalSpace() { - Settings.ShowTotalSpace = !Settings.ShowTotalSpace; - } - private void OnShowFileTypes() { - Settings.ShowFileTypes = !Settings.ShowFileTypes; - } - private void OnShowTreemap() { - Settings.ShowTreemap = !Settings.ShowTreemap; - } - private void OnShowToolBar() { - Settings.ShowToolBar = !Settings.ShowToolBar; - } - private void OnShowStatusBar() { - Settings.ShowStatusBar = !Settings.ShowStatusBar; - } - - #endregion - - #region Other - - private void OnEmptyRecycleBin() { - OS.EmptyRecycleBin(WindowOwner); - } - - private void OnConfigure() { - // Open settings window - //Dialogs.ShowSettings(WindowOwner); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/MainViewModel.Methods.cs b/WinDirStat.Net.Base/ViewModel/MainViewModel.Methods.cs deleted file mode 100644 index 9c22ec5..0000000 --- a/WinDirStat.Net.Base/ViewModel/MainViewModel.Methods.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Utils; - -namespace WinDirStat.Net.ViewModel { - partial class MainViewModel { - - public void Loaded() { - } - - public void SortFiles() { - SuppressFileTreeRefresh = true; - RootItem?.Sort(FileComparer.Compare); - SuppressFileTreeRefresh = false; - } - - public void SortExtensions() { - Extensions.Sort(ExtensionComparer.Compare); - } - - public void ActivateItem() { - // TODO: Determine the default action for each item type - } - - public void UpdateEmptyRecycleBin() { - Debug.WriteLine("UpdateEmptyRecycleBin"); - RecycleBinInfo info = OS.GetAllRecycleBinInfo(); - string label = "Empty Recycle Bins"; - if (info != null) { - label += " ("; - if (info.ItemCount == 0 && info.Size == 0) { - label += "Empty"; - } - else { - label += $"{info.ItemCount:N0} "; - if (info.ItemCount == 1) - label += $"Item"; - else - label += $"Items"; - label += $", {FormatBytes.Format(info.Size)}"; - } - label += ")"; - } - EmptyRecycleBinLabel = label; - allRecycleBinInfo = info; - EmptyRecycleBin.RaiseCanExecuteChanged(); - } - - public void WindowShown() { - Open.Execute(); - } - } -} diff --git a/WinDirStat.Net.Base/ViewModel/MainViewModel.cs b/WinDirStat.Net.Base/ViewModel/MainViewModel.cs deleted file mode 100644 index 581ed1f..0000000 --- a/WinDirStat.Net.Base/ViewModel/MainViewModel.cs +++ /dev/null @@ -1,387 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.ComponentModel; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; -using GalaSoft.MvvmLight; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Rendering; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Utils; -using WinDirStat.Net.ViewModel.Comparers; -using WinDirStat.Net.ViewModel.Extensions; -using WinDirStat.Net.ViewModel.Files; - -namespace WinDirStat.Net.ViewModel { - /// The main view model for the program. - public partial class MainViewModel : ViewModelWindowBase { - - #region Fields - - public SettingsService Settings { get; } - public ScanningService Scanning { get; } - public IIconCacheService IconCache { get; } - public IUIService UI { get; } - public IBitmapFactory BitmapFactory { get; } - /// Gets the images service. - public ImagesServiceBase Images { get; } - public IClipboardService Clipboard { get; } - public IOSService OS { get; } - public IWindowDialogService Dialogs { get; } - public IShortcutsService Shortcuts { get; } - public TreemapRenderer Treemap { get; } - - public ExtensionItemViewModelCollection Extensions { get; } - - public ObservableCollection SelectedFiles { get; } - public FileItemViewModel SelectedFile { get; private set; } - private ExtensionItemViewModel selectedExtension; - - public FileComparer FileComparer { get; } - public ExtensionComparer ExtensionComparer { get; } - - private long gcRAMUsage; - private FileItemViewModel rootItem; - private RootItem graphViewRootItem; - private readonly IUITimer ramTimer; - private readonly IUITimer statusTimer; - - private RecycleBinInfo allRecycleBinInfo; - private string emptyRecycleBinLabel; - - private bool suppressRefresh; - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the MainViewModel class. - /// - public MainViewModel(SettingsService settings, - ScanningService scanning, - IIconCacheService iconCache, - IUIService ui, - IBitmapFactory bitmapFactory, - ImagesServiceBase images, - IClipboardService clipboard, - IOSService os, - IWindowDialogService dialogs, - TreemapRendererFactory treemapFactory, - IShortcutsService shortcuts, - RelayCommandService relayFactory) - { - Settings = settings; - Scanning = scanning; - IconCache = iconCache; - UI = ui; - BitmapFactory = bitmapFactory; - Images = images; - Clipboard = clipboard; - OS = os; - Dialogs = dialogs; - Shortcuts = shortcuts; - Treemap = treemapFactory.Create(); - - Settings.PropertyChanged += OnSettingsPropertyChanged; - Scanning.PropertyChanged += OnScanningPropertyChanged; - - Extensions = new ExtensionItemViewModelCollection(this); - - SelectedFiles = new ObservableCollection(); - SelectedFiles.CollectionChanged += OnSelectedFilesChanged; - - FileComparer = new FileComparer(); - ExtensionComparer = new ExtensionComparer(); - UpdateEmptyRecycleBin(); - - GCRAMUsage = GC.GetTotalMemory(false); - if (IsInDesignMode) { - // Code runs in Blend --> create design time data. - } - else { - // Code runs "for real" - ramTimer = UI.StartTimer(Settings.RAMInterval, true, OnRAMUsageTick); - statusTimer = UI.CreateTimer(Settings.StatusInterval, true, OnStatusTick); - } - } - - #endregion - - #region Properties - - /// Gets the title to display for the window. - public override string Title { - get { - string title = "WinDirStat.Net"; - if (Scanning.ProgressState != ScanProgressState.NotStarted) { - var paths = Scanning.RootPaths.Select(p => PathUtils.TrimSeparatorEnd(p)); - title = $"{string.Join("|", paths)} - {title}"; - } - if (OS.IsElevated) - title += " (Administrator)"; - return title; - } - } - - /// Gets the Garbage Collector's RAM Usage. - public long GCRAMUsage { - get => gcRAMUsage; - set => Set(ref gcRAMUsage, value); - } - - /// Gets the root file tree item. - public FileItemViewModel RootItem { - get => rootItem; - private set { - if (rootItem != value) { - if (rootItem != null) { - SuppressFileTreeRefresh = true; - rootItem.IsExpanded = false; - SuppressFileTreeRefresh = false; - rootItem.Dispose(); - } - rootItem = value; - RaisePropertyChanged(); - } - } - } - - /// Gets treemap's root file tree item. - public RootItem GraphViewRootItem { - get => graphViewRootItem; - private set => Set(ref graphViewRootItem, value); - } - - #endregion - - #region ScanProperties - - /// Gets if a scan operation is in progress. - public bool IsScanning => Scanning.IsScanning; - /// Gets if a refresh operation is in progress. - public bool IsRefreshing => Scanning.IsRefreshing; - /// Gets if a scan is finished and open. - public bool IsOpen => Scanning.IsOpen; - /// Gets the scan time. - public TimeSpan ScanTime => Scanning.ScanTime; - /// Gets the scan progress. - public double ScanProgress => Scanning.Progress; - /// Gets if scan progress can be displayed. - public bool CanDisplayScanProgress => Scanning.CanDisplayProgress; - - /// Gets or sets if the current scan operation is suspended. - public bool IsScanSuspended { - get => Scanning.IsSuspended; - set => Scanning.IsSuspended = value; - } - - ///Gets if the file list has a selection. - public bool HasFileSelection => SelectedFile != null; - - ///Gets the file type list selection. - public ExtensionItemViewModel SelectedExtension { - get => selectedExtension; - set { - if (selectedExtension != value) { - bool hasSelectionChanged = ((selectedExtension == null) != (value == null)); - selectedExtension = value; - RaisePropertyChanged(); - if (hasSelectionChanged) - RaisePropertyChanged(nameof(HasExtensionSelection)); - } - } - } - - ///Gets if the file type list has a selection. - public bool HasExtensionSelection => selectedExtension != null; - - /// Gets the label to display for the empty recycle bin command. - public string EmptyRecycleBinLabel { - get => emptyRecycleBinLabel; - private set => Set(ref emptyRecycleBinLabel, value); - } - - /// Gets if the UI refreshing should be supressed due to validation. - public bool SuppressFileTreeRefresh { - get => suppressRefresh || Scanning.SuppressFileTreeRefresh; - private set { - if (suppressRefresh != value) { - suppressRefresh = value; - if (!Scanning.SuppressFileTreeRefresh) { - if (!suppressRefresh) - RootItem?.RaiseChildrenReset(); - RaisePropertyChanged(nameof(SuppressFileTreeRefresh)); - } - } - } - } - - #endregion - - #region Visibility Properties - - /// Gets if the file types list should be hidden. - public bool HideFileTypes { - get => (!Settings.ShowFileTypes || (!Scanning.IsRefreshing && !Scanning.IsOpen)) && !IsInDesignMode; - } - /// Gets if the treemap view should be hidden. - public bool HideTreemap { - get => (!Settings.ShowTreemap || (!Scanning.IsRefreshing && !Scanning.IsOpen)) && !IsInDesignMode; - } - /// Gets if the toolbar should be hidden. - public bool HideToolBar => !Settings.ShowToolBar && !IsInDesignMode; - /// Gets if the status bar should be hidden. - public bool HideStatusBar => !Settings.ShowStatusBar && !IsInDesignMode; - /// Gets if the graph view is enabled and able to refres. - public bool GraphViewEnabled => Settings.ShowTreemap && !Scanning.IsRefreshing && Scanning.IsOpen; - /// - /// Gets if the elevate command should be hidden due to the process already being elevated. - /// - public bool HideElevateCommand => OS.IsElevated; - - #endregion - - #region Event Handlers - - private void OnRAMUsageTick() { - GCRAMUsage = GC.GetTotalMemory(false); - } - - private void OnStatusTick() { - RaisePropertyChanged(nameof(ScanTime)); - RaisePropertyChanged(nameof(ScanProgress)); - } - - private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e) { - UI.Invoke(() => { - switch (e.PropertyName) { - case nameof(SettingsService.RAMInterval): - ramTimer.Interval = Settings.RAMInterval; - break; - case nameof(SettingsService.StatusInterval): - statusTimer.Interval = Settings.StatusInterval; - break; - case nameof(SettingsService.ShowFileTypes): - RaisePropertyChanged(nameof(HideFileTypes)); - break; - case nameof(SettingsService.ShowTreemap): - RaisePropertyChanged(nameof(HideTreemap)); - RaisePropertyChanged(nameof(GraphViewEnabled)); - break; - case nameof(SettingsService.ShowToolBar): - RaisePropertyChanged(nameof(HideToolBar)); - break; - case nameof(SettingsService.ShowStatusBar): - RaisePropertyChanged(nameof(HideStatusBar)); - break; - } - }); - } - - private void OnScanningPropertyChanged(object sender, PropertyChangedEventArgs e) { - UI.Invoke(() => { - switch (e.PropertyName) { - case nameof(ScanningService.RootItem): - if (Scanning.RootItem == null) { - GraphViewRootItem = null; - RootItem = null; - } - else { - RootItem = new FileItemViewModel(this, Scanning.RootItem); - } - break; - case nameof(ScanningService.ProgressState): - switch (Scanning.ProgressState) { - case ScanProgressState.Starting: - //GraphViewRootItem = null; - break; - case ScanProgressState.Started: - statusTimer.Start(); - break; - case ScanProgressState.Ending: - statusTimer.Stop(); - break; - case ScanProgressState.Ended: - Extensions.Sort(ExtensionComparer.Compare); - GraphViewRootItem = Scanning.RootItem; - break; - case ScanProgressState.NotStarted: - GraphViewRootItem = null; - RootItem?.Dispose(); - RootItem = null; - //UpdateEmptyRecycleBin(); - break; - } - RaisePropertyChanged(nameof(Title)); - RaisePropertyChanged(nameof(ScanProgress)); - break; - case nameof(ScanningService.ScanState): - RaisePropertyChanged(nameof(HideFileTypes)); - RaisePropertyChanged(nameof(HideTreemap)); - RaisePropertyChanged(nameof(HideToolBar)); - RaisePropertyChanged(nameof(HideStatusBar)); - break; - case nameof(ScanningService.ScanTime): - RaisePropertyChanged(nameof(ScanTime)); - break; - case nameof(ScanningService.Progress): - RaisePropertyChanged(nameof(ScanProgress)); - break; - case nameof(ScanningService.CanDisplayProgress): - RaisePropertyChanged(nameof(CanDisplayScanProgress)); - break; - case nameof(ScanningService.IsOpen): - RaisePropertyChanged(nameof(IsOpen)); - RaisePropertyChanged(nameof(GraphViewEnabled)); - break; - case nameof(ScanningService.IsScanning): - RaisePropertyChanged(nameof(IsScanning)); - break; - case nameof(ScanningService.IsRefreshing): - RaisePropertyChanged(nameof(IsRefreshing)); - RaisePropertyChanged(nameof(GraphViewEnabled)); - //if (!Scanning.IsRefreshing) - // UpdateEmptyRecycleBin(); - break; - case nameof(ScanningService.SuppressFileTreeRefresh): - if (!suppressRefresh) { - RootItem?.RaiseChildrenReset(); - RaisePropertyChanged(nameof(SuppressFileTreeRefresh)); - } - break; - } - }); - } - - private void OnSelectedFilesChanged(object sender, NotifyCollectionChangedEventArgs e) { - FileItemViewModel newSelectedFile = SelectedFiles.FirstOrDefault(); - if (SelectedFile != newSelectedFile) { - SelectedFile = newSelectedFile; - RaisePropertyChanged(nameof(SelectedFile)); - if ((SelectedFile == null) != (newSelectedFile == null)) - RaisePropertyChanged(nameof(HasFileSelection)); - } - } - - #endregion - - #region IDisposable Implementation - - public void Dispose() { - Scanning.Dispose(); - statusTimer.Stop(); - ramTimer.Stop(); - } - - #endregion - - } -} diff --git a/WinDirStat.Net.Base/ViewModel/ViewModelCommandBase.cs b/WinDirStat.Net.Base/ViewModel/ViewModelCommandBase.cs deleted file mode 100644 index cc07618..0000000 --- a/WinDirStat.Net.Base/ViewModel/ViewModelCommandBase.cs +++ /dev/null @@ -1,237 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Windows.Input; -using GalaSoft.MvvmLight; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -#if WPF -using GalaSoft.MvvmLight.CommandWpf; -#else -using GalaSoft.MvvmLight.Command; -#endif - -namespace WinDirStat.Net.ViewModel { - /// An addition to the class with extra helper functions. - public abstract class ViewModelCommandBase : ViewModelBase { - - #region Fields - - /// The list of loaded commands. - private readonly Dictionary commands = new Dictionary(); - - #endregion - - #region Constructors - - public ViewModelCommandBase(IRelayCommandService relayCommand) - - #endregion - - #region Properties - - /// Gets all commands created with . - public IEnumerable Commands => commands.Values; - - #endregion - - #region GetCommand (Basic) - - /// - /// Gets the commnd if one exists, or assigns the passed command. - /// - /// - /// The new command to assign if one does not exist. - /// The name of the command. - /// The command from the command list. - protected TCommand GetCommand(TCommand newCommand, - [CallerMemberName] string commandName = null) - where TCommand : ICommand - { - if (!commands.TryGetValue(commandName, out ICommand command)) { - command = newCommand; - commands.Add(commandName, command); - } - return (TCommand) command; - } - - /// - /// Gets the commnd if one exists, or assigns calls the specified create command function. - /// - /// - /// The function to create the new command if one does not exist. - /// The name of the command. - /// The command from the command list. - protected TCommand GetCommand(Func createCommand, - [CallerMemberName] string commandName = null) - where TCommand : ICommand - { - if (!commands.TryGetValue(commandName, out ICommand command)) { - command = createCommand(); - commands.Add(commandName, command); - } - return (TCommand) command; - } - - #endregion - - #region GetCommand (RelayCommand) - - /// Gets or creates a new command with the specified parameters. - /// - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected RelayCommand GetCommand(Action execute, Func canExecute = null, - [CallerMemberName] string commandName = null) - { - return GetCommand(() => new RelayCommand(execute, canExecute), commandName); - } - - #endregion - - #region GetCommand (RelayCommand) - - /// Gets or creates a new command with the specified parameters. - /// - /// The parameter type of the command. - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected RelayCommand GetCommand(Action execute, Func canExecute = null, - [CallerMemberName] string commandName = null) - { - return GetCommand(() => new RelayCommand(execute, canExecute), commandName); - } - - #endregion - - #region GetCommand (RelayUICommand) - - /// Gets or creates a new command with the specified parameters. - /// - /// The display text for the command. - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected RelayUICommand GetCommand(string text, Action execute, Func canExecute = null, - [CallerMemberName] string commandName = null) - { - return GetCommand(text, null, null, execute, canExecute, commandName); - } - - /// Gets or creates a new command with the specified parameters. - /// - /// The display text for the command. - /// The display icon for the command. - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected RelayUICommand GetCommand(string text, IImage icon, Action execute, - Func canExecute = null, [CallerMemberName] string commandName = null) - { - return GetCommand(text, icon, null, execute, canExecute, commandName); - } - - /// Gets or creates a new command with the specified parameters. - /// - /// The display text for the command. - /// The display icon for the command. - /// The keybind for the command. - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected RelayUICommand GetCommand(string text, IShortcut keyGesture, Action execute, - Func canExecute = null, [CallerMemberName] string commandName = null) - { - return GetCommand(text, null, keyGesture, execute, canExecute, commandName); - } - - /// Gets or creates a new command with the specified parameters. - /// - /// The display text for the command. - /// The display icon for the command. - /// The keybind for the command. - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected RelayUICommand GetCommand(string text, IImage icon, IShortcut keyGesture, - Action execute, Func canExecute = null, [CallerMemberName] string commandName = null) - { - return GetCommand(() => new RelayUICommand(text, icon, keyGesture, execute, canExecute), commandName); - } - - #endregion - - #region GetCommand (RelayUICommand) - - /// Gets or creates a new command with the specified parameters. - /// - /// The parameter type of the command. - /// The display text for the command. - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected RelayUICommand GetCommand(string text, Action execute, - Func canExecute = null, [CallerMemberName] string commandName = null) - { - return GetCommand(text, null, null, execute, canExecute, commandName); - } - - /// Gets or creates a new command with the specified parameters. - /// - /// The parameter type of the command. - /// The display text for the command. - /// The display icon for the command. - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected RelayUICommand GetCommand(string text, IImage icon, Action execute, - Func canExecute = null, [CallerMemberName] string commandName = null) - { - return GetCommand(text, icon, null, execute, canExecute, commandName); - } - - /// Gets or creates a new command with the specified parameters. - /// - /// The parameter type of the command. - /// The display text for the command. - /// The display icon for the command. - /// The keybind for the command. - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected RelayUICommand GetCommand(string text, IShortcut keyGesture, Action execute, - Func canExecute = null, [CallerMemberName] string commandName = null) - { - return GetCommand(text, null, keyGesture, execute, canExecute, commandName); - } - - /// Gets or creates a new command with the specified parameters. - /// - /// The parameter type of the command. - /// The display text for the command. - /// The display icon for the command. - /// The keybind for the command. - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected RelayUICommand GetCommand(string text, IImage icon, IShortcut keyGesture, - Action execute, Func canExecute = null, [CallerMemberName] string commandName = null) - { - return GetCommand(() => new RelayUICommand(text, icon, keyGesture, execute, canExecute), commandName); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/ViewModelControlBase.cs b/WinDirStat.Net.Base/ViewModel/ViewModelControlBase.cs deleted file mode 100644 index 4ecd762..0000000 --- a/WinDirStat.Net.Base/ViewModel/ViewModelControlBase.cs +++ /dev/null @@ -1,25 +0,0 @@ -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.ViewModel { - /// An addition to the class with extra helper functions. - public abstract class ViewModelControlBase : ViewModelCommandBase { - - #region Fields - - /// The control owning this view model. - private IControl controlOwner; - - #endregion - - #region Properties - - /// Gets or sets the control owning this view model. - public IControl WindowOwner { - get => controlOwner; - set => Set(ref controlOwner, value); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/ViewModel/ViewModelWindowBase.cs b/WinDirStat.Net.Base/ViewModel/ViewModelWindowBase.cs deleted file mode 100644 index a26b313..0000000 --- a/WinDirStat.Net.Base/ViewModel/ViewModelWindowBase.cs +++ /dev/null @@ -1,32 +0,0 @@ -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.ViewModel { - /// An addition to the class with extra helper functions. - public abstract class ViewModelWindowBase : ViewModelCommandBase { - - #region Fields - - /// The window owning this view model. - private IWindow windowOwner; - - #endregion - - #region Virtual Properties - - /// Gets the title to display for the window. - public virtual string Title => "WinDirStat.Net"; - - #endregion - - #region Properties - - /// Gets or sets the window owning this view model. - public IWindow WindowOwner { - get => windowOwner; - set => Set(ref windowOwner, value); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Base/WinDirStat.Net.Base.csproj b/WinDirStat.Net.Base/WinDirStat.Net.Base.csproj deleted file mode 100644 index 3702582..0000000 --- a/WinDirStat.Net.Base/WinDirStat.Net.Base.csproj +++ /dev/null @@ -1,109 +0,0 @@ - - - - WinDirStat.Net.Base - WinDirStat.Net - true - latest - Debug;Release - - - - - - - - - - - - net462 - - - - TRACE;DEBUG;WINDOWS;WPF - full - true - - - - TRACE;WINDOWS;WPF - - - - - - - - - - - - - - - - - - Rendering\TreemapRenderer.cs - - - Services\ScanningService.cs - - - Services\SettingsService.cs - - - ViewModel\DriveSelectViewModel.cs - - - ViewModel\MainViewModel.cs - - - ViewModel\Commands\RelayUICommand.cs - - - ViewModel\Files\FileItemViewModel.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WinDirStat.Net.Windows/Native/Win32.FindFile.cs b/WinDirStat.Net.Windows/Native/Win32.FindFile.cs deleted file mode 100644 index 0fc76db..0000000 --- a/WinDirStat.Net.Windows/Native/Win32.FindFile.cs +++ /dev/null @@ -1,227 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; - -namespace WinDirStat.Net.Windows.Native { - partial class Win32 { - - /// - /// Searches a directory for a file or subdirectory with a name and attributes that match those - /// specified. - /// - /// - /// - /// The directory or path, and the file name. The file name can include wildcard characters, for - /// example, an asterisk (*) or a question mark (?). - /// - /// The information level of the returned data. - /// - /// A reference to the that receives the file data. - /// - /// - /// The type of filtering to perform that is different from wildcard matching. - /// - /// - /// A pointer to the search criteria if the specified fSearchOp needs structured search information. - /// - /// Specifies additional flags that control the search. - /// - /// If the function succeeds, the return value is a search handle used in a subsequent call to - /// or , and the - /// parameter contains information about the first file or directory found. - /// - /// If the function fails or fails to locate files from the search string in the lpFileName - /// parameter, the return value is . - /// - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr FindFirstFileEx( - string lpFileName, - FindExInfoLevels fInfoLevelId, - out Win32FindData lpFindFileData, - FindExSearchOps fSearchOp, - IntPtr lpSearchFilter, - [MarshalAs(UnmanagedType.U4)] FindExFlags dwAdditionalFlags); - - /// - /// Continues a file search from a previous call to the function. - /// - /// - /// - /// The search handle returned by a previous call to the function. - /// - /// - /// A pointer to the structure that receives information about the found - /// file or subdirectory. - /// - /// - /// If the function succeeds, the return value is true and the - /// parameter contains information about the next file or directory found. - /// - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool FindNextFile( - IntPtr hFindFile, - out Win32FindData lpFindFileData); - - /// - /// Closes a file search handle opened by the function. - /// - /// - /// The file search handle. - /// If the function succeeds, the return value is true. - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool FindClose( - IntPtr hFindFile); - - /// - /// Contains information about the file that is found by the , or function. - /// - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public struct Win32FindData { - /// The file attributes of a file. - [MarshalAs(UnmanagedType.U4)] - public FileAttributes dwFileAttributes; - /// - /// A structure that specifies when a file or directory was created. - /// - public FILETIME ftCreationTime; - /// - /// For a file, the structure specifies when the file was last read from, written to, or for - /// executable files, run. - /// - /// For a directory, the structure specifies when the directory is created. If the underlying - /// file system does not support last access time, this member is zero. - /// - /// On the FAT file system, the specified date for both files and directories is correct, but the - /// time of day is always set to midnight. - /// - public FILETIME ftLastAccessTime; - /// - /// For a file, the structure specifies when the file was last written to, truncated, or - /// overwritten. The date and time are not updated when file attributes or security descriptors - /// are changed. - /// - public FILETIME ftLastWriteTime; - /// The high-order value of the file size, in bytes. - public int nFileSizeHigh; - /// The low-order value of the file size, in bytes. - public uint nFileSizeLow; - /// Reserved for future use. - public uint dwReserved0; - /// Reserved for future use. - public uint dwReserved1; - /// The name of the file. - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string cFileName; - //[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] - //public string cAlternateFileName; - - /// True if the file is a directory. - public bool IsDirectory { - get => (dwFileAttributes.HasFlag(FileAttributes.Directory)); - } - /// True if the file is a symbolic link. - public bool IsSymbolicLink { - get => (dwFileAttributes.HasFlag(FileAttributes.ReparsePoint)); - } - /// True if the file is a relative directory and should be ignored. - public bool IsRelativeDirectory { - get => (cFileName == "." || cFileName == ".."); - } - /// The full size of the file. - public long Size { - get => ((long) nFileSizeHigh << 32) | nFileSizeLow; - } - - /// The UTC creation time of the file. - public DateTime CreationTimeUtc { - get => ftCreationTime.ToDateTimeUtc(); - } - /// The local creation time of the file. - public DateTime CreationTime { - get => ftCreationTime.ToDateTime(); - } - /// The UTC last access time of the file. - public DateTime LastAccessTimeUtc { - get => ftLastAccessTime.ToDateTimeUtc(); - } - /// The local last access time of the file. - public DateTime LastAccessTime { - get => ftLastAccessTime.ToDateTime(); - } - /// The UTC last write time of the file. - public DateTime LastWriteTimeUtc { - get => ftLastWriteTime.ToDateTimeUtc(); - } - /// The local last write time of the file. - public DateTime LastWriteTime { - get => ftLastWriteTime.ToDateTime(); - } - } - - public enum FindExInfoLevels { - /// - /// The FindFirstFileEx function retrieves a standard set of attribute information. The data is - /// returned in a structure. - /// - Standard, - /// - /// The FindFirstFileEx function does not query the short file name, improving overall - /// enumeration speed.The data is returned in a WIN32_FIND_DATA structure, and the - /// cAlternateFileName member is always a NULL string. Windows Server 2008, Windows Vista, - /// Windows Server 2003 and Windows XP: This value is not supported until Windows Server 2008 R2 - /// and Windows 7. - /// - Basic, - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - MaxInfoLevel, - } - public enum FindExSearchOps { - /// - /// The search for a file that matches a specified file name. The lpSearchFilter parameter of - /// must be NULL when this search operation is used. - /// - NameMatch, - /// - /// This is an advisory flag. If the file system supports directory filtering, the function - /// searches for a file that matches the specified name and is also a directory. If the file - /// system does not support directory filtering, this flag is silently ignored. The - /// lpSearchFilter parameter of the FindFirstFileEx function must be NULL when this search value - /// is used. If directory filtering is desired, this flag can be used on all file systems, but - /// because it is an advisory flag and only affects file systems that support it, the application - /// must examine the file attribute data stored in the lpFindFileData parameter of the function to determine whether the function has returned a handle to a - /// directory. - /// - LimitToDirectories, - /// This filtering type is not available. - LimitToDevices, - [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - MaxSearchOp, - } - [Flags] - public enum FindExFlags : uint { - /// No flags. - None = 0, - /// Searches are case-sensitive. - CaseSensitive = 1, - /// - /// Uses a larger buffer for directory queries, which can increase performance of the find - /// operation. Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This - /// value is not supported until Windows Server 2008 R2 and Windows 7. - /// - LargeFetch = 2, - /// - /// Limits the results to files that are physically on disk. This flag is only relevant when a - /// file virtualization filter is present. - /// - OnDiskEntriesOnly = 4, - } - } -} diff --git a/WinDirStat.Net.Windows/Native/Win32.ImageList.cs b/WinDirStat.Net.Windows/Native/Win32.ImageList.cs deleted file mode 100644 index 26d0363..0000000 --- a/WinDirStat.Net.Windows/Native/Win32.ImageList.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Windows.Native { - partial class Win32 { - [DllImport("comctl32.dll", SetLastError = true)] - public static extern int ImageList_GetImageCount( - IntPtr hImageList); - - [DllImport("comctl32.dll", SetLastError = true)] - public static extern IntPtr ImageList_Duplicate( - IntPtr hImageList); - - [DllImport("comctl32.dll", SetLastError = true)] - public static extern IntPtr ImageList_Destroy( - IntPtr hImageList); - - [DllImport("comctl32.dll", SetLastError = true)] - public static extern int ImageList_Add( - IntPtr hImageList, - IntPtr image, - IntPtr mask); - - [DllImport("comctl32.dll", SetLastError = true)] - public static extern IntPtr ImageList_ExtractIcon( - IntPtr hInstance, - IntPtr hImageList, - int i); - - [DllImport("comctl32.dll", SetLastError = true)] - public static extern IntPtr ImageList_GetIcon( - IntPtr hImageList, - int i, - [MarshalAs(UnmanagedType.U4)] ImageListDrawFlags flags); - - [Flags] - public enum ImageListDrawFlags : uint { - Normal = 0x00000000, - Transparent = 0x00000001, - Blend25 = 0x00000002, - Focus = 0x00000002, - Blend50 = 0x00000004, - Selected = 0x00000004, - Blend = 0x00000004, - Mask = 0x00000010, - Image = 0x00000020, - Rop = 0x00000040, - OverlayMask = 0x00000F00, - PreserveAlpha = 0x00001000, - Scale = 0x00002000, - DpiScale = 0x00004000, - Async = 0x00008000, - } - } -} diff --git a/WinDirStat.Net.Windows/Native/Win32.RecycleBin.cs b/WinDirStat.Net.Windows/Native/Win32.RecycleBin.cs deleted file mode 100644 index 3833d1c..0000000 --- a/WinDirStat.Net.Windows/Native/Win32.RecycleBin.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Windows.Native { - partial class Win32 { - - /// Information about the Recycle Bin returned by . - [StructLayout(LayoutKind.Sequential, Pack = 4)] - public struct SHRecycleBinInfo { - public static readonly int CBSize = Marshal.SizeOf(); - - /// The size of this structure. - public int cbSize; - /// The size of items in the Recycle Bin. - public long i64Size; - /// The number of items in the Recycle Bin. - public long i64NumItems; - } - - /// Flags for . - [Flags] - public enum SHEmptyRecycleBinFlags : uint { - /// No flags. - None = 0, - /// No dialog box confirming the deletion of the objects will be displayed. - NoConfirmation = 0x00000001, - /// No dialog box indicating the progress will be displayed. - NoProgressUI = 0x00000002, - /// No sound will be played when the operation is complete. - NoSound = 0x00000004, - } - - /// - /// Retrieves the size of the Recycle Bin and the number of items in it, for a specified drive. - /// - /// - /// - /// The address of a null-terminated string of maximum length MAX_PATH to contain the path of the - /// root drive on which the Recycle Bin is located. This parameter can contain the address of a - /// string formatted with the drive, folder, and subfolder names (C:\Windows\System...). - /// - /// - /// The reference to a structure that receives the Recycle Bin - /// information. The cbSize member of the structure must be set to the size of the structure before - /// calling this API. - /// - /// False if the function succeeds. - [DllImport("shell32.dll", CharSet = CharSet.Auto)] - public static extern bool SHQueryRecycleBin( - string pszRootPath, - ref SHRecycleBinInfo pSHQueryRBInfo); - - /// Empties the Recycle Bin on the specified drive. - /// - /// - /// A handle to the parent window of any dialog boxes that might be displayed during the operation. - /// This parameter can be null. - /// - /// - /// The address of a null-terminated string of maximum length MAX_PATH that contains the path of the - /// root drive on which the Recycle Bin is located. This parameter can contain the address of a - /// string formatted with the drive, folder, and subfolder names, for example c:\windows\system. It - /// can also contain an empty string or null. If this value is an empty string or null, all Recycle - /// Bins on all drives will be emptied. - /// - /// - /// - [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Auto)] - public static extern bool SHEmptyRecycleBin( - IntPtr hWnd, - string pszRootPath, - [MarshalAs(UnmanagedType.U4)] SHEmptyRecycleBinFlags dwFlags); - - - } -} diff --git a/WinDirStat.Net.Windows/Native/Win32.SHFileOperation.cs b/WinDirStat.Net.Windows/Native/Win32.SHFileOperation.cs deleted file mode 100644 index 6e541ed..0000000 --- a/WinDirStat.Net.Windows/Native/Win32.SHFileOperation.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Windows.Native { - partial class Win32 { - - /// File Operation Function Type for SHFileOperation. - public enum FileOperationFunc : uint { - /// Move the objects. - Move = 0x0001, - /// Copy the objects. - Copy = 0x0002, - /// Delete (or recycle) the objects. - Delete = 0x0003, - /// Rename the objects. - Rename = 0x0004, - } - - /// Possible flags for the SHFileOperation method. - [Flags] - public enum FileOperationFlags : ushort { - /// No flags. - None = 0, - - /// Do not show a dialog during the process - Silent = 0x0004, - /// Do not ask the user to confirm selection. - NoConfirmation = 0x0010, - /// - /// Delete the file to the recycle bin. (Required flag to send a file to the bin) - /// - AllowUndo = 0x0040, - /// Do not show the names of the files or folders that are being recycled. - SimpleProgress = 0x0100, - /// Surpress errors, if any occur during the process. - NoErrorUI = 0x0400, - /// - /// Warn if files are too big to fit in the recycle bin and will need to be deleted completely. - /// - WarnFilesTooBigForRecycleBin = 0x4000, - } - - /// SHFILEOPSTRUCT for SHFileOperation from COM. - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public struct SHFileOperationStruct { - public IntPtr hwnd; - [MarshalAs(UnmanagedType.U4)] - public FileOperationFunc wFunc; - [MarshalAs(UnmanagedType.LPTStr)] - public string pFrom; - [MarshalAs(UnmanagedType.LPTStr)] - public string pTo; - [MarshalAs(UnmanagedType.U2)] - public FileOperationFlags fFlags; - [MarshalAs(UnmanagedType.Bool)] - public bool fAnyOperationsAborted; - public IntPtr hNameMappings; - [MarshalAs(UnmanagedType.LPTStr)] - public string lpszProgressTitle; - } - - /// - /// Copies, moves, renames, or deletes a file system object. This function has been replaced in - /// Windows Vista by IFileOperation. - /// - /// - /// - /// A reference to an that contains information this function - /// needs to carry out the specified operation. This parameter must contain a valid value that is not - /// nulll. You are responsible for validating the value. If you do not validate it, you will - /// experience unexpected results. - /// - /// False on success. - [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Auto)] - public static extern bool SHFileOperation(ref SHFileOperationStruct FileOp); - } -} diff --git a/WinDirStat.Net.Windows/Native/Win32.SHGetFileInfo.cs b/WinDirStat.Net.Windows/Native/Win32.SHGetFileInfo.cs deleted file mode 100644 index 1ae4772..0000000 --- a/WinDirStat.Net.Windows/Native/Win32.SHGetFileInfo.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Windows.Native { - partial class Win32 { - - /// Contains information about a file object. - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public struct SHFileInfo { - /// The marshaled size of the struct. - public static readonly int CBSize = Marshal.SizeOf(); - - /// - /// A handle to the icon that represents the file. You are responsible for destroying this handle - /// with DestroyIcon when you no longer need it. - /// - public IntPtr hIcon; - /// The index of the icon image within the system image list. - public int iIcon; - /// - /// An array of values that indicates the attributes of the file object. For information about - /// these values, see the IShellFolder::GetAttributesOf method. - /// - public uint dwAttributes; - /// - /// A string that contains the name of the file as it appears in the Windows Shell, or the path - /// and file name of the file that contains the icon representing the file. - /// - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string szDisplayName; - /// A string that describes the type of file. - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] - public string szTypeName; - } - - /// - /// The flags that specify the file information to retrieve for . - /// - [Flags] - public enum SHFileInfoFlags : uint { - None = 0, - LargeIcon = 0x000000000, - - SmallIcon = 0x000000001, - OpenIcon = 0x000000002, - ShellIconSize = 0x000000004, - PIDL = 0x000000008, - - UseFileAttributes = 0x000000010, - AddOverlays = 0x000000020, - OverlayIndex = 0x000000040, - - Icon = 0x000000100, - DisplayName = 0x000000200, - TypeName = 0x000000400, - Attributes = 0x000000800, - - IconLocation = 0x000001000, - ExeType = 0x000002000, - SysIconIndex = 0x000004000, - LinkOverlay = 0x000008000, - - Selected = 0x000010000, - AttrSpecified = 0x000020000, - } - - /// - /// Retrieves information about an object in the file system, such as a file, folder, directory, or - /// drive root. - /// - /// - /// - /// A string of maximum length MAX_PATH that contains the path and file name. Both absolute and - /// relative paths are valid. - /// - /// - /// A combination of one or more file attribute flags. If does not include - /// the flag, this parameter is ignored. - /// - /// A structure to receive the file information. - /// Use here. - /// - /// The flags that specify the file information to retrieve. This parameter can be a combination of - /// the following values. - /// - /// Returns a value whose meaning depends on the uFlags parameter. - [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr SHGetFileInfo( - string pszPath, - [MarshalAs(UnmanagedType.U4)] FileAttributes dwFileAttributes, - ref SHFileInfo psfi, - int cbFileInfo, - [MarshalAs(UnmanagedType.U4)] SHFileInfoFlags uFlags); - - [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr SHGetFileInfo( - IntPtr pszPath, - [MarshalAs(UnmanagedType.U4)] FileAttributes dwFileAttributes, - ref SHFileInfo psfi, - int cbFileInfo, - [MarshalAs(UnmanagedType.U4)] SHFileInfoFlags uFlags); - - [DllImport("shell32.dll", SetLastError = true)] - public static extern bool SHGetSpecialFolderLocation( - IntPtr hwnd, - [MarshalAs(UnmanagedType.I4)] Environment.SpecialFolder csidl, - ref IntPtr ppidl); - } -} diff --git a/WinDirStat.Net.Windows/Native/Win32.SHGetStockIconInfo.cs b/WinDirStat.Net.Windows/Native/Win32.SHGetStockIconInfo.cs deleted file mode 100644 index 2e9026f..0000000 --- a/WinDirStat.Net.Windows/Native/Win32.SHGetStockIconInfo.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Windows.Native { - partial class Win32 { - /// - /// Used by to identify which stock system icon to retrieve. - /// - public enum SHStockIconID : uint { - DocNoAssoc = 0, - DocAssoc = 1, - Application = 2, - Folder = 3, - FolderOpen = 4, - Drive525 = 5, - Drive35 = 6, - DriveRemove = 7, - DriveFixed = 8, - DriveNet = 9, - DriveNetDisabled = 10, - DriveCD = 11, - DriveRAM = 12, - World = 13, - Server = 15, - Printer = 16, - MyNetwork = 17, - Find = 22, - Help = 23, - Share = 28, - Link = 29, - SlowFile = 30, - Recycler = 31, - RecyclerFull = 32, - MediaCDAudio = 40, - Lock = 47, - AutoList = 49, - PrinterNet = 50, - ServerShare = 51, - PrinterFax = 52, - PrenterFaxNet = 53, - PrinterFile = 54, - Stack = 55, - MediaSVCD = 56, - StuffedFolder = 57, - DriveUnknown = 58, - DriveDVD = 59, - MediaDVD = 60, - MediaDVDRAM = 61, - MediaDVDRW = 62, - MediaDVDR = 63, - MediaDVDROM = 64, - MediaCDAudioPlus = 65, - MediaCDRW = 66, - MediaCDR = 67, - MediaCDBurn = 68, - MediaCDBlank = 69, - MediaCDROM = 70, - AudioFiles = 71, - ImageFiles = 72, - VideoFiles = 73, - MixedFiles = 74, - FolderBack = 75, - FolderFront = 76, - Shield = 77, - Warning = 78, - Info = 79, - Error = 80, - Key = 81, - Software = 82, - Rename = 83, - Delete = 84, - MediaAudioDVD = 85, - MediaMovieDVD = 86, - MediaEnhancedCD = 87, - MediaEnhancedDVD = 88, - MediaHDDVD = 89, - MediaBluray = 90, - MediaVCD = 91, - MediaDVDPlusR = 92, - MediaDVDPlusRW = 93, - DesktopPC = 94, - MobilePC = 95, - Users = 96, - MediaSmartMedia = 97, - MediaCompactFlash = 98, - DeviceCellPhone = 99, - DeviceCamera = 100, - DeviceVideoCamera = 101, - DeviceAudioPlayer = 102, - NetworkConnect = 103, - Internet = 104, - ZipFile = 105, - Settings = 106, - DriveHDDVD = 132, - DriveBD = 133, - MediaHDDVDROM = 134, - MediaHDDVDR = 135, - MediaHDDVDRAM = 136, - MediaBDROM = 137, - MediaBDR = 138, - MediaBDRE = 139, - ClusteredDrive = 140, - MaxIcons = 175, - } - - [Flags] - public enum SHStockIconFlags : uint { - None = 0, - - IconLocation = 0, - LargeIcon = 0x000000000, - SmallIcon = 0x000000001, - ShellIconSize = 0x000000004, - Icon = 0x000000100, - SysIconIndex = 0x000004000, - LinkOverlay = 0x000008000, - Selected = 0x000010000, - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public struct SHStockIconInfo { - /// The marshaled size of the struct. - public static readonly int CBSize = Marshal.SizeOf(); - - public int cbSize; - public IntPtr hIcon; - public int iSysIconIndex; - public int iIcon; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string szPath; - } - - [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool SHGetStockIconInfo( - [MarshalAs(UnmanagedType.U4)] SHStockIconID siid, - [MarshalAs(UnmanagedType.U4)] SHStockIconFlags uFlags, - ref SHStockIconInfo psii); - } -} diff --git a/WinDirStat.Net.Windows/Native/Win32.Shell.cs b/WinDirStat.Net.Windows/Native/Win32.Shell.cs deleted file mode 100644 index 4e09c31..0000000 --- a/WinDirStat.Net.Windows/Native/Win32.Shell.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Windows.Native { - partial class Win32 { - - /// - /// Requests the form of an item's display name to retrieve through . - /// - public enum SIGetDisplayName : uint { - /// - /// Returns the display name relative to the parent folder. In UI this name is generally ideal - /// for display to the user. - /// - NormalDisplay = 0x00000000, - /// - /// Returns the parsing name relative to the parent folder. This name is not suitable for use in - /// UI. - /// - ParentRelativeParsing = 0x80018001, - /// - /// Returns the parsing name relative to the desktop. This name is not suitable for use in UI. - /// - DesktopAbsoluteParsing = 0x80028000, - /// - /// Returns the editing name relative to the parent folder. In UI this name is suitable for - /// display to the user. - /// - ParentRelativeEditing = 0x80031001, - /// - /// Returns the editing name relative to the desktop. In UI this name is suitable for display to - /// the user. - /// - DesktopAbsoluteEditing = 0x8004c000, - /// - /// Returns the item's file system path, if it has one. Only items that report SFGAO_FILESYSTEM - /// have a file system path. When an item does not have a file system path, a call to on that item will fail. In UI this name is suitable for display to - /// the user in some cases, but note that it might not be specified for all items. - /// - FileSysPath = 0x80058000, - /// - /// Returns the item's URL, if it has one. Some items do not have a URL, and in those cases a - /// call to will fail. This name is suitable for display to the - /// user in some cases, but note that it might not be specified for all items. - /// - Url = 0x80068000, - /// - /// Returns the path relative to the parent folder in a friendly format as displayed in an - /// address bar. This name is suitable for display to the user. - /// - ParentRelativeForAddressBar = 0x8007c001, - /// Returns the path relative to the parent folder. - ParentRelative = 0x80080001, - /// Introduced in Windows 8. - ParentRelativeForUI = 0x80094001, - } - - // https://stackoverflow.com/a/29198314/7517185 - - /// - /// Translates a Shell namespace object's display name into an item identifier list and returns the - /// attributes of the object. This function is the preferred method to convert a string to a pointer - /// to an item identifier list (PIDL). - /// - /// - /// A string that contains the display name to parse. - /// This parameter is normally set to null. - /// - /// - /// - /// - [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool SHParseDisplayName( - string pszName, - IntPtr pbc, - out IntPtr ppidl, - int sfgaoIn, - out int psfgaoOut); - - /// Retrieves the display name of an item identified by its IDList. - /// - /// A PIDL that identifies the item. - /// - /// A value from the enumeration that specifies the type of display - /// name to retrieve. - /// - /// - /// A value that, when this function returns successfully, receives the display name. - /// - /// If this function succeeds, it returns false. Otherwise, it returns true. - [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool SHGetNameFromIDList( - IntPtr pidl, - SIGetDisplayName sigdnName, - out string ppszName); - - } -} diff --git a/WinDirStat.Net.Windows/Native/Win32.ShellExecute.cs b/WinDirStat.Net.Windows/Native/Win32.ShellExecute.cs deleted file mode 100644 index 0d2bbe0..0000000 --- a/WinDirStat.Net.Windows/Native/Win32.ShellExecute.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Windows.Native { - partial class Win32 { - - [Flags] - public enum ShellExecuteMaskFlags : uint { - Default = 0x00000000, - ClassName = 0x00000001, - ClassKey = 0x00000003, - IDList = 0x00000004, - InvokeIDList = 0x0000000c, // Note SEE_MASK_INVOKEIDLIST(0xC) implies SEE_MASK_IDLIST(0x04) - HotKey = 0x00000020, - NoCloseProcess = 0x00000040, - ConnectNetDRV = 0x00000080, - NoAsync = 0x00000100, - FlagDDEWait = NoAsync, - DOEnvSubset = 0x00000200, - FlagNoUI = 0x00000400, - Unicode = 0x00004000, - NoConsole = 0x00008000, - AsyncOK = 0x00100000, - HMonitor = 0x00200000, - NoZoneChecks = 0x00800000, - NoQueryClassStore = 0x01000000, - WaitForInputIdle = 0x02000000, - MaskFlagLogUsage = 0x04000000, - } - - public enum ShowCommands : int { - Hide = 0, - ShowNormal = 1, - Normal = 1, - ShowMinimized = 2, - ShowMaximized = 3, - Maximize = 3, - ShowNoActive = 4, - Show = 5, - Minimize = 6, - ShowMinNoActive = 7, - ShowNA = 8, - Restore = 9, - ShowDefault = 10, - ForceMinimize = 11, - Max = 11 - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public struct ShellExecuteInfo { - public static readonly int CBSize = Marshal.SizeOf(); - - public int cbSize; - [MarshalAs(UnmanagedType.U4)] - public ShellExecuteMaskFlags fMask; - public IntPtr hwnd; - [MarshalAs(UnmanagedType.LPTStr)] - public string lpVerb; - [MarshalAs(UnmanagedType.LPTStr)] - public string lpFile; - [MarshalAs(UnmanagedType.LPTStr)] - public string lpParameters; - [MarshalAs(UnmanagedType.LPTStr)] - public string lpDirectory; - [MarshalAs(UnmanagedType.I4)] - public ShowCommands nShow; - public IntPtr hInstApp; - public IntPtr lpIDList; - [MarshalAs(UnmanagedType.LPTStr)] - public string lpClass; - public IntPtr hkeyClass; - public uint dwHotKey; - public IntPtr hIcon; - public IntPtr hProcess; - } - - [DllImport("shell32.dll", CharSet = CharSet.Auto)] - public static extern bool ShellExecuteEx(ref ShellExecuteInfo lpExecInfo); - } -} diff --git a/WinDirStat.Net.Windows/Native/Win32.Windows.cs b/WinDirStat.Net.Windows/Native/Win32.Windows.cs deleted file mode 100644 index d1042f3..0000000 --- a/WinDirStat.Net.Windows/Native/Win32.Windows.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace WinDirStat.Net.Windows.Native { - partial class Win32 { - - public enum WindowLongs : int { - ExStyle = -20, - HInstance = -6, - HwndParent = -8, - ID = -12, - Style = -16, - UserData = -21, - WndProc = -4, - User = 0x8, - MsgResult = 0x0, - DlgProc = 0x4 - } - - public const int GWL_STYLE = -16; - - [Flags] - public enum WindowStyles : uint { - None = 0, - VScroll = 0x00200000, - HScroll = 0x00100000, - Visible = 0x10000000, - Border = 0x00800000, - Overlapped = 0x00000000, - Tiled = 0x00000000, - Maximize = 0x01000000, - Minimize = 0x20000000, - Iconic = 0x20000000, - ThickFrame = 0x00040000, - SizeBox = 0x00040000, - Popup = 0x80000000, - PopupWindow = Popup | Border | SysMenu, - DlgFrame = 0x00400000, - Caption = 0x00C00000, - ChildWindow = 0x40000000, - SysMenu = 0x00080000, - MinimizeBox = 0x00020000, - MaximizeBox = 0x00010000, - OverlappedWindow = Overlapped | Caption | SysMenu | ThickFrame | MinimizeBox | MaximizeBox, - Child = 0x40000000, - ClipChildren = 0x02000000, - ClipSiblings = 0x04000000, - Disabled = 0x08000000, - Group = 0x00020000, - Tabstop = 0x00010000, - TiledWindow = Tiled | Caption | SysMenu | ThickFrame | MinimizeBox | MaximizeBox, - } - - [DllImport("user32.dll")] - public static extern uint GetWindowLong( - IntPtr hWnd, - [MarshalAs(UnmanagedType.U4)] WindowLongs nIndex); - - [DllImport("user32.dll")] - public static extern uint SetWindowLong( - IntPtr hWnd, - [MarshalAs(UnmanagedType.U4)] WindowLongs nIndex, - uint dwNewLong); - } -} diff --git a/WinDirStat.Net.Windows/Native/Win32.cs b/WinDirStat.Net.Windows/Native/Win32.cs deleted file mode 100644 index 84a43cd..0000000 --- a/WinDirStat.Net.Windows/Native/Win32.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace WinDirStat.Net.Windows.Native { - /// A static class for native methods, structs, and enums. - public static partial class Win32 { - - /// An invalid handle value of -1 returned from some functions. - public static readonly IntPtr InvalidHandle = new IntPtr(-1); - - /// Invalid low-order file size returned by . - public const uint InvalidFileSize = 0xFFFFFFFF; - - /// - /// Retrieves information about the amount of space that is available on a disk volume, which is the - /// total amount of space, the total amount of free space, and the total amount of free space - /// available to the user that is associated with the calling thread. - /// - /// - /// A directory on the disk. - /// - /// Receives the total number of free bytes on a disk that are available to the user who is - /// associated with the calling thread. - /// - /// - /// A pointer to a variable that receives the total number of bytes on a disk that are available to - /// the user who is associated with the calling thread. - /// - /// Receives the total number of free bytes on a disk. - /// If the function succeeds, the return value is true. - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetDiskFreeSpaceEx( - string lpDirectoryName, - out ulong lpFreeBytesAvailable, - out ulong lpTotalNumberOfBytes, - out ulong lpTotalNumberOfFreeBytes); - - /// - /// Retrieves the actual number of bytes of disk storage used to store a specified file. If the file - /// is located on a volume that supports compression and the file is compressed, the value obtained - /// is the compressed size of the specified file. If the file is located on a volume that supports - /// sparse files and the file is a sparse file, the value obtained is the sparse size of the - /// specified file. - /// - /// - /// The name of the file. - /// - /// The high-order DWORD of the compressed file size. The function's return value is the low-order - /// DWORD of the compressed file size. - /// - /// - /// If the function succeeds, the return value is the low-order DWORD of the actual number of bytes - /// of disk storage used to store the specified file, and if lpFileSizeHigh is non-NULL, the function - /// puts the high-order DWORD of that actual value into the DWORD pointed to by that parameter. This - /// is the compressed file size for compressed files, the actual file size for noncompressed files. - /// - /// If the function fails, and lpFileSizeHigh is NULL, the return value is INVALID_FILE_SIZE. To get - /// extended error information, call GetLastError. - /// - [DllImport("kernel32.dll", SetLastError = true)] - public static extern uint GetCompressedFileSize( - string lpFileName, - out int lpFileSizeHigh); - - /// Destroys an icon and frees any memory the icon occupied. - /// - /// A handle to the icon to be destroyed. The icon must not be in use. - /// If the function succeeds, the return value is true. - [DllImport("user32.dll", SetLastError = true)] - public static extern bool DestroyIcon( - IntPtr hIcon); - - /// - /// The DeleteObject function deletes a logical pen, brush, font, bitmap, region, or palette, freeing - /// all system resources associated with the object. After the object is deleted, the specified - /// handle is no longer valid. - /// - /// - /// A handle to a logical pen, brush, font, bitmap, region, or palette. - /// If the function succeeds, the return value is true. - [DllImport("gdi32.dll", SetLastError = true)] - public static extern bool DeleteObject( - IntPtr hObject); - - /// - /// Retrieves the path of the system directory. The system directory contains system files such as - /// dynamic-link libraries and drivers. - /// - /// - /// Receives the path - /// The maximum size of the buffer. - /// If the function succeeds, the return value is the length. - [DllImport("kernel32.dll", SetLastError = true)] - public static extern uint GetSystemDirectory(out string lpBuffer, int uSize); - - } -} diff --git a/WinDirStat.Net.Windows/Native/Win32Extensions.cs b/WinDirStat.Net.Windows/Native/Win32Extensions.cs deleted file mode 100644 index e641a7b..0000000 --- a/WinDirStat.Net.Windows/Native/Win32Extensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; - -namespace WinDirStat.Net.Windows.Native { - /// Extentions for native Win32 structures. - internal static class Win32Extensions { - - #region ToDateTime - - /// Converts the native to a local . - public static DateTime ToDateTime(this FILETIME fileTime) { - long ticks = ((long) fileTime.dwHighDateTime << 32) | unchecked((uint) fileTime.dwLowDateTime); - return DateTime.FromFileTime(ticks); - } - - /// Converts the native to a UTC . - public static DateTime ToDateTimeUtc(this FILETIME fileTime) { - long ticks = ((long) fileTime.dwHighDateTime << 32) | unchecked((uint) fileTime.dwLowDateTime); - return DateTime.FromFileTimeUtc(ticks); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Windows/Services/Structures/WindowsScanFileInfo.cs b/WinDirStat.Net.Windows/Services/Structures/WindowsScanFileInfo.cs deleted file mode 100644 index d35d06b..0000000 --- a/WinDirStat.Net.Windows/Services/Structures/WindowsScanFileInfo.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Filesystem.Ntfs; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Windows.Native; - -namespace WinDirStat.Net.Windows.Services.Structures { - /// Information about a file used to populate a file item. - public class WindowsScanFileInfo : IScanFileInfo { - - #region Fields - - /// The name of the file. - public string Name { get; } - /// The full path of the file. - public string FullName { get; } - /// The size of the file. - public long Size { get; } - /// The attributes of the file. - public FileAttributes Attributes { get; } - /// The UTC creation time of the file. - public DateTime CreationTimeUtc { get; } - /// The UTC last access time of the file. - public DateTime LastAccessTimeUtc { get; } - /// The UTC last write time of the file. - public DateTime LastWriteTimeUtc { get; } - - #endregion - - #region Constructors - - /// - /// Constructs the from a . - /// - internal WindowsScanFileInfo(Win32.Win32FindData find, string path) { - Name = find.cFileName; - FullName = path; - Size = find.Size; - Attributes = find.dwFileAttributes; - CreationTimeUtc = find.CreationTimeUtc; - LastAccessTimeUtc = find.LastAccessTimeUtc; - LastWriteTimeUtc = find.LastWriteTimeUtc; - } - - /// Constructs the from a . - internal WindowsScanFileInfo(INtfsNode node) { - Name = node.Name; - FullName = node.FullName; - Size = (long) node.Size; - Attributes = node.Attributes; - CreationTimeUtc = node.CreationTime; - LastAccessTimeUtc = node.LastAccessTime; - LastWriteTimeUtc = node.LastChangeTime; - } - - #endregion - - #region Properties - - /// Gets if the file is a directory. - public bool IsDirectory => Attributes.HasFlag(FileAttributes.Directory); - /// Gets if the file is a symbolic link. - public bool IsSymbolicLink => Attributes.HasFlag(FileAttributes.ReparsePoint); - - #endregion - } -} diff --git a/WinDirStat.Net.Windows/Services/WindowsIconCacheService.cs b/WinDirStat.Net.Windows/Services/WindowsIconCacheService.cs deleted file mode 100644 index da8eadf..0000000 --- a/WinDirStat.Net.Windows/Services/WindowsIconCacheService.cs +++ /dev/null @@ -1,387 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; -using GalaSoft.MvvmLight; -using WinDirStat.Net.Model.Extensions; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -using static WinDirStat.Net.Windows.Native.Win32; - -namespace WinDirStat.Net.Windows.Services { - /// A service for caching file and folder icons. - public class WindowsIconCacheService : ObservableObject, IIconCacheService { - - #region Constants - - private const SHFileInfoFlags CacheIconFlags = - SHFileInfoFlags.SysIconIndex | SHFileInfoFlags.SmallIcon; - - private const SHFileInfoFlags CacheFileTypeFlags = CacheIconFlags | - SHFileInfoFlags.UseFileAttributes | SHFileInfoFlags.TypeName; - - private const SHFileInfoFlags CacheSpecialFolderFlags = CacheIconFlags | - SHFileInfoFlags.PIDL; - - private const SHStockIconFlags CacheStockIconFlags = - SHStockIconFlags.SysIconIndex | SHStockIconFlags.Icon | SHStockIconFlags.SmallIcon; - - #endregion - - #region Fields - - /// The default file icon. - private IImage fileIcon; - /// The default folder icon. - private IImage folderIcon; - /// The default drive icon. - private IImage volumeIcon; - /// The default shortcut icon. - private IImage shortcutIcon; - - /// The service for performing UI actions such as dispatcher invoking. - private readonly IUIService ui; - /// The service for creating and loading bitmaps. - private readonly IBitmapFactory bitmapFactory; - private readonly Dictionary cachedIcons; - private readonly Dictionary cachedSpecialFolders; - private readonly Dictionary cachedFileTypes; - private readonly ObservableCollection cachedIconList; - - #endregion - - #region Constructors - - /// Constructs the . - public WindowsIconCacheService(IUIService ui, - IBitmapFactory bitmapFactory) { - this.ui = ui; - this.bitmapFactory = bitmapFactory; - - cachedIcons = new Dictionary(); - cachedSpecialFolders = new Dictionary(); - cachedFileTypes = new Dictionary(); - cachedIconList = new ObservableCollection(); - } - - #endregion - - #region Properties - - /// Gets the number of cached icons. - public int Count => cachedIcons.Count; - - #endregion - - #region Icon Properties - - /// Gets the default file icon. - public IImage FileIcon { - get => fileIcon ?? (fileIcon = CacheStockIcon(SHStockIconID.DocNoAssoc)); - } - /// Gets the default folder icon. - public IImage FolderIcon { - get => folderIcon ?? (folderIcon = CacheStockIcon(SHStockIconID.Folder)); - } - /// Gets the default drive icon. - public IImage VolumeIcon { - get => volumeIcon ?? (volumeIcon = CacheStockIcon(SHStockIconID.DriveFixed)); - } - /// Gets the default shortcut icon. - public IImage ShortcutIcon { - get => shortcutIcon ?? (shortcutIcon = CacheStockIcon(SHStockIconID.Link)); - } - - #endregion - - #region Icon Caching - - /// Caches the icon of the specified file. - /// - /// The path of the file. - /// The cached icon on success, otherwise null. - public IImage CacheIcon(string path) { - return ui.Invoke(() => CacheIconImpl(path, 0, SHFileInfoFlags.None, out _, out _)); - } - /// Asynchronousy caches the icon of the specified file. - /// - /// The path of the file. - /// The method that returns the icon upon completion. - public void CacheIconAsync(string path, ICacheIconCallback callback) { - if (callback == null) throw new ArgumentNullException(nameof(callback)); - ui.BeginInvoke(() => callback(CacheIcon(path)), false); - } - - /// Caches the icon and display name of the specified file. - /// - /// The path of the file. - /// The cached icon and icon on success, otherwise null. - public IIconAndName CacheIconAndDisplayName(string path) { - return ui.Invoke(() => { - IImage icon = CacheIconImpl(path, 0, SHFileInfoFlags.DisplayName, out string name, out _); - if (icon != null) - return new IIconAndName(icon, name); - return null; - }); - } - /// Asynchronousy caches the icon and display name of the specified file. - /// - /// The path of the file. - /// The method that returns the icon and name upon completion. - public void CacheIconAndDisplayNameAsync(string path, ICacheIconAndNameCallback callback) { - if (callback == null) throw new ArgumentNullException(nameof(callback)); - ui.BeginInvoke(() => callback(CacheIconAndDisplayName(path)), false); - } - - /// Caches the file type's icon and type name. - /// - /// The extension of the file type. - /// The cached icon and type name on success, otherwise null. - public IIconAndName CacheFileType(string extension) { - return ui.Invoke(() => { - if (!cachedFileTypes.TryGetValue(extension, out IIconAndName iconName)) { - try { - // Empty extensions will just return the Local Disk instead of a proper file - string extensionPath = extension; - if (extension == ExtensionItem.EmptyExtension) - extensionPath = Guid.NewGuid().ToString(); - IImage icon = CacheIconImpl(extensionPath, FileAttributes.Normal, - CacheFileTypeFlags, out _, out string typeName); - if (icon != null) - iconName = new IIconAndName(icon, typeName); - cachedFileTypes.Add(extension, iconName); - } - catch { } - } - return iconName; - }); - } - /// Asynchronousy caches the file type's icon and type name. - /// - /// The extension of the file type. - /// The method that returns the icon and type name upon completion. - public void CacheFileTypeAsync(string extension, ICacheIconAndNameCallback callback) { - if (callback == null) throw new ArgumentNullException(nameof(callback)); - ui.BeginInvoke(() => callback(CacheFileType(extension)), false); - } - - /// Caches the special folder's icon and display name. - /// - /// The special folder type. - /// The cached icon and name on success, otherwise null. - public IIconAndName CacheSpecialFolder(Environment.SpecialFolder folder) { - return ui.Invoke(() => { - if (!cachedSpecialFolders.TryGetValue(folder, out IIconAndName iconName)) { - try { - IImage icon = CacheSpecialFolderImpl(folder, 0, SHFileInfoFlags.DisplayName, - out string name, out _); - if (icon != null) - iconName = new IIconAndName(icon, name); - cachedSpecialFolders.Add(folder, iconName); - } - catch { } - } - return iconName; - }); - } - /// Asynchronousy caches the special folder's icon and display name. - /// - /// The special folder type. - /// The method that returns the icon and name upon completion. - public void CacheSpecialFolderAsync(Environment.SpecialFolder folder, ICacheIconAndNameCallback callback) { - if (callback == null) throw new ArgumentNullException(nameof(callback)); - ui.BeginInvoke(() => callback(CacheSpecialFolder(folder)), false); - } - - #endregion - - #region Private Icon Caching - - /// Caches a stock icon. - /// - /// The id of the stock icon. - /// The icon on success, otherwise null. - private IImage CacheStockIcon(SHStockIconID id) { - return ui.Invoke(() => CacheStockIconImpl(id, SHStockIconFlags.None)); - } - - #endregion - - #region Cache Implementation - - /// The implementation for caching icons with a path. - /// - /// The file path or extension. - /// The optional file attributes. - /// Get flags for getting the icon. - /// - /// The output display name if is used in . - /// - /// - /// The output type name if is used in . - /// - /// The icon on success, otherwise null. - private IImage CacheIconImpl(string path, FileAttributes attributes, SHFileInfoFlags flags, - out string displayName, out string typeName) - { - displayName = null; - typeName = null; - flags |= CacheIconFlags; - - IImage icon = null; - SHFileInfo fileInfo = new SHFileInfo(); - IntPtr hImageList = SHGetFileInfo(path, attributes, ref fileInfo, SHFileInfo.CBSize, flags); - try { - if (hImageList == IntPtr.Zero) - return null; - - if (flags.HasFlag(SHFileInfoFlags.DisplayName)) - displayName = fileInfo.szDisplayName; - if (flags.HasFlag(SHFileInfoFlags.TypeName)) - typeName = fileInfo.szTypeName; - - icon = TryAddIconToCache(fileInfo.iIcon, () => ExtractIcon(hImageList, fileInfo.iIcon)); - if (icon != null) - Debug.WriteLine($"Cache[{Count}]: " + path); - else - Debug.WriteLine($"Failed to load icon for \"{path}\"!"); - } - finally { - ImageList_Destroy(hImageList); - } - return icon; - } - - /// The implementation for caching icons with a special folder. - /// - /// The special folder to get the icon of. - /// The optional file attributes. - /// Get flags for getting the icon. - /// - /// The output display name if is used in . - /// - /// - /// The output type name if is used in . - /// - /// The icon on success, otherwise null. - private IImage CacheSpecialFolderImpl(Environment.SpecialFolder folder, FileAttributes attributes, - SHFileInfoFlags flags, out string displayName, out string typeName) - { - displayName = null; - typeName = null; - flags |= CacheSpecialFolderFlags; - - IntPtr pidl = IntPtr.Zero; - IImage icon = null; - SHFileInfo fileInfo = new SHFileInfo(); - if (SHGetSpecialFolderLocation(IntPtr.Zero, folder, ref pidl)) - return null; - IntPtr hImageList = SHGetFileInfo(pidl, attributes, ref fileInfo, SHFileInfo.CBSize, flags); - try { - if (hImageList == IntPtr.Zero) - return null; - - if (flags.HasFlag(SHFileInfoFlags.DisplayName)) - displayName = fileInfo.szDisplayName; - if (flags.HasFlag(SHFileInfoFlags.TypeName)) - typeName = fileInfo.szTypeName; - - icon = TryAddIconToCache(fileInfo.iIcon, () => ExtractIcon(hImageList, fileInfo.iIcon)); - if (icon != null) - Debug.WriteLine($"Cache[{Count}]: " + pidl); - else - Debug.WriteLine($"Failed to load icon for \"{pidl}\"!"); - } - finally { - ImageList_Destroy(hImageList); - Marshal.FreeCoTaskMem(pidl); - } - return icon; - } - - /// The implementation for caching stock icons. - /// - /// The id of the stock icon. - /// The flags for caching the stock icon. - /// The icon on success, otherwise null. - private IImage CacheStockIconImpl(SHStockIconID id, SHStockIconFlags flags) { - flags |= CacheStockIconFlags; - - IImage icon = null; - SHStockIconInfo stockInfo = new SHStockIconInfo { - cbSize = SHStockIconInfo.CBSize, - }; - if (SHGetStockIconInfo(id, flags, ref stockInfo)) - return null; - try { - if (!cachedIcons.TryGetValue(stockInfo.iSysIconIndex, out icon)) { - icon = TryAddIconToCache(stockInfo.iSysIconIndex, () => ExtractIcon(stockInfo.hIcon)); - if (icon != null) - Debug.WriteLine($"Cache[{Count}]: " + id); - else - Debug.WriteLine($"Failed to load icon for \"{id}\"!"); - } - } - finally { - DestroyIcon(stockInfo.hIcon); - } - return icon; - } - - #endregion - - #region Add/Extracting - - /// - /// Tries to add the icon to the cache, if it does exist, is called to get - /// the icon. - /// - /// - /// The system index of the icon. - /// The method to extract the icon. - /// The extracted icon on success, otherwise null. - private IImage TryAddIconToCache(int systemIndex, Func extract) { - if (!cachedIcons.TryGetValue(systemIndex, out IImage icon)) { - try { - icon = extract(); - cachedIcons.Add(systemIndex, icon); - cachedIconList.Add(icon); - } - catch { } - } - return icon; - } - - /// Extracts the icon from the image list. - /// - /// The handle to the image list. - /// The system index of the icon. - /// The extracted icon on success, otherwise null. - private IImage ExtractIcon(IntPtr hImageList, int systemIndex) { - IntPtr hIcon = ImageList_GetIcon(hImageList, systemIndex, ImageListDrawFlags.Normal); - try { - return ExtractIcon(hIcon); - } - finally { - if (hIcon != IntPtr.Zero) - DestroyIcon(hIcon); - } - } - - /// Extracts the icon from the handle. - /// - /// The handle to the icon. - /// The extracted icon on success, otherwise null. - protected IImage ExtractIcon(IntPtr hIcon) { - return bitmapFactory.FromHIcon(hIcon); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Windows/Services/WindowsOSService.cs b/WinDirStat.Net.Windows/Services/WindowsOSService.cs deleted file mode 100644 index f50ffa6..0000000 --- a/WinDirStat.Net.Windows/Services/WindowsOSService.cs +++ /dev/null @@ -1,241 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Security.Principal; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -using static WinDirStat.Net.Windows.Native.Win32; - -namespace WinDirStat.Net.Windows.Services { - /// A service for OS-specific actions. - public class WindowsOSService : IOSService { - - #region Fields - - /// The service for performing UI actions such as dispatcher invoking. - private readonly IUIService ui; - /// True if the current process has elevated privileges. - private bool? isElevated; - - #endregion - - #region Constructors - - /// Constructs the . - public WindowsOSService(IUIService ui) { - this.ui = ui; - } - - #endregion - - #region Privileges - - /// Gets if the current process has elevated privileges. - public bool IsElevated { - get { - if (!isElevated.HasValue) - isElevated = WindowsIdentity.GetCurrent().Owner - .IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid); - return isElevated.Value; - } - } - - public void StartNewElevated(string arguments = "") { - Process current = Process.GetCurrentProcess(); - ProcessStartInfo startInfo = new ProcessStartInfo { - FileName = current.MainModule.FileName, - Arguments = arguments + " " + string.Join(" ", Environment.GetCommandLineArgs().Select(a => "\"" + a + "\"")), - WorkingDirectory = Directory.GetCurrentDirectory(), - Verb = "runas", - }; - Process.Start(startInfo).Dispose(); - } - - #endregion - - #region RunItem - - /// Opens the specified item using the default action. - /// - /// The file to open. - public void RunItem(string file) { - ProcessStartInfo startInfo = new ProcessStartInfo { - FileName = file, - }; - Process.Start(startInfo)?.Dispose(); - } - - #endregion - - #region Explore - - /// Opens the computer folder in Explorer. - public void ExploreComputer() { - ProcessStartInfo startInfo = new ProcessStartInfo { - FileName = "explorer.exe", - Arguments = "::{20d04fe0-3aea-1069-a2d8-08002b30309d}", - }; - Process.Start(startInfo)?.Dispose(); - } - - /// Opens the folder in Explorer. - /// - /// The path of the folder to open. - public void ExploreFolder(string folderPath) { - ProcessStartInfo startInfo = new ProcessStartInfo { - FileName = "explorer.exe", - Arguments = $"\"{folderPath}\"", - }; - Process.Start(startInfo)?.Dispose(); - } - - /// Opens the parent folder in Explorer and selects the file. - /// - /// The path of the file to select. - public void ExploreFile(string filePath) { - ProcessStartInfo startInfo = new ProcessStartInfo { - FileName = "explorer.exe", - Arguments = $"/select,\"{filePath}\"", - }; - Process.Start(startInfo)?.Dispose(); - } - - /// Opens the properties window for the computer. - public bool OpenComputerProperties(string filePath) { - return OpenProperties("::{20d04fe0-3aea-1069-a2d8-08002b30309d}"); - } - - /// Opens the properties window of the file. - /// The path of the file to view the properties of. - public bool OpenProperties(string filePath) { - ShellExecuteInfo info = new ShellExecuteInfo { - cbSize = ShellExecuteInfo.CBSize, - lpVerb = "properties", - lpFile = filePath, - nShow = ShowCommands.Show, - fMask = ShellExecuteMaskFlags.InvokeIDList, - }; - return ShellExecuteEx(ref info); - } - - #endregion - - #region Console - - /// Opens the command prompt in the specified working directory. - /// - /// The working directory to open the command prompt in. - public void OpenCommandPrompt(string directory) { - ProcessStartInfo startInfo = new ProcessStartInfo { - FileName = "cmd.exe", - WorkingDirectory = directory, - }; - Process.Start(startInfo)?.Dispose(); - } - - /// Opens PowerShell in the specified working directory. - /// - /// The working directory to open PowerShell in. - public void OpenPowerShell(string directory) { - ProcessStartInfo startInfo = new ProcessStartInfo { - FileName = "powershell.exe", - WorkingDirectory = directory, - }; - Process.Start(startInfo)?.Dispose(); - } - - #endregion - - #region Delete/Recycle - - /// Permanently deletes the file. - /// - /// The path of the file to delete. - /// True if the operation was successful. - public bool DeleteFile(string file) { - return DeleteOrRecycleFile(file, false); - } - - /// Sends the file or directory to the recycle bin. - /// - /// The path of the file to delete. - /// True if the operation was successful. - public bool RecycleFile(string file) { - return DeleteOrRecycleFile(file, true); - } - - /// Deletes or recycles the file based on the conditional value. - /// - /// The path of the file to delete. - /// True if the file should be recycled. - /// True if the operation was successful. - public bool DeleteOrRecycleFile(string file, bool recycle) { - return ui.Invoke(() => { - FileOperationFlags flags = FileOperationFlags.None; - if (recycle) - flags = FileOperationFlags.AllowUndo | FileOperationFlags.WarnFilesTooBigForRecycleBin; - SHFileOperationStruct fileOp = new SHFileOperationStruct { - wFunc = FileOperationFunc.Delete, - pFrom = file + '\0' + '\0', - fFlags = flags, - }; - return !SHFileOperation(ref fileOp); - }); - } - - /// Empties the recycle bin at the specified path. - /// - /// The window to own the dialogs. - /// The path of the recycle bin - /// True if the operation was successful. - public bool EmptyRecycleBin(IWindow owner, string path = "") { - return ui.Invoke(() => { - return !SHEmptyRecycleBin(owner.Handle, path, SHEmptyRecycleBinFlags.None); - }); - } - - /// Gets the stats about the specified recycle bin. - /// - /// The path of the recycle bin - /// The info about the recycle bin on success, otherwise null. - public RecycleBinInfo GetRecycleBinInfo(string path) { - //return ui.Invoke(() => { - SHRecycleBinInfo rbInfo = new SHRecycleBinInfo { - cbSize = SHRecycleBinInfo.CBSize, - }; - if (!SHQueryRecycleBin(path, ref rbInfo)) - return new RecycleBinInfo(path, rbInfo.i64NumItems, rbInfo.i64Size); - return null; - //}); - } - - /// Gets the stats about every recycle bin. - /// - /// The info about the recycle bin on success, otherwise null. - public RecycleBinInfo GetAllRecycleBinInfo() { - //return ui.Invoke(() => { - long itemCount = 0; - long size = 0; - foreach (DriveInfo driveInfo in DriveInfo.GetDrives()) { - if (driveInfo.IsReady && driveInfo.DriveType != DriveType.Unknown && - driveInfo.DriveType != DriveType.NoRootDirectory) - { - RecycleBinInfo rbInfo = GetRecycleBinInfo(driveInfo.Name); - if (rbInfo != null) { - itemCount += rbInfo.ItemCount; - size += rbInfo.Size; - } - } - } - return new RecycleBinInfo(itemCount, size); - //}); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Windows/Services/WindowsScanningService.Mft.cs b/WinDirStat.Net.Windows/Services/WindowsScanningService.Mft.cs deleted file mode 100644 index 8adcc7b..0000000 --- a/WinDirStat.Net.Windows/Services/WindowsScanningService.Mft.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Filesystem.Ntfs; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using WinDirStat.Net.Model.Extensions; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Utils; -using WinDirStat.Net.Windows.Services.Structures; - -namespace WinDirStat.Net.Windows.Services { - partial class WindowsScanningService { - - #region Private Structures - - private class FileNodeIndexes { - public FileItemBase FileItem; - public FolderItem FileCollection; - public FileItem FirstFile; - public uint NodeIndex; - public uint ParentNodeIndex; - public string FullName; - - public FileNodeIndexes(FileItemBase fileItem, INtfsNode ntfsNode) { - FileItem = fileItem; - NodeIndex = ntfsNode.NodeIndex; - ParentNodeIndex = ntfsNode.ParentNodeIndex; - FullName = PathUtils.TrimSeparatorDotEnd(ntfsNode.FullName); - } - } - - #endregion - - private void ScanMtf(ScanningState state, CancellationToken token) { - FileNodeIndexes[] fileItemsLookup; - List fileItems = new List(); - - DriveInfo driveInfo = new DriveInfo(Path.GetPathRoot(state.RootPath)); - using (NtfsReader ntfs = new NtfsReader(driveInfo, RetrieveMode.StandardInformations)) { - fileItemsLookup = new FileNodeIndexes[ntfs.NodeCount]; - ReadMft(state, ntfs, fileItemsLookup, fileItems, token); - } - - foreach (FileNodeIndexes indexes in fileItems) { - FileItemBase item = indexes.FileItem; - FileNodeIndexes parentIndexes = fileItemsLookup[indexes.ParentNodeIndex]; - if (indexes.NodeIndex == indexes.ParentNodeIndex) { - // This must be the drive root - } - else if (parentIndexes != null) { - ((FolderItem) parentIndexes.FileItem).AddItem(item, - ref parentIndexes.FileCollection, ref parentIndexes.FirstFile); - } - else { - // This must be the root - } - if (AsyncChecks(token)) - return; - } - } - - private void ReadMft(ScanningState state, NtfsReader ntfs, FileNodeIndexes[] fileItemsLookup, - List fileItems, CancellationToken token) - { - foreach (INtfsNode node in ntfs.EnumerateNodes(state.RootPath)) { - string fullPath = PathUtils.TrimSeparatorDotEnd(node.FullName); - bool isRoot = (node.NodeIndex == node.ParentNodeIndex); - if (!isRoot && SkipFile(state, Path.GetFileName(fullPath), fullPath)) - continue; - FileItemBase child; - bool reparsePoint = node.Attributes.HasFlag(FileAttributes.ReparsePoint); - if (isRoot) { - child = state.Root; - } - else if (node.Attributes.HasFlag(FileAttributes.Directory)) { - if (!state.IsDrive && state.RootPath == node.FullName.ToUpperInvariant()) { - child = state.Root; - } - else { - child = new FolderItem(new WindowsScanFileInfo(node)); - } - } - else { - ExtensionItem extension = Extensions.GetOrAddFromPath(node.Name); - FileItem file = new FileItem(new WindowsScanFileInfo(node), extension); - child = file; - if (!reparsePoint) - TotalScannedSize += child.Size; - } - FileNodeIndexes indexes = new FileNodeIndexes(child, node); - fileItemsLookup[node.NodeIndex] = indexes; - - if (!reparsePoint) - fileItems.Add(indexes); - - if (AsyncChecks(token)) - return; - } - } - - - /*private void ScanMtf(ScanningState state, CancellationToken token) { - Dictionary fileItems = new Dictionary(); - - DriveInfo driveInfo = new DriveInfo(Path.GetPathRoot(state.RootPath)); - using (NtfsReader ntfs = new NtfsReader(driveInfo, RetrieveMode.StandardInformations)) { - ReadMft(state, ntfs, fileItems, token); - } - - foreach (FileNodeIndexes indexes in fileItems.Values) { - FileItemBase item = indexes.FileItem; - if (indexes.NodeIndex == indexes.ParentNodeIndex) { - // This must be the drive root - } - else if (fileItems.TryGetValue(indexes.ParentNodeIndex, out var parentIndexes)) { - ((FolderItem) parentIndexes.FileItem).AddItem(item, - ref parentIndexes.FileCollection, ref parentIndexes.FirstFile); - } - else { - // This must be the root - } - if (AsyncChecks(token)) - return; - } - } - - private void ReadMft(ScanningState state, NtfsReader ntfs, Dictionary fileNodes, - CancellationToken token) { - foreach (INtfsNode node in ntfs.EnumerateNodes(state.RootPath)) { - string fullPath = PathUtils.TrimSeparatorDotEnd(node.FullName); - bool isRoot = (node.NodeIndex == node.ParentNodeIndex); - if (!isRoot && SkipFile(state, Path.GetFileName(fullPath), fullPath)) - continue; - FileItemBase child; - if (isRoot) { - child = state.Root; - } - else if (node.Attributes.HasFlag(FileAttributes.Directory)) { - if (!state.IsDrive && state.RootPath == node.FullName.ToUpperInvariant()) { - child = state.Root; - } - else { - child = new FolderItem(new ScanFileInfo(node)); - } - } - else { - ExtensionItem extension = Extensions.GetOrAddFromPath(node.Name); - FileItem file = new FileItem(new ScanFileInfo(node), extension); - child = file; - if (!node.Attributes.HasFlag(FileAttributes.ReparsePoint)) { - state.ScannedSize += child.Size; - TotalScannedSize += child.Size; - } - } - fileNodes[node.NodeIndex] = new FileNodeIndexes(child, node); - - if (AsyncChecks(token)) - return; - } - }*/ - } -} diff --git a/WinDirStat.Net.Windows/Services/WindowsScanningService.Native.cs b/WinDirStat.Net.Windows/Services/WindowsScanningService.Native.cs deleted file mode 100644 index 58949fa..0000000 --- a/WinDirStat.Net.Windows/Services/WindowsScanningService.Native.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using WinDirStat.Net.Model.Extensions; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Utils; -using WinDirStat.Net.Windows.Services; -using WinDirStat.Net.Windows.Services.Structures; -using static WinDirStat.Net.Windows.Native.Win32; - -namespace WinDirStat.Net.Windows.Services { - partial class WindowsScanningService { - private struct FolderState { - public FolderItem Folder; - public ScanningState State; - - public FolderState(ScanningState state) { - Folder = state.Root; - State = state; - } - - public FolderState(FolderItem folder, ScanningState state) { - State = state; - Folder = folder; - } - } - - private void ScanNative(CancellationToken token) { - Queue subdirs = new Queue(); - foreach (ScanningState state in scanningStates) - subdirs.Enqueue(new FolderState(state)); - do { - ReadNative(subdirs, token); - } while (subdirs.Any() && !AsyncChecks(token)); - } - - private void ReadNative(Queue subdirs, CancellationToken token) { - Win32FindData find = new Win32FindData(); - FolderState folderState = subdirs.Dequeue(); - ScanningState state = folderState.State; - FolderItem parent = folderState.Folder; - bool findResult; - string parentPath = parent.FullName; - string searchPattern = PathUtils.CombineNoChecks(parentPath, "*"); - if (!searchPattern.StartsWith(@"\\?\")) - searchPattern = @"\\?\" + searchPattern; - IntPtr hFind = FindFirstFileEx(searchPattern, - FindExInfoLevels.Basic, out find, - FindExSearchOps.NameMatch, IntPtr.Zero, - FindExFlags.LargeFetch); - if (hFind == InvalidHandle) - return; - - FolderItem fileCollection = null; - FileItem firstFile = null; - bool subdirsAdded = false; - try { - do { - string filePath = PathUtils.CombineNoChecks(parentPath, find.cFileName); - if (find.IsRelativeDirectory || SkipFile(state, find.cFileName, filePath)) { - // Skip these types of entries - findResult = FindNextFile(hFind, out find); - continue; - } - FileItemBase child; - if (find.IsDirectory) { - FolderItem folder = new FolderItem(new WindowsScanFileInfo(find, filePath)); - child = folder; - if (!find.IsSymbolicLink) { - subdirsAdded = true; - subdirs.Enqueue(new FolderState(folder, state)); - } - } - else { - ExtensionItem extension = Extensions.GetOrAddFromPath(filePath); - FileItem file = new FileItem(new WindowsScanFileInfo(find, filePath), extension); - child = file; - if (!find.IsSymbolicLink) - TotalScannedSize += child.Size; - } - parent.AddItem(child, ref fileCollection, ref firstFile); - - if (AsyncChecks(token)) - return; - - findResult = FindNextFile(hFind, out find); - } while (findResult); - - if (!subdirsAdded) - parent.Finish(); - //if (parent.IsWatched) - // parent.RaiseChanged(FileItemAction.ChildrenDone); - } - finally { - FindClose(hFind); - } - } - } -} diff --git a/WinDirStat.Net.Windows/Services/WindowsScanningService.Refresh.cs b/WinDirStat.Net.Windows/Services/WindowsScanningService.Refresh.cs deleted file mode 100644 index 3ce6e55..0000000 --- a/WinDirStat.Net.Windows/Services/WindowsScanningService.Refresh.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using WinDirStat.Net.Model.Extensions; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Windows.Services { - partial class WindowsScanningService { - - protected override void Refresh(RefreshFiles[] refreshFiles, CancellationToken token) { - CanDisplayProgress = RootItem.Type == FileItemType.Volume || - (RootItem.Type == FileItemType.Computer && - !RootItem.Children.Any(f => f.Type != FileItemType.Volume && - f.Type != FileItemType.FreeSpace && f.Type != FileItemType.Unknown)); - if (CanDisplayProgress) { - if (RootItem.Type == FileItemType.Volume) { - try { - if (RootItem.CheckExists()) { - DriveInfo driveInfo = new DriveInfo(RootItem.RootPath); - TotalSize = driveInfo.TotalSize; - TotalFreeSpace = driveInfo.TotalFreeSpace; - } - else { - CanDisplayProgress = false; - } - } - catch { - CanDisplayProgress = false; - } - } - else if (RootItem.Type == FileItemType.Computer) { - bool anySuccess = false; - foreach (FileItemBase child in RootItem.Children) { - if (child is RootItem root) { - try { - if (root.CheckExists()) { - DriveInfo driveInfo = new DriveInfo(root.RootPath); - TotalSize += driveInfo.TotalSize; - TotalFreeSpace += driveInfo.TotalFreeSpace; - anySuccess = true; - continue; - } - } - catch { } - TotalSize += root.CachedTotalSize; - TotalFreeSpace += root.CachedFreeSpace; - } - } - if (!anySuccess) - CanDisplayProgress = false; - } - } - // Reset the progress if applicable - TotalScannedSize = Extensions.TotalSize - refreshFiles.Sum(rf => rf.Files.Sum(f => f.Size)); - ProgressState = ScanProgressState.Started; - - foreach (RefreshFiles refresh in refreshFiles) { - FolderItem parent = refresh.Parent; - FolderItem fileCollection = parent.GetFileCollection(); - - Queue subdirs = new Queue(); - - foreach (FileItemBase refreshChild in refresh.Files) { - if (!refreshChild.Refresh()) { - string fullName = refreshChild.FullName; - parent.RemoveItem(refreshChild, ref fileCollection); - - // See if the type changed (file <-> directory) - FileItemBase child = null; - if (refreshChild.Type == FileItemType.File) { - DirectoryInfo info = new DirectoryInfo(fullName); - if (info.Exists) { - FolderItem folder = new FolderItem(info); - child = folder; - // Folder exists enqueue it for scanning - if (!info.Attributes.HasFlag(FileAttributes.ReparsePoint)) - subdirs.Enqueue(folder); - } - } - else if (refreshChild.Type == FileItemType.Directory) { - FileInfo info = new FileInfo(fullName); - if (info.Exists) { - ExtensionItem extension = Extensions.GetOrAddFromPath(fullName); - FileItem file = new FileItem(info, extension); - child = file; - // File exists, add it to the scanned size - if (!info.Attributes.HasFlag(FileAttributes.ReparsePoint)) - TotalScannedSize += child.Size; - } - } - if (child != null) { - FileItem firstFile = parent.GetFirstFile(); - parent.AddItem(child, ref fileCollection, ref firstFile); - } - } - else if (!refreshChild.IsReparsePointFile) { - // Folder exists enqueue it for scanning - if (refreshChild is FolderItem folder) - subdirs.Enqueue(folder); - // File exists, add it to the scanned size - else - TotalScannedSize += refreshChild.Size; - } - - if (AsyncChecks(token)) - return; - } - - if (subdirs.Count > 0) - RefreshFolders(subdirs, token); - - if (AsyncChecks(token)) - return; - } - } - - private void RefreshFolders(Queue subdirs, CancellationToken token) { - scanningStates = new List(); - foreach (FolderItem subdir in subdirs) - scanningStates.Add(CreateState(subdir)); - - // Master file tables cannot be scanned inline, so scan them one at a time first - for (int i = 0; i < scanningStates.Count; i++) { - ScanningState state = scanningStates[i]; - try { - ScanMtf(state, token); - scanningStates.RemoveAt(i--); - } - catch (Exception) { - // We don't have permission, are not elevated, or path is not an NTFS drive - // We'll scan this path normally instead - } - } - - if (scanningStates.Count > 0) - ScanNative(token); - - scanningStates = null; - } - } -} diff --git a/WinDirStat.Net.Windows/Services/WindowsScanningService.cs b/WinDirStat.Net.Windows/Services/WindowsScanningService.cs deleted file mode 100644 index 6cb842d..0000000 --- a/WinDirStat.Net.Windows/Services/WindowsScanningService.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; -using WinDirStat.Net.Model.Extensions; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Services; -using WinDirStat.Net.Utils; -using WinDirStat.Net.Windows.Native; -using System.Runtime.InteropServices; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Windows.Services { - public partial class WindowsScanningService : ScanningService { - - #region Private Classes - - private class ScanningState { - public long TotalSize; - public long FreeSpace; - public string RootPath; - public bool IsDrive; - public string RecycleBinPath; - public FolderItem Root; - } - - #endregion - - #region Fields - - private List scanningStates; - - #endregion - - #region Constructors - - public WindowsScanningService(SettingsService settings, - IOSService os, - IUIService ui) - : base(settings, - os, - ui) - { - } - - #endregion - - public long GetCompressedFileSize(string filePath) { - uint low = Win32.GetCompressedFileSize(filePath, out int high); - if (low == Win32.InvalidFileSize) { - int error = Marshal.GetLastWin32Error(); - if (error != 0) - throw new Win32Exception(error); - } - return ((long) high << 32) | low; - } - - /// Runs the actual scan on any number of root paths. - /// - /// The root paths to scan. - /// The token for cleanly cancelling the operations. - protected override void Scan(string[] rootPaths, CancellationToken token) { - // See if we can perform a single scan - if (rootPaths.Length == 1) { - Scan(rootPaths[0], token); - return; - } - - scanningStates = rootPaths.Select(p => CreateState(p, false)).ToList(); - CanDisplayProgress = !scanningStates.Any(s => !s.IsDrive); - - TotalSize = scanningStates.Sum(s => s.TotalSize); - TotalFreeSpace = scanningStates.Sum(s => s.FreeSpace); - - // Computer Root - RootItem computerRoot = new RootItem(this); - foreach (ScanningState state in scanningStates) { - computerRoot.AddItem(state.Root); - } - - RootItem = computerRoot; - ProgressState = ScanProgressState.Started; - - // Master file tables cannot be scanned inline, so scan them one at a time first - for (int i = 0; i < scanningStates.Count; i++) { - ScanningState state = scanningStates[i]; - try { - ScanMtf(state, token); - scanningStates.RemoveAt(i--); - } - catch (Exception) { - // We don't have permission, are not elevated, or path is not an NTFS drive - // We'll scan this path normally instead - } - } - - // Are there any leftover states to work on? - if (scanningStates.Any()) - ScanNative(token); - - FinishScan(token); - } - - /// Runs the actual scan on a single root path. - /// - /// The single root path to scan. - /// The token for cleanly cancelling the operations. - private void Scan(string rootPath, CancellationToken token) { - ScanningState state = CreateState(rootPath, true); - scanningStates = new List() { state }; - CanDisplayProgress = scanningStates[0].IsDrive; - - TotalSize = state.TotalSize; - TotalFreeSpace = state.FreeSpace; - - RootItem = (RootItem) state.Root; - ProgressState = ScanProgressState.Started; - - try { - ScanMtf(state, token); - } - catch (Exception) { - // We don't have permission, are not elevated, or path is not an NTFS drive - // We'll scan this path normally instead - ScanNative(token); - } - FinishScan(token); - } - - /// Performs the final opreations after a scan. - /// - private void FinishScan(CancellationToken token) { - scanningStates = null; - if (!token.IsCancellationRequested) { - RootItem.Finish(); - } - } - - /// Creates a for the specified root path. - /// - /// The path to create a state for. - /// - /// True if the there is only one state. - /// This means this is the absolute root item instead of Computer. - /// - /// The newly created and initialized . - private ScanningState CreateState(string rootPath, bool single) { - rootPath = Path.GetFullPath(rootPath); - string pathRoot = Path.GetPathRoot(rootPath); - ScanningState state = new ScanningState { - IsDrive = PathUtils.IsSamePath(pathRoot, rootPath), - RecycleBinPath = Path.Combine(pathRoot, "$Recycle.Bin"), - Root = new RootItem(this, new DirectoryInfo(rootPath), single), - RootPath = rootPath.ToUpperInvariant(), - }; - if (state.IsDrive) { - Win32.GetDiskFreeSpaceEx(rootPath, out _, out ulong totalSize, out ulong freeSpace); - state.TotalSize = (long) totalSize; - state.FreeSpace = (long) freeSpace; - } - return state; - } - - /// - /// Creates a for the specified . - /// - /// - /// The folder to create the state for. - /// The newly created and initialized . - private ScanningState CreateState(FolderItem folder) { - string rootPath = folder.FullName; - string pathRoot = Path.GetPathRoot(rootPath); - ScanningState state = new ScanningState { - IsDrive = PathUtils.IsSamePath(pathRoot, rootPath), - RecycleBinPath = Path.Combine(pathRoot, "$Recycle.Bin"), - Root = folder, - RootPath = rootPath.ToUpperInvariant(), - }; - if (state.IsDrive) { - Win32.GetDiskFreeSpaceEx(rootPath, out _, out ulong totalSize, out ulong freeSpace); - state.TotalSize = (long) totalSize; - state.FreeSpace = (long) freeSpace; - } - return state; - } - - /// Checks if we should ignore this file in the scan. - /// - /// The scan state for this file. - /// The name of the file. - /// The full path of the file. - /// True if the file should be skipped. - private bool SkipFile(ScanningState state, string name, string path) { - if (name.Length == 0) - Console.WriteLine("WHAT"); - // We still want to see all those delicious files that were thrown away - if (name[0] == '$' && !path.StartsWith(state.RecycleBinPath)) - return true; - - // Certified spam - //if (string.Compare(name, "desktop.ini", true) == 0) - // return true; - - return false; - } - - protected override void FinishedCleanup() { - scanningStates = null; - } - - protected override void ClosedCleanup() { - } - } -} diff --git a/WinDirStat.Net.Windows/WinDirStat.Net.Windows.csproj b/WinDirStat.Net.Windows/WinDirStat.Net.Windows.csproj deleted file mode 100644 index f66832f..0000000 --- a/WinDirStat.Net.Windows/WinDirStat.Net.Windows.csproj +++ /dev/null @@ -1,49 +0,0 @@ - - - - net462 - latest - true - Debug;Release - - - - - - - - - - - - - - Native\Win32.cs - - - Native\Win32.cs - - - Native\Win32.cs - - - Native\Win32.cs - - - Native\Win32.cs - - - Native\Win32.cs - - - Native\Win32.cs - - - Native\Win32.cs - - - Native\Win32.cs - - - - diff --git a/WinDirStat.Net.Wpf.Base/Model/Drives/DriveItems.cs b/WinDirStat.Net.Wpf.Base/Model/Drives/DriveItems.cs index 8fd961d..34901f1 100644 --- a/WinDirStat.Net.Wpf.Base/Model/Drives/DriveItems.cs +++ b/WinDirStat.Net.Wpf.Base/Model/Drives/DriveItems.cs @@ -1,17 +1,12 @@ -using System; -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using WinDirStat.Net.Services; using WinDirStat.Net.Utils; -namespace WinDirStat.Net.Model.Drives { - /// A collection of see s. - public class DriveItems : ObservablePropertyCollectionObject, IReadOnlyList { +namespace WinDirStat.Net.Model.Drives { + /// A collection of see s. + public class DriveItems : ObservablePropertyCollectionObject, IReadOnlyList { #region Fields @@ -39,7 +34,7 @@ public void Refresh() { if (drives.Count > 0) { List oldItems = drives.GetFullRange(); drives.Clear(); - RaisePropertyChanged(nameof(Count)); + OnPropertyChanged(nameof(Count)); RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, oldItems, 0); } drives.AddRange(scanning.ScanDrives()); diff --git a/WinDirStat.Net.Wpf.Base/Model/Extensions/ExtensionItems.cs b/WinDirStat.Net.Wpf.Base/Model/Extensions/ExtensionItems.cs index 164be02..1afa3f9 100644 --- a/WinDirStat.Net.Wpf.Base/Model/Extensions/ExtensionItems.cs +++ b/WinDirStat.Net.Wpf.Base/Model/Extensions/ExtensionItems.cs @@ -1,22 +1,18 @@ -using System; -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using WinDirStat.Net.Services; using WinDirStat.Net.Utils; using static WinDirStat.Net.Model.Extensions.ExtensionItem; -namespace WinDirStat.Net.Model.Extensions { - /// - /// A collection that maintains information about all extensions encountered while scanning the file - /// tree. - /// - public class ExtensionItems : ObservablePropertyCollectionObject, IReadOnlyList { +namespace WinDirStat.Net.Model.Extensions { + /// + /// A collection that maintains information about all extensions encountered while scanning the file + /// tree. + /// + public class ExtensionItems : ObservablePropertyCollectionObject, IReadOnlyList { #region Fields @@ -87,12 +83,12 @@ private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e /// Gets the total size of all files in the file tree. public long TotalSize { get => totalSize; - internal set => Set(ref totalSize, value); + internal set => SetProperty(ref totalSize, value); } /// Gets the total number of files in the file tree. public long TotalFileCount { get => totalFileCount; - internal set => Set(ref totalFileCount, value); + internal set => SetProperty(ref totalFileCount, value); } /// Gets the number of extensions in the file tree. @@ -125,8 +121,8 @@ public ExtensionItem GetOrAdd(string extension) { extensions.Add(extension, item); sortedExtensions.Add(item); if (unusedFound) - RaisePropertyChanged(nameof(UnusedCount)); - RaisePropertyChanged(nameof(Count)); + OnPropertyChanged(nameof(UnusedCount)); + OnPropertyChanged(nameof(Count)); RaiseCollectionChanged(NotifyCollectionChangedAction.Add, item, sortedExtensions.Count - 1); } return item; @@ -149,8 +145,8 @@ internal bool Remove(ExtensionItem item) { int index = sortedExtensions.IndexOf(item); sortedExtensions.RemoveAt(index); unusedExtensions.Add(item.Extension, item); - RaisePropertyChanged(nameof(Count)); - RaisePropertyChanged(nameof(UnusedCount)); + OnPropertyChanged(nameof(Count)); + OnPropertyChanged(nameof(UnusedCount)); RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, item, index); return true; } @@ -168,8 +164,8 @@ internal bool Remove(string extension) { extensions.Remove(extension); int index = sortedExtensions.IndexOf(item); sortedExtensions.RemoveAt(index); - RaisePropertyChanged(nameof(Count)); - RaisePropertyChanged(nameof(UnusedCount)); + OnPropertyChanged(nameof(Count)); + OnPropertyChanged(nameof(UnusedCount)); RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, item, index); return true; } @@ -187,8 +183,8 @@ internal void Clear() { extensions.Clear(); TotalSize = 0; TotalFileCount = 0; - RaisePropertyChanged(nameof(Count)); - RaisePropertyChanged(nameof(UnusedCount)); + OnPropertyChanged(nameof(Count)); + OnPropertyChanged(nameof(UnusedCount)); RaiseCollectionChanged(NotifyCollectionChangedAction.Remove, oldItems, 0); } diff --git a/WinDirStat.Net.Wpf.Base/ObservableCollectionObject.cs b/WinDirStat.Net.Wpf.Base/ObservableCollectionObject.cs index 636b1ed..2ad72c2 100644 --- a/WinDirStat.Net.Wpf.Base/ObservableCollectionObject.cs +++ b/WinDirStat.Net.Wpf.Base/ObservableCollectionObject.cs @@ -1,18 +1,10 @@ using System; using System.Collections; -using System.Collections.Generic; using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; - -namespace WinDirStat.Net { - /// A base class for objects of which the collection must be observable. - public abstract class ObservableCollectionObject : INotifyCollectionChanged { + +namespace WinDirStat.Net { + /// A base class for objects of which the collection must be observable. + public abstract class ObservableCollectionObject : INotifyCollectionChanged { #region Fields diff --git a/WinDirStat.Net.Wpf.Base/ObservableObjectEx.cs b/WinDirStat.Net.Wpf.Base/ObservableObjectEx.cs index e25ddb3..3abcda8 100644 --- a/WinDirStat.Net.Wpf.Base/ObservableObjectEx.cs +++ b/WinDirStat.Net.Wpf.Base/ObservableObjectEx.cs @@ -1,22 +1,18 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using Microsoft.Toolkit.Mvvm.ComponentModel; using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; - -namespace WinDirStat.Net { - /// An observable object with extra raise property changed methods. - public class ObservableObjectEx : ObservableObject { + +namespace WinDirStat.Net { + /// An observable object with extra raise property changed methods. + public class ObservableObjectEx : ObservableObject { /// Raises the property as changed if the condition is true. /// /// The condition for raising the changed event. /// The name of the property. /// True if the property was changed. - protected bool RaisePropertyChangedIf(bool condition, [CallerMemberName] string propertyName = null) { - RaisePropertyChanged(propertyName); + protected bool OnPropertyChangedIf(bool condition, [CallerMemberName] string propertyName = null) { + //FIXME: this never checks the condition... + OnPropertyChanged(propertyName); return condition; } } diff --git a/WinDirStat.Net.Wpf.Base/ObservablePropertyCollectionObject.cs b/WinDirStat.Net.Wpf.Base/ObservablePropertyCollectionObject.cs index 645f28a..dd88e1d 100644 --- a/WinDirStat.Net.Wpf.Base/ObservablePropertyCollectionObject.cs +++ b/WinDirStat.Net.Wpf.Base/ObservablePropertyCollectionObject.cs @@ -1,18 +1,11 @@ -using System; +using Microsoft.Toolkit.Mvvm.ComponentModel; +using System; using System.Collections; -using System.Collections.Generic; using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; - -namespace WinDirStat.Net { - /// A base class for objects of which the collection must be observable. - public abstract class ObservablePropertyCollectionObject : ObservableObject, INotifyCollectionChanged { + +namespace WinDirStat.Net { + /// A base class for objects of which the collection must be observable. + public abstract class ObservablePropertyCollectionObject : ObservableObject, INotifyCollectionChanged { #region Fields diff --git a/WinDirStat.Net.Wpf.Base/ObservableVolatileObject.cs b/WinDirStat.Net.Wpf.Base/ObservableVolatileObject.cs index a858af5..671165f 100644 --- a/WinDirStat.Net.Wpf.Base/ObservableVolatileObject.cs +++ b/WinDirStat.Net.Wpf.Base/ObservableVolatileObject.cs @@ -1,13 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -namespace WinDirStat.Net { - /// An observable object with volatile get and set. - public class ObservableVolatileObject : ObservableObjectEx { +namespace WinDirStat.Net { + /// An observable object with volatile get and set. + public class ObservableVolatileObject : ObservableObjectEx { /// The lock for volatile properties. protected readonly object volatileLock = new object(); @@ -37,7 +33,7 @@ protected bool VolatileSet(ref T field, T newValue, [CallerMemberName] string return false; field = newValue; } - RaisePropertyChanged(propertyName); + OnPropertyChanged(propertyName); return true; } diff --git a/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.DrawChildren.cs b/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.DrawChildren.cs index 15df745..00db92d 100644 --- a/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.DrawChildren.cs +++ b/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.DrawChildren.cs @@ -1,9 +1,5 @@ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using WinDirStat.Net.Structures; #if DOUBLE @@ -12,11 +8,10 @@ using Number = System.Single; #endif -namespace WinDirStat.Net.Rendering { - unsafe partial class TreemapRenderer { +namespace WinDirStat.Net.Rendering { + partial class TreemapRenderer { - private void RecurseDrawGraph(Rgba32Color* bitmap, ITreemapItem item, Rectangle2I rc, - bool isroot, Number[] pSurface, Number h, uint flags) + private void RecurseDrawGraph(Span bitmap, ITreemapItem item, Rectangle2I rc, bool isroot, Number[] pSurface, Number h, uint flags) { Debug.Assert(rc.Width >= 0); Debug.Assert(rc.Height >= 0); @@ -48,7 +43,7 @@ private void RecurseDrawGraph(Rgba32Color* bitmap, ITreemapItem item, Rectangle2 } } - private void DrawChildren(Rgba32Color* bitmap, ITreemapItem parent, Number[] surface, Number h, uint flags) { + private void DrawChildren(Span bitmap, ITreemapItem parent, Number[] surface, Number h, uint flags) { switch (options.Style) { case TreemapStyle.KDirStatStyle: KDirStat_DrawChildren(bitmap, parent, surface, h, flags); @@ -69,7 +64,7 @@ private bool IsCushionShading { get => options.AmbientLight < 1 && options.Height > 0 && options.ScaleFactor > 0; } - private void RenderLeaf(Rgba32Color* bitmap, ITreemapItem item, Number[] surface) { + private void RenderLeaf(Span bitmap, ITreemapItem item, Number[] surface) { Rectangle2I rc = item.Rectangle; if (options.Grid) { @@ -84,7 +79,7 @@ private void RenderLeaf(Rgba32Color* bitmap, ITreemapItem item, Number[] surface RenderRectangle(bitmap, rc, surface, item.Color); } - private void RenderRectangle(Rgba32Color* bitmap, Rectangle2I rc, Number[] surface, Rgba32Color color) { + private void RenderRectangle(Span bitmap, Rectangle2I rc, Number[] surface, Rgba32Color color) { Number brightness = options.Brightness; //color = ColorSpace.SetBrightness(color, PaletteBrightness); @@ -98,7 +93,7 @@ private void RenderRectangle(Rgba32Color* bitmap, Rectangle2I rc, Number[] surfa } } - private void DrawSolidRect(Rgba32Color* bitmap, Rectangle2I rc, Rgba32Color color, Number brightness) { + private void DrawSolidRect(Span bitmap, Rectangle2I rc, Rgba32Color color, Number brightness) { Number factor = brightness / ColorSpace.PaletteBrightness; int red = (int) (color.R * factor); @@ -114,7 +109,7 @@ private void DrawSolidRect(Rgba32Color* bitmap, Rectangle2I rc, Rgba32Color colo } } } - private void DrawCushion(Rgba32Color* bitmap, Rectangle2I rc, Number[] surface, Rgba32Color color, Number brightness) { + private void DrawCushion(Span bitmap, Rectangle2I rc, Number[] surface, Rgba32Color color, Number brightness) { Number Ia = options.AmbientLight; Number Is = 1 - Ia; diff --git a/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.Highlighting.cs b/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.Highlighting.cs index 1a24fd0..d27e6d7 100644 --- a/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.Highlighting.cs +++ b/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.Highlighting.cs @@ -1,14 +1,9 @@ -using System; +using Microsoft.Toolkit.HighPerformance.Buffers; +using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows; -using System.Windows.Media.Imaging; -using TriggersTools.SharpUtils.Collections; +using System.Windows.Media.Imaging; using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Services; using WinDirStat.Net.Structures; #if DOUBLE @@ -17,100 +12,92 @@ using Number = System.Single; #endif -namespace WinDirStat.Net.Rendering { - unsafe partial class TreemapRenderer { - - public void HighlightItems(WriteableBitmap bitmap, Rectangle2I rc, Rgba32Color color, IEnumerable items) { - if (rc.Width <= 0 || rc.Height <= 0) - return; - - renderArea = rc; - - InitPixels(rc, Rgba32Color.Transparent); - - fixed (Rgba32Color* pBitmapBits = pixels) { - - foreach (FileItemBase item in items) - HighlightRectangle(pBitmapBits, item.Rectangle, color); - - IntPtr bitmapBitsPtr = (IntPtr) pBitmapBits; - - ui.Invoke(() => { - bitmap.WritePixels((Int32Rect) rc, bitmapBitsPtr, rc.Width * rc.Height * 4, bitmap.BackBufferStride); - }); - } - } - - public void HighlightExtensions(WriteableBitmap bitmap, Rectangle2I rc, FileItemBase root, Rgba32Color color, string extension) { - if (rc.Width <= 0 || rc.Height <= 0) - return; - - renderArea = rc; - - InitPixels(rc, Rgba32Color.Transparent); - - fixed (Rgba32Color* pBitmapBits = pixels) { - - RecurseHighlightExtensions(pBitmapBits, root, color, extension); - - IntPtr bitmapBitsPtr = (IntPtr) pBitmapBits; - - ui.Invoke(() => { - bitmap.WritePixels((Int32Rect) rc, bitmapBitsPtr, rc.Width * rc.Height * 4, bitmap.BackBufferStride); - }); - } - } - - private void RecurseHighlightExtensions(Rgba32Color* bitmap, FileItemBase parent, Rgba32Color color, string extension) { - List children = parent.Children; - int count = children.Count; - for (int i = 0; i < count; i++) { - FileItemBase child = children[i]; - Rectangle2S rc = child.Rectangle; - if (rc.Width > 0 && rc.Height > 0) { - if (child.IsLeaf) { - if (child.Extension == extension) - HighlightRectangle(bitmap, rc, color); - } - else { - RecurseHighlightExtensions(bitmap, child, color, extension); - } - } - } - } - - private void HighlightRectangle(Rgba32Color* bitmap, Rectangle2I rc, Rgba32Color color) { - if (rc.Width >= 7 && rc.Height >= 7) { - FillRectangle(bitmap, Rectangle2I.FromLTRB(rc.Left, rc.Top, rc.Right, rc.Top + 3), color); - FillRectangle(bitmap, Rectangle2I.FromLTRB(rc.Left, rc.Bottom - 3, rc.Right, rc.Bottom), color); - FillRectangle(bitmap, Rectangle2I.FromLTRB(rc.Left, rc.Top + 3, rc.Left + 3, rc.Bottom - 3), color); - FillRectangle(bitmap, Rectangle2I.FromLTRB(rc.Right - 3, rc.Top + 3, rc.Right, rc.Bottom - 3), color); - } - else if (rc.Width == 1 && rc.Height == 1) { - bitmap[rc.Left + rc.Top * renderArea.Width] = color; - } - else if (rc.Width > 0 && rc.Height > 0) { - FillRectangle(bitmap, rc, color); - } - } - - private void FillRectangle(Rgba32Color* bitmap, Rectangle2I rc, Rgba32Color color) { - int bottom = rc.Bottom; - int right = rc.Right; - if (rc.Width >= rc.Height) { - for (int iy = rc.Top; iy < bottom; iy++) { - for (int ix = rc.Left; ix < right; ix++) { - bitmap[ix + iy * renderArea.Width] = color; - } - } - } - else { - for (int ix = rc.Left; ix < right; ix++) { - for (int iy = rc.Top; iy < bottom; iy++) { - bitmap[ix + iy * renderArea.Width] = color; - } - } - } - } - } +namespace WinDirStat.Net.Rendering { + partial class TreemapRenderer { + unsafe void WritePixelSpan(MemoryOwner pixels, WriteableBitmap bitmap, Rectangle2I rc) { + fixed (Rgba32Color* pBuffer = pixels.Span) { + bitmap.WritePixels((Int32Rect) rc, (IntPtr) pBuffer, rc.Width * rc.Height * sizeof(Rgba32Color), bitmap.BackBufferStride); + } + } + + public void HighlightItems(WriteableBitmap bitmap, Rectangle2I rc, Rgba32Color color, IEnumerable items) { + if (rc.Width <= 0 || rc.Height <= 0) + return; + + renderArea = rc; + + using var pixels = InitPixels(rc, Rgba32Color.Transparent); + + var span = pixels.Span; + foreach (FileItemBase item in items) { + HighlightRectangle(span, item.Rectangle, color); + } + + ui.Invoke(() => WritePixelSpan(pixels, bitmap, rc)); + } + + public void HighlightExtensions(WriteableBitmap bitmap, Rectangle2I rc, FileItemBase root, Rgba32Color color, string extension) { + if (rc.Width <= 0 || rc.Height <= 0) + return; + + renderArea = rc; + + using var pixels = InitPixels(rc, Rgba32Color.Transparent); + RecurseHighlightExtensions(pixels.Span, root, color, extension); + + ui.Invoke(() => WritePixelSpan(pixels, bitmap, rc)); + } + + private void RecurseHighlightExtensions(Span bitmap, FileItemBase parent, Rgba32Color color, string extension) { + List children = parent.Children; + int count = children.Count; + for (int i = 0; i < count; i++) { + FileItemBase child = children[i]; + Rectangle2S rc = child.Rectangle; + if (rc.Width > 0 && rc.Height > 0) { + if (child.IsLeaf) { + if (child.Extension == extension) + HighlightRectangle(bitmap, rc, color); + } + else { + RecurseHighlightExtensions(bitmap, child, color, extension); + } + } + } + } + + private void HighlightRectangle(Span bitmap, Rectangle2I rc, Rgba32Color color) { + if (rc.Width >= 7 && rc.Height >= 7) { + FillRectangle(bitmap, Rectangle2I.FromLTRB(rc.Left, rc.Top, rc.Right, rc.Top + 3), color); + FillRectangle(bitmap, Rectangle2I.FromLTRB(rc.Left, rc.Bottom - 3, rc.Right, rc.Bottom), color); + FillRectangle(bitmap, Rectangle2I.FromLTRB(rc.Left, rc.Top + 3, rc.Left + 3, rc.Bottom - 3), color); + FillRectangle(bitmap, Rectangle2I.FromLTRB(rc.Right - 3, rc.Top + 3, rc.Right, rc.Bottom - 3), color); + } + else if (rc.Width == 1 && rc.Height == 1) { + bitmap[rc.Left + rc.Top * renderArea.Width] = color; + } + else if (rc.Width > 0 && rc.Height > 0) { + FillRectangle(bitmap, rc, color); + } + } + + private void FillRectangle(Span bitmap, Rectangle2I rc, Rgba32Color color) { + int bottom = rc.Bottom; + int right = rc.Right; + if (rc.Width >= rc.Height) { + for (int iy = rc.Top; iy < bottom; iy++) { + for (int ix = rc.Left; ix < right; ix++) { + bitmap[ix + iy * renderArea.Width] = color; + } + } + } + else { + for (int ix = rc.Left; ix < right; ix++) { + for (int iy = rc.Top; iy < bottom; iy++) { + bitmap[ix + iy * renderArea.Width] = color; + } + } + } + } + } } diff --git a/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.KDirStat.cs b/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.KDirStat.cs index a5d5cb1..d575afd 100644 --- a/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.KDirStat.cs +++ b/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.KDirStat.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using WinDirStat.Net.Structures; #if DOUBLE @@ -12,10 +9,10 @@ using Number = System.Single; #endif -namespace WinDirStat.Net.Rendering { - unsafe partial class TreemapRenderer { +namespace WinDirStat.Net.Rendering { + partial class TreemapRenderer { - private void KDirStat_DrawChildren(Rgba32Color* bitmap, ITreemapItem parent, Number[] surface, Number h, uint flags) { + private void KDirStat_DrawChildren(Span bitmap, ITreemapItem parent, Number[] surface, Number h, uint flags) { Debug.Assert(parent.ChildCount > 0); Rectangle2I rc = parent.Rectangle; diff --git a/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.cs b/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.cs index 0c90e1d..b0e66af 100644 --- a/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.cs +++ b/WinDirStat.Net.Wpf.Base/Rendering/TreemapRenderer.cs @@ -1,12 +1,8 @@ -using System; -using System.Collections.Generic; +using Microsoft.Toolkit.HighPerformance.Buffers; +using System; using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows; using System.Windows.Media.Imaging; -using TriggersTools.SharpUtils.Collections; using WinDirStat.Net.Services; using WinDirStat.Net.Structures; @@ -16,162 +12,157 @@ using Number = System.Single; #endif -namespace WinDirStat.Net.Rendering { - /// A service for rendering WinDirStat treemaps. - public unsafe partial class TreemapRenderer { - - #region Fields - - /// The UI service. - private readonly UIService ui; - - /// The last pixel array used for drawing. - private Rgba32Color[] pixels; - - /// The render options for the treemap. - private TreemapOptions options; - /// Calculated light position for the treemap. - private Number lx; - /// Calculated light position for the treemap. - private Number ly; - /// Calculated light position for the treemap. - private Number lz; - /// The render area for the current operation. - private Rectangle2I renderArea; - - #endregion - - #region Constructors - - /// Constructs the . - public TreemapRenderer(UIService ui) { - this.ui = ui; - Options = TreemapOptions.Default; - } - - #endregion - - #region Properties - - /// Gets or sets the treemap options. - public TreemapOptions Options { - get => options; - set { - options = value; - - Number lx = options.LightSourceX; - Number ly = options.LightSourceY; - const Number lz = 10f; - - Number lenght = (Number) Math.Sqrt(lx*lx + ly*ly + lz*lz); - this.lx = lx / lenght; - this.ly = ly / lenght; - this.lz = lz / lenght; - } - } - - #endregion - - private void InitPixels(Rectangle2I rc, Rgba32Color? background = null) { - int pixelCount = rc.Width * rc.Height; - if (pixels == null || pixels.Length != pixelCount) - pixels = new Rgba32Color[rc.Width * rc.Height]; - if (background.HasValue) - pixels.Memset(background.Value); - } - - [Conditional("DEBUG")] - private void RecurseCheckTree(ITreemapItem item) { - if (item.IsLeaf) { - Debug.Assert(item.ChildCount == 0); - } - else { - // TODO: check that children are sorted by size. - long sum = 0; - for (int i = 0; i < item.ChildCount; i++) { - ITreemapItem child = item[i]; - sum += child.Size; - RecurseCheckTree(child); - } - Debug.Assert(sum == item.Size); - } - } - - public void DrawTreemap(WriteableBitmap bitmap, Rectangle2I rc, ITreemapItem root) { - RecurseCheckTree(root); - - Rectangle2I fullRc = rc; - - rc.Width--; - rc.Height--; - - if (rc.Width <= 0 || rc.Height <= 0) - return; - - renderArea = fullRc; - - if (root.Size == 0) - InitPixels(fullRc, Rgba32Color.Black); - else if (options.Grid) - InitPixels(fullRc, options.GridColor); - else - InitPixels(fullRc, new Rgba32Color(160, 160, 160)); - - fixed (Rgba32Color* pBitmapBits = pixels) { - - // Recursively draw the tree graph - if (root.Size > 0) { - Number[] surface = { 0, 0, 0, 0 }; - RecurseDrawGraph(pBitmapBits, root, rc, true, surface, options.Height, 0); - } - - IntPtr bitmapBitsPtr = (IntPtr) pBitmapBits; - - ui.Invoke(() => { - bitmap.WritePixels((Int32Rect) fullRc, bitmapBitsPtr, fullRc.Width * fullRc.Height * 4, bitmap.BackBufferStride); - }); - } - } - - public void DrawColorPreview(WriteableBitmap bitmap, Rectangle2I rc, Rgb24Color color) { - if (rc.Width <= 0 || rc.Height <= 0) - return; - - renderArea = rc; - - // That bitmap in turn will be created from this array - InitPixels(rc); - - fixed (Rgba32Color* pBitmapBits = pixels) { - - Number[] surface = { 0, 0, 0, 0 }; - - AddRidge(rc, surface, options.Height * options.ScaleFactor); - RenderRectangle(pBitmapBits, rc, surface, color); - - IntPtr bitmapBitsPtr = (IntPtr) pBitmapBits; - - ui.Invoke(() => { - bitmap.WritePixels((Int32Rect) rc, bitmapBitsPtr, rc.Width * rc.Height * 4, bitmap.BackBufferStride); - }); - } - } - - public static ITreemapItem FindItemAtPoint(ITreemapItem item, Point2I p) { - if (item.IsLeaf) { - return item; - } - else { - for (int i = 0; i < item.ChildCount; i++) { - ITreemapItem child = item[i]; - Rectangle2I rcChild = child.Rectangle; - - if (rcChild.Contains(p)) - return FindItemAtPoint(child, p); - } - } - - return null; - } - } +namespace WinDirStat.Net.Rendering { + /// A service for rendering WinDirStat treemaps. + public unsafe partial class TreemapRenderer { + + #region Fields + + /// The UI service. + private readonly UIService ui; + + /// The render options for the treemap. + private TreemapOptions options; + /// Calculated light position for the treemap. + private Number lx; + /// Calculated light position for the treemap. + private Number ly; + /// Calculated light position for the treemap. + private Number lz; + /// The render area for the current operation. + private Rectangle2I renderArea; + + #endregion + + #region Constructors + + /// Constructs the . + public TreemapRenderer(UIService ui) { + this.ui = ui; + Options = TreemapOptions.Default; + } + + #endregion + + #region Properties + + /// Gets or sets the treemap options. + public TreemapOptions Options { + get => options; + set { + options = value; + + Number lx = options.LightSourceX; + Number ly = options.LightSourceY; + const Number lz = 10f; + + Number length = (Number) Math.Sqrt(lx * lx + ly * ly + lz * lz); + this.lx = lx / length; + this.ly = ly / length; + this.lz = lz / length; + } + } + + #endregion + + private MemoryOwner InitPixels(Rectangle2I rc, Rgba32Color? background = null) { + int pixelCount = rc.Width * rc.Height; + var pixels = MemoryOwner.Allocate(pixelCount); + if (background.HasValue) { + pixels.Span.Fill(background.Value); + } + return pixels; + } + + [Conditional("DEBUG")] + private void RecurseCheckTree(ITreemapItem item) { + if (item.IsLeaf) { + Debug.Assert(item.ChildCount == 0); + } + else { + // TODO: check that children are sorted by size. + long sum = 0; + for (int i = 0; i < item.ChildCount; i++) { + ITreemapItem child = item[i]; + sum += child.Size; + RecurseCheckTree(child); + } + Debug.Assert(sum == item.Size); + } + } + + public void DrawTreemap(WriteableBitmap bitmap, Rectangle2I rc, ITreemapItem root) { + RecurseCheckTree(root); + + Rectangle2I fullRc = rc; + + rc.Width--; + rc.Height--; + + if (rc.Width <= 0 || rc.Height <= 0) + return; + + renderArea = fullRc; + + MemoryOwner pixels; + if (root.Size == 0) + pixels = InitPixels(fullRc, Rgba32Color.Black); + else if (options.Grid) + pixels = InitPixels(fullRc, options.GridColor); + else + pixels = InitPixels(fullRc, new Rgba32Color(160, 160, 160)); + + using (pixels) { + // Recursively draw the tree graph + if (root.Size > 0) { + Number[] surface = { 0, 0, 0, 0 }; + RecurseDrawGraph(pixels.Span, root, rc, true, surface, options.Height, 0); + } + + ui.Invoke(() => { + fixed (Rgba32Color* pBitmapBits = pixels.Span) { + bitmap.WritePixels((Int32Rect) fullRc, (IntPtr) pBitmapBits, fullRc.Width * fullRc.Height * sizeof(Rgba32Color), bitmap.BackBufferStride); + } + }); + } + } + + public void DrawColorPreview(WriteableBitmap bitmap, Rectangle2I rc, Rgb24Color color) { + if (rc.Width <= 0 || rc.Height <= 0) + return; + + renderArea = rc; + + // That bitmap in turn will be created from this array + using var pixels = InitPixels(rc); + + Number[] surface = { 0, 0, 0, 0 }; + + AddRidge(rc, surface, options.Height * options.ScaleFactor); + RenderRectangle(pixels.Span, rc, surface, color); + + ui.Invoke(() => { + fixed (Rgba32Color* pBitmapBits = pixels.Span) { + bitmap.WritePixels((Int32Rect) rc, (IntPtr) pBitmapBits, rc.Width * rc.Height * sizeof(Rgba32Color), bitmap.BackBufferStride); + } + }); + } + + public static ITreemapItem FindItemAtPoint(ITreemapItem item, Point2I p) { + if (item.IsLeaf) { + return item; + } + else { + for (int i = 0; i < item.ChildCount; i++) { + ITreemapItem child = item[i]; + Rectangle2I rcChild = child.Rectangle; + + if (rcChild.Contains(p)) + return FindItemAtPoint(child, p); + } + } + + return null; + } + } } diff --git a/WinDirStat.Net.Wpf.Base/Services/BitmapFactory.cs b/WinDirStat.Net.Wpf.Base/Services/BitmapFactory.cs index 8c2046e..a5ff3b5 100644 --- a/WinDirStat.Net.Wpf.Base/Services/BitmapFactory.cs +++ b/WinDirStat.Net.Wpf.Base/Services/BitmapFactory.cs @@ -1,22 +1,16 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Reflection; -using System.Text; -using System.Threading.Tasks; using System.Windows; using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; -using WinDirStat.Net.Services; using WinDirStat.Net.Structures; using WinDirStat.Net.Utils; -using WinDirStat.Net.Native; -namespace WinDirStat.Net.Services { - /// An service for creating and loading bitmaps. - public class BitmapFactory { +namespace WinDirStat.Net.Services { + /// An service for creating and loading bitmaps. + public class BitmapFactory { #region Fields @@ -103,12 +97,9 @@ public BitmapSource FromStream(Stream stream) { /// The handle of the icon to load. /// The loaded bitmap. public BitmapSource FromHIcon(IntPtr hIcon) { - return ui.Invoke(() => { - return Imaging.CreateBitmapSourceFromHIcon( - hIcon, - Int32Rect.Empty, - BitmapSizeOptions.FromEmptyOptions()); - }); + var bmpSource = Imaging.CreateBitmapSourceFromHIcon(hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); + bmpSource.Freeze(); + return bmpSource; } #endregion diff --git a/WinDirStat.Net.Wpf.Base/Services/IconCacheService.cs b/WinDirStat.Net.Wpf.Base/Services/IconCacheService.cs index dd351f4..f257c01 100644 --- a/WinDirStat.Net.Wpf.Base/Services/IconCacheService.cs +++ b/WinDirStat.Net.Wpf.Base/Services/IconCacheService.cs @@ -1,390 +1,292 @@ using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Diagnostics; +using System.Collections.Concurrent; using System.IO; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; using System.Windows.Media; using WinDirStat.Net.Model.Extensions; -using WinDirStat.Net.Services; using static WinDirStat.Net.Native.Win32; -namespace WinDirStat.Net.Services { - /// A service for caching file and folder icons. - public class IconCacheService { - - #region Constants - - private const SHFileInfoFlags CacheIconFlags = - SHFileInfoFlags.SysIconIndex | SHFileInfoFlags.SmallIcon; - - private const SHFileInfoFlags CacheFileTypeFlags = CacheIconFlags | - SHFileInfoFlags.UseFileAttributes | SHFileInfoFlags.TypeName; - - private const SHFileInfoFlags CacheSpecialFolderFlags = CacheIconFlags | - SHFileInfoFlags.PIDL; - - private const SHStockIconFlags CacheStockIconFlags = - SHStockIconFlags.SysIconIndex | SHStockIconFlags.Icon | SHStockIconFlags.SmallIcon; - - #endregion - - #region Fields - - /// The default file icon. - private ImageSource fileIcon; - /// The default folder icon. - private ImageSource folderIcon; - /// The default drive icon. - private ImageSource volumeIcon; - /// The default shortcut icon. - private ImageSource shortcutIcon; - - /// The service for performing UI actions such as dispatcher invoking. - private readonly UIService ui; - /// The service for creating and loading bitmaps. - private readonly BitmapFactory bitmapFactory; - private readonly Dictionary cachedIcons; - private readonly Dictionary cachedSpecialFolders; - private readonly Dictionary cachedFileTypes; - private readonly ObservableCollection cachedIconList; - - #endregion - - #region Constructors - - /// Constructs the . - public IconCacheService(UIService ui, - BitmapFactory bitmapFactory) { - this.ui = ui; - this.bitmapFactory = bitmapFactory; - - cachedIcons = new Dictionary(); - cachedSpecialFolders = new Dictionary(); - cachedFileTypes = new Dictionary(); - cachedIconList = new ObservableCollection(); - } - - #endregion - - #region Properties - - /// Gets the number of cached icons. - public int Count => cachedIcons.Count; - - #endregion - - #region Icon Properties - - /// Gets the default file icon. - public ImageSource FileIcon { - get => fileIcon ?? (fileIcon = CacheStockIcon(SHStockIconID.DocNoAssoc)); - } - /// Gets the default folder icon. - public ImageSource FolderIcon { - get => folderIcon ?? (folderIcon = CacheStockIcon(SHStockIconID.Folder)); - } - /// Gets the default drive icon. - public ImageSource VolumeIcon { - get => volumeIcon ?? (volumeIcon = CacheStockIcon(SHStockIconID.DriveFixed)); - } - /// Gets the default shortcut icon. - public ImageSource ShortcutIcon { - get => shortcutIcon ?? (shortcutIcon = CacheStockIcon(SHStockIconID.Link)); - } - - #endregion - - #region Icon Caching - - /// Caches the icon of the specified file. - /// - /// The path of the file. - /// The cached icon on success, otherwise null. - public ImageSource CacheIcon(string path) { - return ui.Invoke(() => CacheIconImpl(path, 0, SHFileInfoFlags.None, out _, out _)); - } - /// Asynchronousy caches the icon of the specified file. - /// - /// The path of the file. - /// The method that returns the icon upon completion. - public void CacheIconAsync(string path, CacheIconCallback callback) { - if (callback == null) throw new ArgumentNullException(nameof(callback)); - ui.BeginInvoke(() => callback(CacheIcon(path)), false); - } - - /// Caches the icon and display name of the specified file. - /// - /// The path of the file. - /// The cached icon and icon on success, otherwise null. - public IconAndName CacheIconAndDisplayName(string path) { - return ui.Invoke(() => { - ImageSource icon = CacheIconImpl(path, 0, SHFileInfoFlags.DisplayName, out string name, out _); - if (icon != null) - return new IconAndName(icon, name); - return null; - }); - } - /// Asynchronousy caches the icon and display name of the specified file. - /// - /// The path of the file. - /// The method that returns the icon and name upon completion. - public void CacheIconAndDisplayNameAsync(string path, CacheIconAndNameCallback callback) { - if (callback == null) throw new ArgumentNullException(nameof(callback)); - ui.BeginInvoke(() => callback(CacheIconAndDisplayName(path)), false); - } - - /// Caches the file type's icon and type name. - /// - /// The extension of the file type. - /// The cached icon and type name on success, otherwise null. - public IconAndName CacheFileType(string extension) { - return ui.Invoke(() => { - if (!cachedFileTypes.TryGetValue(extension, out IconAndName iconName)) { - try { - // Empty extensions will just return the Local Disk instead of a proper file - string extensionPath = extension; - if (extension == ExtensionItem.EmptyExtension) - extensionPath = Guid.NewGuid().ToString(); - ImageSource icon = CacheIconImpl(extensionPath, FileAttributes.Normal, - CacheFileTypeFlags, out _, out string typeName); - if (icon != null) - iconName = new IconAndName(icon, typeName); - cachedFileTypes.Add(extension, iconName); - } - catch { } - } - return iconName; - }); - } - /// Asynchronousy caches the file type's icon and type name. - /// - /// The extension of the file type. - /// The method that returns the icon and type name upon completion. - public void CacheFileTypeAsync(string extension, CacheIconAndNameCallback callback) { - if (callback == null) throw new ArgumentNullException(nameof(callback)); - ui.BeginInvoke(() => callback(CacheFileType(extension)), false); - } - - /// Caches the special folder's icon and display name. - /// - /// The special folder type. - /// The cached icon and name on success, otherwise null. - public IconAndName CacheSpecialFolder(Environment.SpecialFolder folder) { - return ui.Invoke(() => { - if (!cachedSpecialFolders.TryGetValue(folder, out IconAndName iconName)) { - try { - ImageSource icon = CacheSpecialFolderImpl(folder, 0, SHFileInfoFlags.DisplayName, - out string name, out _); - if (icon != null) - iconName = new IconAndName(icon, name); - cachedSpecialFolders.Add(folder, iconName); - } - catch { } - } - return iconName; - }); - } - /// Asynchronousy caches the special folder's icon and display name. - /// - /// The special folder type. - /// The method that returns the icon and name upon completion. - public void CacheSpecialFolderAsync(Environment.SpecialFolder folder, CacheIconAndNameCallback callback) { - if (callback == null) throw new ArgumentNullException(nameof(callback)); - ui.BeginInvoke(() => callback(CacheSpecialFolder(folder)), false); - } - - #endregion - - #region Private Icon Caching - - /// Caches a stock icon. - /// - /// The id of the stock icon. - /// The icon on success, otherwise null. - private ImageSource CacheStockIcon(SHStockIconID id) { - return ui.Invoke(() => CacheStockIconImpl(id, SHStockIconFlags.None)); - } - - #endregion - - #region Cache Implementation - - /// The implementation for caching icons with a path. - /// - /// The file path or extension. - /// The optional file attributes. - /// Get flags for getting the icon. - /// - /// The output display name if is used in . - /// - /// - /// The output type name if is used in . - /// - /// The icon on success, otherwise null. - private ImageSource CacheIconImpl(string path, FileAttributes attributes, SHFileInfoFlags flags, - out string displayName, out string typeName) - { - displayName = null; - typeName = null; - flags |= CacheIconFlags; - - ImageSource icon = null; - SHFileInfo fileInfo = new SHFileInfo(); - IntPtr hImageList = SHGetFileInfo(path, attributes, ref fileInfo, SHFileInfo.CBSize, flags); - try { - if (hImageList == IntPtr.Zero) - return null; - - if (flags.HasFlag(SHFileInfoFlags.DisplayName)) - displayName = fileInfo.szDisplayName; - if (flags.HasFlag(SHFileInfoFlags.TypeName)) - typeName = fileInfo.szTypeName; - - icon = TryAddIconToCache(fileInfo.iIcon, () => ExtractIcon(hImageList, fileInfo.iIcon)); - if (icon != null) - Debug.WriteLine($"Cache[{Count}]: " + path); - else - Debug.WriteLine($"Failed to load icon for \"{path}\"!"); - } - finally { - ImageList_Destroy(hImageList); - } - return icon; - } - - /// The implementation for caching icons with a special folder. - /// - /// The special folder to get the icon of. - /// The optional file attributes. - /// Get flags for getting the icon. - /// - /// The output display name if is used in . - /// - /// - /// The output type name if is used in . - /// - /// The icon on success, otherwise null. - private ImageSource CacheSpecialFolderImpl(Environment.SpecialFolder folder, FileAttributes attributes, - SHFileInfoFlags flags, out string displayName, out string typeName) - { - displayName = null; - typeName = null; - flags |= CacheSpecialFolderFlags; - - IntPtr pidl = IntPtr.Zero; - ImageSource icon = null; - SHFileInfo fileInfo = new SHFileInfo(); - if (SHGetSpecialFolderLocation(IntPtr.Zero, folder, ref pidl)) - return null; - IntPtr hImageList = SHGetFileInfo(pidl, attributes, ref fileInfo, SHFileInfo.CBSize, flags); - try { - if (hImageList == IntPtr.Zero) - return null; - - if (flags.HasFlag(SHFileInfoFlags.DisplayName)) - displayName = fileInfo.szDisplayName; - if (flags.HasFlag(SHFileInfoFlags.TypeName)) - typeName = fileInfo.szTypeName; - - icon = TryAddIconToCache(fileInfo.iIcon, () => ExtractIcon(hImageList, fileInfo.iIcon)); - if (icon != null) - Debug.WriteLine($"Cache[{Count}]: " + pidl); - else - Debug.WriteLine($"Failed to load icon for \"{pidl}\"!"); - } - finally { - ImageList_Destroy(hImageList); - Marshal.FreeCoTaskMem(pidl); - } - return icon; - } - - /// The implementation for caching stock icons. - /// - /// The id of the stock icon. - /// The flags for caching the stock icon. - /// The icon on success, otherwise null. - private ImageSource CacheStockIconImpl(SHStockIconID id, SHStockIconFlags flags) { - flags |= CacheStockIconFlags; - - ImageSource icon = null; - SHStockIconInfo stockInfo = new SHStockIconInfo { - cbSize = SHStockIconInfo.CBSize, - }; - if (SHGetStockIconInfo(id, flags, ref stockInfo)) - return null; - try { - if (!cachedIcons.TryGetValue(stockInfo.iSysIconIndex, out icon)) { - icon = TryAddIconToCache(stockInfo.iSysIconIndex, () => ExtractIcon(stockInfo.hIcon)); - if (icon != null) - Debug.WriteLine($"Cache[{Count}]: " + id); - else - Debug.WriteLine($"Failed to load icon for \"{id}\"!"); - } - } - finally { - DestroyIcon(stockInfo.hIcon); - } - return icon; - } - - #endregion - - #region Add/Extracting - - /// - /// Tries to add the icon to the cache, if it does exist, is called to get - /// the icon. - /// - /// - /// The system index of the icon. - /// The method to extract the icon. - /// The extracted icon on success, otherwise null. - private ImageSource TryAddIconToCache(int systemIndex, Func extract) { - if (!cachedIcons.TryGetValue(systemIndex, out ImageSource icon)) { - try { - icon = extract(); - cachedIcons.Add(systemIndex, icon); - cachedIconList.Add(icon); - } - catch { } - } - return icon; - } - - /// Extracts the icon from the image list. - /// - /// The handle to the image list. - /// The system index of the icon. - /// The extracted icon on success, otherwise null. - private ImageSource ExtractIcon(IntPtr hImageList, int systemIndex) { - IntPtr hIcon = ImageList_GetIcon(hImageList, systemIndex, ImageListDrawFlags.Normal); - try { - return ExtractIcon(hIcon); - } - finally { - if (hIcon != IntPtr.Zero) - DestroyIcon(hIcon); - } - } - - /// Extracts the icon from the handle. - /// - /// The handle to the icon. - /// The extracted icon on success, otherwise null. - protected ImageSource ExtractIcon(IntPtr hIcon) { - return bitmapFactory.FromHIcon(hIcon); - } - - #endregion - } +namespace WinDirStat.Net.Services { + /// A service for caching file and folder icons. + public class IconCacheService { + + #region Constants + + private const SHFileInfoFlags CacheIconFlags = + SHFileInfoFlags.SysIconIndex | SHFileInfoFlags.SmallIcon; + + private const SHFileInfoFlags CacheFileTypeFlags = CacheIconFlags | + SHFileInfoFlags.UseFileAttributes | SHFileInfoFlags.TypeName; + + private const SHFileInfoFlags CacheSpecialFolderFlags = CacheIconFlags | + SHFileInfoFlags.PIDL; + + private const SHStockIconFlags CacheStockIconFlags = + SHStockIconFlags.SysIconIndex | SHStockIconFlags.Icon | SHStockIconFlags.SmallIcon; + + #endregion + + #region Fields + + /// The default file icon. + private ImageSource fileIcon; + /// The default folder icon. + private ImageSource folderIcon; + /// The default drive icon. + private ImageSource volumeIcon; + /// The default shortcut icon. + private ImageSource shortcutIcon; + + /// The service for creating and loading bitmaps. + private readonly BitmapFactory bitmapFactory; + + private readonly ConcurrentDictionary cachedIcons; + private readonly ConcurrentDictionary cachedSpecialFolders; + private readonly ConcurrentDictionary cachedFileTypes; + + #endregion + + #region Constructors + + /// Constructs the . + public IconCacheService(BitmapFactory bitmapFactory) { + this.bitmapFactory = bitmapFactory; + + cachedIcons = new(); + cachedSpecialFolders = new(); + cachedFileTypes = new(); + } + + #endregion + + #region Properties + + /// Gets the number of cached icons. + public int Count => cachedIcons.Count; + + #endregion + + #region Icon Properties + + /// Gets the default file icon. + public ImageSource FileIcon => fileIcon ??= CacheStockIcon(SHStockIconID.DocNoAssoc); + /// Gets the default folder icon. + public ImageSource FolderIcon => folderIcon ??= CacheStockIcon(SHStockIconID.Folder); + /// Gets the default drive icon. + public ImageSource VolumeIcon => volumeIcon ??= CacheStockIcon(SHStockIconID.DriveFixed); + /// Gets the default shortcut icon. + public ImageSource ShortcutIcon => shortcutIcon ??= CacheStockIcon(SHStockIconID.Link); + + #endregion + + #region Icon Caching + + /// Caches the icon of the specified file. + /// + /// The path of the file. + /// The cached icon on success, otherwise null. + public ImageSource CacheIcon(string path) { + return CacheIconImpl(path, 0, SHFileInfoFlags.None, out _, out _); + } + + /// Caches the icon and display name of the specified file. + /// + /// The path of the file. + /// The cached icon and icon on success, otherwise null. + public IconAndName CacheIconAndDisplayName(string path) { + ImageSource icon = CacheIconImpl(path, 0, SHFileInfoFlags.DisplayName, out string name, out _); + return icon != null ? new IconAndName(icon, name) : null; + } + + /// Caches the file type's icon and type name. + /// + /// The extension of the file type. + /// The cached icon and type name on success, otherwise null. + public IconAndName CacheFileType(string extension) { + return cachedFileTypes.GetOrAdd(extension, Create); + + IconAndName Create(string ext) { + // Empty extensions will just return the Local Disk instead of a proper file + var key = ext == ExtensionItem.EmptyExtension ? Guid.NewGuid().ToString() : ext; + var icon = CacheIconImpl(key, FileAttributes.Normal, CacheFileTypeFlags, out _, out string typeName); + return icon != null ? new IconAndName(icon, typeName) : null; + } + } + + /// Caches the special folder's icon and display name. + /// + /// The special folder type. + /// The cached icon and name on success, otherwise null. + public IconAndName CacheSpecialFolder(Environment.SpecialFolder folder) { + return cachedSpecialFolders.GetOrAdd(folder, Create); + + IconAndName Create(Environment.SpecialFolder dir) { + var icon = CacheSpecialFolderImpl(dir, 0, SHFileInfoFlags.DisplayName, out string name, out _); + return icon != null ? new IconAndName(icon, name) : null; + } + } + + #endregion + + #region Private Icon Caching + + /// Caches a stock icon. + /// + /// The id of the stock icon. + /// The icon on success, otherwise null. + private ImageSource CacheStockIcon(SHStockIconID id) { + return CacheStockIconImpl(id, SHStockIconFlags.None); + } + + #endregion + + #region Cache Implementation + + /// The implementation for caching icons with a path. + /// + /// The file path or extension. + /// The optional file attributes. + /// Get flags for getting the icon. + /// + /// The output display name if is used in . + /// + /// + /// The output type name if is used in . + /// + /// The icon on success, otherwise null. + private ImageSource CacheIconImpl(string path, FileAttributes attributes, SHFileInfoFlags flags, out string displayName, out string typeName) { + displayName = null; + typeName = null; + flags |= CacheIconFlags; + + ImageSource icon = null; + SHFileInfo fileInfo = new SHFileInfo(); + IntPtr hImageList = SHGetFileInfo(path, attributes, ref fileInfo, SHFileInfo.CBSize, flags); + try { + if (hImageList == IntPtr.Zero) + return null; + + if (flags.HasFlag(SHFileInfoFlags.DisplayName)) + displayName = fileInfo.szDisplayName; + if (flags.HasFlag(SHFileInfoFlags.TypeName)) + typeName = fileInfo.szTypeName; + + icon = TryAddIconToCache(fileInfo.iIcon, () => ExtractIcon(hImageList, fileInfo.iIcon)); + } + finally { + ImageList_Destroy(hImageList); + } + return icon; + } + + /// The implementation for caching icons with a special folder. + /// + /// The special folder to get the icon of. + /// The optional file attributes. + /// Get flags for getting the icon. + /// + /// The output display name if is used in . + /// + /// + /// The output type name if is used in . + /// + /// The icon on success, otherwise null. + private ImageSource CacheSpecialFolderImpl(Environment.SpecialFolder folder, FileAttributes attributes, SHFileInfoFlags flags, out string displayName, out string typeName) { + displayName = null; + typeName = null; + flags |= CacheSpecialFolderFlags; + + IntPtr pidl = IntPtr.Zero; + if (SHGetSpecialFolderLocation(IntPtr.Zero, folder, ref pidl)) + return null; + + SHFileInfo fileInfo = new SHFileInfo(); + IntPtr hImageList = SHGetFileInfo(pidl, attributes, ref fileInfo, SHFileInfo.CBSize, flags); + try { + if (hImageList == IntPtr.Zero) + return null; + + if (flags.HasFlag(SHFileInfoFlags.DisplayName)) + displayName = fileInfo.szDisplayName; + if (flags.HasFlag(SHFileInfoFlags.TypeName)) + typeName = fileInfo.szTypeName; + + return TryAddIconToCache(fileInfo.iIcon, () => ExtractIcon(hImageList, fileInfo.iIcon)); + } + finally { + ImageList_Destroy(hImageList); + Marshal.FreeCoTaskMem(pidl); + } + } + + /// The implementation for caching stock icons. + /// + /// The id of the stock icon. + /// The flags for caching the stock icon. + /// The icon on success, otherwise null. + private ImageSource CacheStockIconImpl(SHStockIconID id, SHStockIconFlags flags) { + flags |= CacheStockIconFlags; + + SHStockIconInfo stockInfo = new SHStockIconInfo { + cbSize = SHStockIconInfo.CBSize, + }; + + if (SHGetStockIconInfo(id, flags, ref stockInfo)) + return null; + + try { + return cachedIcons.GetOrAdd(stockInfo.iSysIconIndex, + idx => TryAddIconToCache(idx, () => ExtractIcon(stockInfo.hIcon))); + } + finally { + DestroyIcon(stockInfo.hIcon); + } + } + + #endregion + + #region Add/Extracting + + /// + /// Tries to add the icon to the cache, if it does exist, is called to get + /// the icon. + /// + /// + /// The system index of the icon. + /// The method to extract the icon. + /// The extracted icon on success, otherwise null. + private ImageSource TryAddIconToCache(int systemIndex, Func extract) { + return cachedIcons.GetOrAdd(systemIndex, _ => extract()); + } + + /// Extracts the icon from the image list. + /// + /// The handle to the image list. + /// The system index of the icon. + /// The extracted icon on success, otherwise null. + private ImageSource ExtractIcon(IntPtr hImageList, int systemIndex) { + IntPtr hIcon = ImageList_GetIcon(hImageList, systemIndex, ImageListDrawFlags.Normal); + try { + return ExtractIcon(hIcon); + } + finally { + if (hIcon != IntPtr.Zero) + DestroyIcon(hIcon); + } + } + + /// Extracts the icon from the handle. + /// + /// The handle to the icon. + /// The extracted icon on success, otherwise null. + protected ImageSource ExtractIcon(IntPtr hIcon) { + return bitmapFactory.FromHIcon(hIcon); + } + + #endregion + } } diff --git a/WinDirStat.Net.Wpf.Base/Services/Misc/IconCacheStructures.cs b/WinDirStat.Net.Wpf.Base/Services/Misc/IconCacheStructures.cs index 57c5af0..be52d8f 100644 --- a/WinDirStat.Net.Wpf.Base/Services/Misc/IconCacheStructures.cs +++ b/WinDirStat.Net.Wpf.Base/Services/Misc/IconCacheStructures.cs @@ -1,14 +1,10 @@ using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Media; -namespace WinDirStat.Net.Services { - /// How icons are stored and displayed. - [Serializable] +namespace WinDirStat.Net.Services { + /// How icons are stored and displayed. + [Serializable] public enum IconCacheMode : byte { /// Don't show icons. [Description("Don't show icons")] @@ -38,21 +34,7 @@ public enum IconCacheState : byte { } /// A structure containing both a cached icon and name. - public class IconAndName { - /// The returned icon. - public ImageSource Icon { get; } - /// The returned name. - public string Name { get; } - - /// Constructs a new . - /// - /// The icon to use. - /// The name to use. - public IconAndName(ImageSource icon, string name) { - Icon = icon; - Name = name; - } - } + public record class IconAndName(ImageSource Icon, string Name); /// The callback delegate for caching an icon. /// diff --git a/WinDirStat.Net.Wpf.Base/Services/RelayCommandFactory.cs b/WinDirStat.Net.Wpf.Base/Services/RelayCommandFactory.cs index fb6c6b1..b5e2aee 100644 --- a/WinDirStat.Net.Wpf.Base/Services/RelayCommandFactory.cs +++ b/WinDirStat.Net.Wpf.Base/Services/RelayCommandFactory.cs @@ -1,55 +1,46 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.ViewModel.Commands; - -namespace WinDirStat.Net.Services { - /// A service for creating relay commands to be loaded by the view model. - public abstract class RelayCommandFactory { - - #region Create - - /// - /// Creates a new with the specified info and functions. - /// - /// - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - public IRelayCommand Create(Action execute, bool keepTargetAlive = false) { - return Create(execute, null, keepTargetAlive); - } - - /// - /// Creates a new with the specified info and functions. - /// - /// - /// The parameter type of the command. - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - public IRelayCommand Create(Action execute, bool keepTargetAlive = false) { - return Create(execute, null, keepTargetAlive); - } - - #endregion - - #region Create Abstract - - /// - /// Creates a new with the specified info and functions. - /// - /// - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - public abstract IRelayCommand Create(Action execute, Func canExecute, - bool keepTargetAlive = false); +using Microsoft.Toolkit.Mvvm.Input; +using System; + +namespace WinDirStat.Net.Services { + /// A service for creating relay commands to be loaded by the view model. + public abstract class RelayCommandFactory { + + #region Create + + /// + /// Creates a new with the specified info and functions. + /// + /// + /// The abstract information about the command. + /// The execution action. + /// The optional can execute function. + /// The constructed + public IRelayCommand Create(Action execute) => Create(execute, null); + + /// + /// Creates a new with the specified info and functions. + /// + /// + /// The parameter type of the command. + /// The abstract information about the command. + /// The execution action. + /// The optional can execute function. + /// The constructed + public IRelayCommand Create(Action execute) => Create(execute, null); + + #endregion + + #region Create Abstract + + /// + /// Creates a new with the specified info and functions. + /// + /// + /// The abstract information about the command. + /// The execution action. + /// The optional can execute function. + /// The constructed + public abstract IRelayCommand Create(Action execute, Func canExecute); /// /// Creates a new with the specified info and functions. @@ -60,8 +51,7 @@ public abstract IRelayCommand Create(Action execute, Func canExecute, /// The execution action. /// The optional can execute function. /// The constructed - public abstract IRelayCommand Create(Action execute, Func canExecute, - bool keepTargetAlive = false); + public abstract IRelayCommand Create(Action execute, Predicate canExecute); #endregion } diff --git a/WinDirStat.Net.Wpf.Base/Services/ScanningService.Implementation.cs b/WinDirStat.Net.Wpf.Base/Services/ScanningService.Implementation.cs index ac78b6a..0aaf4ba 100644 --- a/WinDirStat.Net.Wpf.Base/Services/ScanningService.Implementation.cs +++ b/WinDirStat.Net.Wpf.Base/Services/ScanningService.Implementation.cs @@ -1,22 +1,17 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Diagnostics; +using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; +using System.Runtime.InteropServices; using System.Threading; -using System.Threading.Tasks; -using GalaSoft.MvvmLight; -using WinDirStat.Net.Model.Extensions; using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Services; -using WinDirStat.Net.Utils; using WinDirStat.Net.Native; -using System.Runtime.InteropServices; +using WinDirStat.Net.Utils; -namespace WinDirStat.Net.Services { - partial class ScanningService { +namespace WinDirStat.Net.Services { + partial class ScanningService { #region Private Classes @@ -182,9 +177,9 @@ private ScanningState CreateState(FolderItem folder) { /// The name of the file. /// The full path of the file. /// True if the file should be skipped. - private bool SkipFile(ScanningState state, string name, string path) { - if (name.Length == 0) - Console.WriteLine("WHAT"); + private bool SkipFile(ScanningState state, string name, string path) { + Debug.Assert(name.Length > 0); + // We still want to see all those delicious files that were thrown away if (name[0] == '$' && !path.StartsWith(state.RecycleBinPath)) return true; diff --git a/WinDirStat.Net.Wpf.Base/Services/ScanningService.cs b/WinDirStat.Net.Wpf.Base/Services/ScanningService.cs index 767188c..e449ade 100644 --- a/WinDirStat.Net.Wpf.Base/Services/ScanningService.cs +++ b/WinDirStat.Net.Wpf.Base/Services/ScanningService.cs @@ -3,890 +3,876 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; -using System.Linq; using System.Threading; -using System.Windows; +using System.Threading.Tasks; using WinDirStat.Net.Model.Drives; using WinDirStat.Net.Model.Extensions; using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Utils; namespace WinDirStat.Net.Services { - /// A service for scanning a path's file tree. - public partial class ScanningService : ObservableVolatileObject { - - #region Protected Classes - - /// A collection of parent folders and files to refresh. - protected class RefreshFiles { - /// The parent folder of the files. - public FolderItem Parent { get; } - /// The files in the parent folder to refresh. - public List Files { get; } - - /// Constructs the . - public RefreshFiles(FolderItem parent) { - Parent = parent; - Files = new List(); - } - - /// Constructs the . - public RefreshFiles(KeyValuePair> pair) { - Parent = pair.Key; - Files = pair.Value; - } - } - - #endregion - - #region Fields - - /// The program settings. - protected readonly SettingsService settings; - /// The OS specific service - protected readonly OSService os; - /// The UI service - protected readonly UIService ui; - - // Scan async - /// The cancellation token source for the asynchronous scan thread. - private CancellationTokenSource cancel; - /// The current asynchronous scan thread. - private Thread scanThread; - /// The lock object for scan thread setup. - private readonly object threadLock = new object(); - /// The lock object exclusively for accessing the resume event. - private readonly object resumeLock = new object(); - /// The timer for validating the file tree during a scan. - private readonly Timer validateTimer; - - // Scan progress - /// The total size that has been scanned so far. - private long totalScannedSize; - /// The total size for all scanned roots. - private long totalSize; - /// The total free space for all scanned roots. - private long totalFreeSpace; - /// True if all scanned roots are drives and thus have a definite used size. - private bool canDisplayProgress; - /// The watch for keeping track of the scan duration. - private readonly Stopwatch scanWatch; - /// A watch that keeps track of the time spent validating. - private readonly Stopwatch validateWatch; - /// True if validation has been requested on the scan thread. - private volatile bool validationRequested; - - // Scan state - /// The current state of the scan. - private ScanState scanState; - /// The current progress state of the scan. - private ScanProgressState progressState; - /// True if a refresh operation is in progress. - private bool isRefreshing; - /// The wait handle for resuming a scan. Set if the scan is not suspended. - private ManualResetEvent resumeEvent = new ManualResetEvent(true); - /// True if the UI refreshing should be supressed due to validation. - private bool suppressRefresh; - - // Scan result - /// The root item of the file tree being scanned. - private RootItem rootItem; - /// The resulting exception from the current scan. - private Exception exceptionResult; - /// Gets the extension item collection that records all encountered extensions. - public ExtensionItems Extensions { get; } - /// Gets the drive item collection that records the current drive list. - public DriveItems Drives { get; } - /// The root paths to scan. - private string[] rootPaths; - /// The files to refresh. - private RefreshFiles[] refreshFiles; - /// The result of the drive select dialog used for scanning. - private DriveSelectResult driveSelectResult; - - // Dispose - /// True if the scanning service has been disposed of. - private volatile bool disposed; - - #endregion - - #region Events - - /// Callbacks for when a scan has ended in any fashion. - public event ScanEventHander Ended; - /// Callbacks for . - private event ScanEventHander Cancelled; - - /// Called when the space settings have changed. - public event EventHandler SpaceChanged; - - #endregion - - #region Constructors - - /// Constructs the . - public ScanningService(SettingsService settings, - OSService os, - UIService ui) - { - this.settings = settings; - this.os = os; - this.ui = ui; - settings.PropertyChanged += OnSettingsPropertyChanged; - Extensions = new ExtensionItems(this, settings); - Drives = new DriveItems(this); - validateTimer = new Timer(OnValidateTick, null, Timeout.Infinite, Timeout.Infinite); - validateWatch = new Stopwatch(); - scanWatch = new Stopwatch(); - validationRequested = false; - } - - #endregion - - #region Event Handlers - - /// Called when the settings' properties have changed. - private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - case nameof(SettingsService.ShowFreeSpace): - case nameof(SettingsService.ShowUnknown): - case nameof(SettingsService.ShowTotalSpace): - bool shouldSet = !IsScanning && !IsRefreshing; - if (shouldSet) - IsRefreshing = true; - RaisePropertyChanged(e.PropertyName); - RaiseSpaceChanged(); - if (shouldSet) - IsRefreshing = false; - break; - case nameof(SettingsService.ScanPriority): - lock (volatileLock) { - if (IsAsync) - scanThread.Priority = settings.ScanPriority; - } - break; - case nameof(SettingsService.ValidateInterval): - // Same thing as performing an interval change - StartValidateTimer(); - break; - } - } - - #endregion - - #region Private Helpers - - /// Stops the validate timer. - private void StopValidateTimer() { - if (!disposed) - validateTimer.Change(Timeout.Infinite, Timeout.Infinite); - } - - /// Starts the validate timer. - private void StartValidateTimer() { - if (!disposed) - validateTimer.Change(settings.ValidateInterval, Timeout.InfiniteTimeSpan); - } - - /// Adds a request for the file tree to be validated. - private void OnValidateTick(object state) { - validationRequested = true; - } - - /// Raises the event. - private void RaiseSpaceChanged() { - SpaceChanged?.Invoke(this, EventArgs.Empty); - } - - /// Throws an exception if a scan is in progress. - [DebuggerStepThrough] - private void ThrowIfScanning() { - if (IsScanning) - throw new InvalidOperationException("Cannot start new scan while one is currently in progress!"); - } - - #endregion - - #region Public Scanning - - /// Begins a synchronous scan of the specified root paths. - public void Scan(DriveSelectResult result) { - if (result == null) - throw new ArgumentNullException(nameof(result)); - ThrowIfScanning(); - lock (threadLock) { - RootPaths = result.GetResultPaths(); - driveSelectResult = result; - ScanPrepare(false); - ScanThread(false, cancel.Token); - } - } - - /// Begins a asynchronous scan of the specified root paths. - public void ScanAsync(DriveSelectResult result) { - if (result == null) - throw new ArgumentNullException(nameof(result)); - ThrowIfScanning(); - lock (threadLock) { - RootPaths = result.GetResultPaths(); - driveSelectResult = result; - ScanPrepare(false); - scanThread = new Thread(() => ScanThread(false, cancel.Token)) { - Priority = settings.ScanPriority, - Name = "File Scan", - }; - scanThread.Start(); - } - } - - /// Closes the current scanned file tree. - /// - /// - /// Waits for the scan to fully close. DO NOT call this on the UI thread. - /// - public void Close(bool waitForClose = false) { - if (IsOpen) { - Cancel(waitForClose); - RootItem = null; - ClosedCleanup(); - ScanState = ScanState.NotStarted; - ProgressState = ScanProgressState.NotStarted; - Extensions.Clear(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - } - } - - /// - /// Closes the current scanned file tree if one exists and runs the callback if needed. - /// - /// - /// The callback to run after close has fininshed. - /// True if the callback is run when no file tree is open. - public void CloseAsync(Action callback, bool runWhenNotOpen = true) { - if (callback == null) - throw new ArgumentNullException(nameof(callback)); - if (IsScanning) { - CancelAsync(() => { - Close(true); - callback(); - }, true); - } - else if (IsOpen || runWhenNotOpen) { - Close(true); - callback(); - } - } - - /// Cancels the current scan if one exists. - /// - /// - /// Waits for the scan to fully complete. DO NOT call this on the UI thread. - /// - public void Cancel(bool waitForCancel = false) { - if (IsScanning && ScanState != ScanState.Cancelling) { - ScanState = ScanState.Cancelling; - CancellationTokenSource cancel = this.cancel; - ProgressState = ScanProgressState.Ending; - cancel.Cancel(); - // Make sure the wait handle resumes if suspended. - // Otherwise cancellation will never be reached. - IsSuspended = false; - while (waitForCancel && IsAsync) - Thread.Sleep(5); - } - } - - /// Cancels the current scan if one exists and runs the callback if needed. - /// - /// The callback to run after cancellation is fininshed. - /// True if the callback is run when no scan is running. - public void CancelAsync(Action callback, bool runWhenNotScanning = true) { - if (callback == null) - throw new ArgumentNullException(nameof(callback)); - CancelAsync((o, e) => callback(), runWhenNotScanning); - } - - /// Cancels the current scan if one exists and runs the callback if needed. - /// - /// The callback to run after cancellation is fininshed. - /// True if the callback is run when no scan is running. - public void CancelAsync(ScanEventHander callback, bool runWhenNotScanning = true) { - if (callback == null) - throw new ArgumentNullException(nameof(callback)); - if (IsScanning) { - if (ScanState != ScanState.Cancelling) { - Cancelled += new ScanEventHander(callback); - Cancel(false); - } - } - else if (runWhenNotScanning) { - callback(this, new ScanEventArgs(scanState, progressState)); - } - } - - #endregion - - #region Scan Prepare/Thread - - /// Prepares the scan before starting. - private void ScanPrepare(bool refreshing) { - lock (threadLock) { - IsSuspended = false; - IsRefreshing = refreshing; - refreshFiles = null; - CanDisplayProgress = false; - validateWatch.Reset(); - scanWatch.Reset(); - ProgressState = ScanProgressState.Starting; - ScanState = ScanState.Scanning; - TotalScannedSize = 0; - TotalSize = 0; - TotalFreeSpace = 0; - if (!refreshing) { - Extensions.Clear(); - RootItem = null; - } - validateWatch.Reset(); - RaisePropertyChanged(nameof(ScanTime)); - scanWatch.Start(); - cancel = new CancellationTokenSource(); - StartValidateTimer(); - } - } - - /// The root method for running the scan. - private void ScanThread(bool useRefreshFiles, CancellationToken token) { - Exception exception = null; - try { - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - if (useRefreshFiles) - Refresh(refreshFiles, token); - else - Scan(rootPaths, token); - RootItem?.FullValidate(); - } - catch (ThreadAbortException ex) { - exception = ex; - } - catch (Exception ex) { - Debug.WriteLine(ex); - exception = ex; - } - finally { - refreshFiles = null; - FinishedCleanup(); - StopValidateTimer(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - ProgressState = ScanProgressState.Ending; - cancel?.Dispose(); - cancel = null; - scanWatch?.Stop(); - scanThread = null; - - if (!disposed) { - RaisePropertyChanged(nameof(ScanTime)); - if (scanState == ScanState.Cancelling) { - // TODO: Should cancel remove all progress made? - //RootItem = null; - ScanState = ScanState.Cancelled; - } - else if (exception == null) { - ScanState = ScanState.Finished; - } - else { - RootItem = null; - ExceptionResult = exception; - ScanState = ScanState.Failed; - } - IsRefreshing = false; - ProgressState = ScanProgressState.Ended; - Ended?.Invoke(this, new ScanEventArgs(scanState, progressState, exception)); - if (scanState == ScanState.Cancelled) { - Cancelled?.Invoke(this, new ScanEventArgs(scanState, progressState, exception)); - Cancelled = null; - } - } - else { - IsRefreshing = false; - ExceptionResult = exception; - ScanState = ScanState.Failed; - } - } - } - - #endregion - - #region Root Space Properties - - /// Gets if free space items should be listed. - public bool ShowFreeSpace => settings.ShowFreeSpace; - /// Gets if unknown items should be listed. - public bool ShowUnknown => settings.ShowUnknown; - /// - /// Gets if free space and unknown items should be listed in the absolute or file root. - /// - public bool ShowTotalSpace => settings.ShowTotalSpace; - - #endregion - - #region Scan Properties - - /*/// Gets the result of the drive select dialog used for scanning. + /// A service for scanning a path's file tree. + public partial class ScanningService : ObservableVolatileObject, IAsyncDisposable { + + #region Protected Classes + + /// A collection of parent folders and files to refresh. + protected class RefreshFiles { + /// The parent folder of the files. + public FolderItem Parent { get; } + /// The files in the parent folder to refresh. + public List Files { get; } + + /// Constructs the . + public RefreshFiles(FolderItem parent) { + Parent = parent; + Files = new List(); + } + + /// Constructs the . + public RefreshFiles(KeyValuePair> pair) { + Parent = pair.Key; + Files = pair.Value; + } + } + + #endregion + + #region Fields + + /// The program settings. + protected readonly SettingsService settings; + /// The OS specific service + protected readonly OSService os; + /// The UI service + protected readonly UIService ui; + + // Scan async + /// The cancellation token source for the asynchronous scan thread. + private CancellationTokenSource cancel; + /// The current asynchronous scan thread. + private Task scanTask; + /// The lock object for scan thread setup. + private readonly object threadLock = new object(); + /// The lock object exclusively for accessing the resume event. + private readonly object resumeLock = new object(); + /// The timer for validating the file tree during a scan. + private readonly Timer validateTimer; + + // Scan progress + /// The total size that has been scanned so far. + private long totalScannedSize; + /// The total size for all scanned roots. + private long totalSize; + /// The total free space for all scanned roots. + private long totalFreeSpace; + /// True if all scanned roots are drives and thus have a definite used size. + private bool canDisplayProgress; + /// The watch for keeping track of the scan duration. + private readonly Stopwatch scanWatch; + /// A watch that keeps track of the time spent validating. + private readonly Stopwatch validateWatch; + /// True if validation has been requested on the scan thread. + private volatile bool validationRequested; + + // Scan state + /// The current state of the scan. + private ScanState scanState; + /// The current progress state of the scan. + private ScanProgressState progressState; + /// True if a refresh operation is in progress. + private bool isRefreshing; + /// The wait handle for resuming a scan. Set if the scan is not suspended. + private ManualResetEvent resumeEvent = new ManualResetEvent(true); + /// True if the UI refreshing should be supressed due to validation. + private bool suppressRefresh; + + // Scan result + /// The root item of the file tree being scanned. + private RootItem rootItem; + /// The resulting exception from the current scan. + private Exception exceptionResult; + /// Gets the extension item collection that records all encountered extensions. + public ExtensionItems Extensions { get; } + /// Gets the drive item collection that records the current drive list. + public DriveItems Drives { get; } + /// The root paths to scan. + private string[] rootPaths; + /// The files to refresh. + private RefreshFiles[] refreshFiles; + /// The result of the drive select dialog used for scanning. + private DriveSelectResult driveSelectResult; + + // Dispose + /// True if the scanning service has been disposed of. + private volatile bool disposed; + + #endregion + + #region Events + + /// Callbacks for when a scan has ended in any fashion. + public event ScanEventHander Ended; + /// Callbacks for . + private event ScanEventHander Cancelled; + + /// Called when the space settings have changed. + public event EventHandler SpaceChanged; + + #endregion + + #region Constructors + + /// Constructs the . + public ScanningService(SettingsService settings, + OSService os, + UIService ui) { + this.settings = settings; + this.os = os; + this.ui = ui; + settings.PropertyChanged += OnSettingsPropertyChanged; + Extensions = new ExtensionItems(this, settings); + Drives = new DriveItems(this); + validateTimer = new Timer(OnValidateTick, null, Timeout.Infinite, Timeout.Infinite); + validateWatch = new Stopwatch(); + scanWatch = new Stopwatch(); + validationRequested = false; + } + + #endregion + + #region Event Handlers + + /// Called when the settings' properties have changed. + private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e) { + switch (e.PropertyName) { + case nameof(SettingsService.ShowFreeSpace): + case nameof(SettingsService.ShowUnknown): + case nameof(SettingsService.ShowTotalSpace): + bool shouldSet = !IsScanning && !IsRefreshing; + if (shouldSet) + IsRefreshing = true; + OnPropertyChanged(e.PropertyName); + RaiseSpaceChanged(); + if (shouldSet) + IsRefreshing = false; + break; + case nameof(SettingsService.ScanPriority): + lock (volatileLock) { + if (IsAsync) + throw new NotImplementedException(); + } + break; + case nameof(SettingsService.ValidateInterval): + // Same thing as performing an interval change + StartValidateTimer(); + break; + } + } + + #endregion + + #region Private Helpers + + /// Stops the validate timer. + private void StopValidateTimer() { + if (!disposed) + validateTimer.Change(Timeout.Infinite, Timeout.Infinite); + } + + /// Starts the validate timer. + private void StartValidateTimer() { + if (!disposed) + validateTimer.Change(settings.ValidateInterval, Timeout.InfiniteTimeSpan); + } + + /// Adds a request for the file tree to be validated. + private void OnValidateTick(object state) { + validationRequested = true; + } + + /// Raises the event. + private void RaiseSpaceChanged() { + SpaceChanged?.Invoke(this, EventArgs.Empty); + } + + /// Throws an exception if a scan is in progress. + [DebuggerStepThrough] + private void ThrowIfScanning() { + if (IsScanning) + throw new InvalidOperationException("Cannot start new scan while one is currently in progress!"); + } + + #endregion + + #region Public Scanning + + /// Begins a synchronous scan of the specified root paths. + public void Scan(DriveSelectResult result) { + if (result == null) + throw new ArgumentNullException(nameof(result)); + ThrowIfScanning(); + lock (threadLock) { + RootPaths = result.GetResultPaths(); + driveSelectResult = result; + ScanPrepare(false); + ScanThread(false, cancel.Token); + } + } + + /// Begins a asynchronous scan of the specified root paths. + public void ScanAsync(DriveSelectResult result) { + if (result == null) + throw new ArgumentNullException(nameof(result)); + ThrowIfScanning(); + lock (threadLock) { + RootPaths = result.GetResultPaths(); + driveSelectResult = result; + ScanPrepare(false); + Debug.Assert(scanTask == null || scanTask.IsCompleted); + scanTask = Task.Run(() => ScanThread(false, cancel.Token)); //{ + } + } + + /// Closes the current scanned file tree. + /// + /// + /// Waits for the scan to fully close. DO NOT call this on the UI thread. + /// + public void Close(bool waitForClose = false) { + if (IsOpen) { + Cancel(waitForClose); + RootItem = null; + ClosedCleanup(); + ScanState = ScanState.NotStarted; + ProgressState = ScanProgressState.NotStarted; + Extensions.Clear(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + } + } + + /// + /// Closes the current scanned file tree if one exists and runs the callback if needed. + /// + /// + /// The callback to run after close has fininshed. + /// True if the callback is run when no file tree is open. + public void CloseAsync(Action callback, bool runWhenNotOpen = true) { + if (callback == null) + throw new ArgumentNullException(nameof(callback)); + if (IsScanning) { + CancelAsync(() => { + Close(true); + callback(); + }, true); + } + else if (IsOpen || runWhenNotOpen) { + Close(true); + callback(); + } + } + + /// Cancels the current scan if one exists. + /// + /// + /// Waits for the scan to fully complete. DO NOT call this on the UI thread. + /// + public void Cancel(bool waitForCancel = false) { + if (IsScanning && ScanState != ScanState.Cancelling) { + ScanState = ScanState.Cancelling; + CancellationTokenSource cancel = this.cancel; + ProgressState = ScanProgressState.Ending; + cancel.Cancel(); + // Make sure the wait handle resumes if suspended. + // Otherwise cancellation will never be reached. + IsSuspended = false; + while (waitForCancel && IsAsync) + Thread.Sleep(5); + } + } + + /// Cancels the current scan if one exists and runs the callback if needed. + /// + /// The callback to run after cancellation is fininshed. + /// True if the callback is run when no scan is running. + public void CancelAsync(Action callback, bool runWhenNotScanning = true) { + if (callback == null) + throw new ArgumentNullException(nameof(callback)); + CancelAsync((o, e) => callback(), runWhenNotScanning); + } + + /// Cancels the current scan if one exists and runs the callback if needed. + /// + /// The callback to run after cancellation is fininshed. + /// True if the callback is run when no scan is running. + public void CancelAsync(ScanEventHander callback, bool runWhenNotScanning = true) { + if (callback == null) + throw new ArgumentNullException(nameof(callback)); + if (IsScanning) { + if (ScanState != ScanState.Cancelling) { + Cancelled += new ScanEventHander(callback); + Cancel(false); + } + } + else if (runWhenNotScanning) { + callback(this, new ScanEventArgs(scanState, progressState)); + } + } + + #endregion + + #region Scan Prepare/Thread + + /// Prepares the scan before starting. + private void ScanPrepare(bool refreshing) { + lock (threadLock) { + IsSuspended = false; + IsRefreshing = refreshing; + refreshFiles = null; + CanDisplayProgress = false; + validateWatch.Reset(); + scanWatch.Reset(); + ProgressState = ScanProgressState.Starting; + ScanState = ScanState.Scanning; + TotalScannedSize = 0; + TotalSize = 0; + TotalFreeSpace = 0; + if (!refreshing) { + Extensions.Clear(); + RootItem = null; + } + validateWatch.Reset(); + OnPropertyChanged(nameof(ScanTime)); + scanWatch.Start(); + cancel = new CancellationTokenSource(); + StartValidateTimer(); + } + } + + /// The root method for running the scan. + private void ScanThread(bool useRefreshFiles, CancellationToken token) { + Exception exception = null; + try { + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + if (useRefreshFiles) + Refresh(refreshFiles, token); + else + Scan(rootPaths, token); + RootItem?.FullValidate(); + } + catch (ThreadAbortException ex) { + exception = ex; + } + catch (Exception ex) { + Debug.WriteLine(ex); + exception = ex; + } + finally { + refreshFiles = null; + FinishedCleanup(); + StopValidateTimer(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + ProgressState = ScanProgressState.Ending; + scanWatch?.Stop(); + + if (!disposed) { + OnPropertyChanged(nameof(ScanTime)); + if (scanState == ScanState.Cancelling) { + // TODO: Should cancel remove all progress made? + //RootItem = null; + ScanState = ScanState.Cancelled; + } + else if (exception == null) { + ScanState = ScanState.Finished; + } + else { + RootItem = null; + ExceptionResult = exception; + ScanState = ScanState.Failed; + } + IsRefreshing = false; + ProgressState = ScanProgressState.Ended; + Ended?.Invoke(this, new ScanEventArgs(scanState, progressState, exception)); + if (scanState == ScanState.Cancelled) { + Cancelled?.Invoke(this, new ScanEventArgs(scanState, progressState, exception)); + Cancelled = null; + } + } + else { + IsRefreshing = false; + ExceptionResult = exception; + ScanState = ScanState.Failed; + } + } + } + + #endregion + + #region Root Space Properties + + /// Gets if free space items should be listed. + public bool ShowFreeSpace => settings.ShowFreeSpace; + /// Gets if unknown items should be listed. + public bool ShowUnknown => settings.ShowUnknown; + /// + /// Gets if free space and unknown items should be listed in the absolute or file root. + /// + public bool ShowTotalSpace => settings.ShowTotalSpace; + + #endregion + + #region Scan Properties + + /*/// Gets the result of the drive select dialog used for scanning. public DriveSelectResult DriveSelectResult { get => driveSelectResult; - set => Set(ref driveSelectResult, value); - }*/ - - /// Gets the root paths to scan. - public string[] RootPaths { - get => rootPaths; - set => Set(ref rootPaths, value); - } - - /// Gets the root item of the scanned/scanning file tree. - public RootItem RootItem { - get => VolatileGet(ref rootItem); - protected set { - lock (volatileLock) { - if (rootItem == value) - return; - // Unhooks the events from the IScanningService - rootItem?.Dispose(); - rootItem = value; - } - RaisePropertyChanged(); - } - } - - /// Gets how long the scan has been going on for. Or how long the scan took. - public TimeSpan ScanTime => scanWatch.Elapsed; - - /// Gets the amount of time taken to validate the file tree while scanning. - public TimeSpan ValidateTime => validateWatch.Elapsed; - - /// Gets the current state of the scan. - public ScanState ScanState { - get => scanState; - set { - bool suspendedChanged = false; - bool scanningChanged = false; - bool scanningNotRefreshingChanged = false; - bool finishedChanged = false; - bool openChanged = false; - lock (volatileLock) { - if (scanState == value) - return; - - bool suspendedBefore = IsSuspended; - bool scanningBefore = IsScanning; - bool scanningNotRefreshingBefore = IsScanningAndNotRefreshing; - bool finishedBefore = IsFinished; - bool openBefore = IsOpen; - - scanState = value; - - suspendedChanged = suspendedBefore != IsSuspended; - scanningChanged = scanningBefore != IsScanning; - scanningNotRefreshingChanged = scanningNotRefreshingBefore != IsScanningAndNotRefreshing; - finishedChanged = finishedBefore != IsFinished; - openChanged = openBefore != IsOpen; - - if (suspendedChanged) { - if (IsSuspended) - scanWatch.Stop(); - else - scanWatch.Start(); - } - } - RaisePropertyChanged(); - RaisePropertyChangedIf(suspendedChanged, nameof(IsSuspended)); - RaisePropertyChangedIf(scanningChanged, nameof(IsScanning)); - RaisePropertyChangedIf(scanningNotRefreshingChanged, nameof(IsScanningAndNotRefreshing)); - RaisePropertyChangedIf(finishedChanged, nameof(IsFinished)); - RaisePropertyChangedIf(openChanged, nameof(IsOpen)); - } - } - /// Gets the current progress state of the scan. - public ScanProgressState ProgressState { - get => VolatileGet(ref progressState); - protected set => VolatileSet(ref progressState, value); - } - - /// Gets if the scanner can guarantee some estimate of scan progress. - public bool CanDisplayProgress { - get => VolatileGet(ref canDisplayProgress); - protected set => VolatileSet(ref canDisplayProgress, value); - } - /// Gets the progress of the scan, or 1 if the scan is ended. - public double Progress { - get { - lock (volatileLock) { - if (canDisplayProgress) { - switch (progressState) { - case ScanProgressState.Started: - return (double) totalScannedSize / (totalSize - totalFreeSpace); - case ScanProgressState.Ending: - case ScanProgressState.Ended: - return 1d; - } - } - return 0d; - } - } - } - /// Gets if the scanner is scanning or cancelling a scan. - public bool IsScanning { - get { - lock (volatileLock) - return scanState == ScanState.Scanning || scanState == ScanState.Cancelling; - } - } - // Todo: We can probably remove this - /// Gets if the scanner is scanning or cancelling a scan, but not refreshing. - public bool IsScanningAndNotRefreshing { - get { - lock (volatileLock) - return (scanState == ScanState.Scanning || scanState == ScanState.Cancelling) && - !isRefreshing; - } - } - /// Gets if the scanner is refreshing. - public bool IsRefreshing { - get => VolatileGet(ref isRefreshing); - protected set => VolatileSet(ref isRefreshing, value); - } - /// Gets if the scanner has a successfully finished scan. - public bool IsFinished { - get => VolatileGet(ref scanState) == ScanState.Finished; - } - /// Gets if a finished or cancelled scanned file tree is open. - public bool IsOpen { - get { - lock (volatileLock) - return scanState == ScanState.Finished || scanState == ScanState.Cancelled; - } - } - /// Gets or sets if the current scan operation is suspended. - public bool IsSuspended { - get { - lock (resumeLock) { - if (!disposed) - return !resumeEvent.WaitOne(0); - } - return false; - } - set { - lock (resumeLock) { - lock (volatileLock) { - //if (!IsScanning) - // throw new InvalidOperationException("Cannot changed suspended state while not scanning!"); - if (IsSuspended == value) - return; - - if (!disposed) { - if (value) - resumeEvent.Reset(); - else - resumeEvent.Set(); - } - } - } - RaisePropertyChanged(); - } - } - /// Gets if an asynchronous scan thread is running. - public bool IsAsync { - get { - lock (volatileLock) - return scanThread != null && scanThread.IsAlive; - } - } - /// Gets if an asynchronous scan thread is running. - public Exception ExceptionResult { - get => VolatileGet(ref exceptionResult); - private set => VolatileSet(ref exceptionResult, value); - } - - /// Gets if the UI refreshing should be supressed due to validation. - public bool SuppressFileTreeRefresh { - get => VolatileGet(ref suppressRefresh); - private set => VolatileSet(ref suppressRefresh, value); - } - - #endregion - - #region IDisposable Implementation - - /// Disposes of the scanning service. - public void Dispose() { - if (!disposed) { - disposed = true; - scanThread?.Abort(); - validateTimer?.Dispose(); - resumeEvent.Dispose(); - } - } - - /// Disposes of the scanning service. - /*protected virtual void Dispose(bool disposing) { - }*/ - - #endregion - - #region Protected Properties - - /// Gets or sets the total size that has been scanned so far. - protected long TotalScannedSize { - get { lock (volatileLock) return totalScannedSize; } - set { lock (volatileLock) totalScannedSize = value; } - } - /// Gets or sets the total size for all scanned roots. - protected long TotalSize { - get { lock (volatileLock) return totalSize; } - set { lock (volatileLock) totalSize = value; } - } - /// Gets or sets the total free space for all scanned roots. - protected long TotalFreeSpace { - get { lock (volatileLock) return totalFreeSpace; } - set { lock (volatileLock) totalFreeSpace = value; } - } - - #endregion - - #region Protected Methods - - /// Checks if the scan operation is suspended and waits until resume if it is. - protected bool AsyncChecks(CancellationToken token) { - if (disposed) - return true; - - if (!resumeEvent.WaitOne(0)) { - StopValidateTimer(); - // Let's validate before suspension so that things are up to date - BasicValidate(); - resumeEvent.WaitOne(); - StartValidateTimer(); - validationRequested = false; - } - else if (validationRequested) { - StopValidateTimer(); - BasicValidate(); - StartValidateTimer(); - validationRequested = false; - } - return token.IsCancellationRequested; - } - - /// Performs a basic validation of the file tree being scanned. - private void BasicValidate() { - if (RootItem != null) { - ui.Invoke(() => { - Stopwatch validateWatch = Stopwatch.StartNew(); - SuppressFileTreeRefresh = true; - RootItem.BasicValidate(); - SuppressFileTreeRefresh = false; - TimeSpan validateTime = validateWatch.Elapsed; - Console.WriteLine($"Took {validateTime.TotalMilliseconds}ms to validate"); - }); - } - } - - #endregion - - #region Drives - - /// Scans and returns all valid drive items. - /// - /// All valid drive items. - public DriveItem[] ScanDrives() { - List drives = new List(); - DriveInfo[] driveInfos = DriveInfo.GetDrives(); - for (int i = 0; i < driveInfos.Length; i++) { - DriveInfo driveInfo = driveInfos[i]; - if (IsDriveValid(driveInfo)) - drives.Add(new DriveItem(driveInfo)); - } - return drives.ToArray(); - } - - /// Scans and returns all valid drive names. - /// - /// All valid drive names. - public string[] ScanDriveNames() { - List paths = new List(); - DriveInfo[] driveInfos = DriveInfo.GetDrives(); - for (int i = 0; i < driveInfos.Length; i++) { - DriveInfo driveInfo = driveInfos[i]; - if (IsDriveValid(driveInfo)) - paths.Add(driveInfo.Name); - } - return paths.ToArray(); - } - - /// Gets if the drive is valid for use. - /// - /// The drive to check. - /// True if the drive is valid. - public bool IsDriveValid(DriveInfo driveInfo) { - return driveInfo.IsReady && - driveInfo.DriveType != DriveType.Unknown && - driveInfo.DriveType != DriveType.NoRootDirectory; - } - - #endregion - - #region Abstract Methods - - /// Runs the scan process. - /// - /// The root paths to scan. - /// The scan cancellation token. - //protected abstract void Scan(string[] rootPaths, CancellationToken token); - - /// Cleanup called as a scan finishes. - //protected abstract void FinishedCleanup(); - /// Cleanup called when a scanned file tree is closed. - //protected abstract void ClosedCleanup(); - - #endregion - - #region File Management - - /// Permanently deletes the file. - /// - /// The path of the file to delete. - /// True if the operation was successful. - public bool DeleteFile(FileItemBase file) { - return DeleteOrRecycleFile(file, false); - } - - /// Sends the file or directory to the recycle bin. - /// - /// The path of the file to delete. - /// True if the operation was successful. - public bool RecycleFile(FileItemBase file) { - return DeleteOrRecycleFile(file, true); - } - - /// Deletes or recycles the file based on the conditional value. - /// - /// The path of the file to delete. - /// True if the file should be recycled. - /// True if the operation was successful. - public bool DeleteOrRecycleFile(FileItemBase file, bool recycle) { - ThrowIfScanning(); - if (!file.IsFileType || file.Type == FileItemType.Volume) - throw new InvalidOperationException("Can only delete files or folders"); - if (os.DeleteOrRecycleFile(file.FullName, recycle)) { - // File was successfully deleted, let's remove it from the file tree - // Set IsRefreshing to trigger any required UI invalidation - IsRefreshing = true; - FolderItem parent = file.Parent; - parent.RemoveItem(file); - parent.UpdwardsFullValidate(); - IsRefreshing = false; - return true; - } - return false; - } - - #endregion - - #region Public Refreshing - - /// Reloads the selected files. - /// - /// The files to reload. - public void RefreshFilesAsync(IEnumerable selectedFiles) { - if (!IsOpen) - throw new InvalidOperationException("No scan is open to refresh!"); - ThrowIfScanning(); - lock (threadLock) { - ScanPrepare(true); - scanThread = new Thread(() => RefreshThread(selectedFiles, cancel.Token)) { - Priority = settings.ScanPriority, - Name = "File Refresh", - }; - - // Measures to ensure garbage collection - //selectedFiles = null; - - scanThread.Start(); - } - } - - private void RefreshThread(IEnumerable selectedFiles, CancellationToken token) { - FileItemBase[] isolatedFiles = FolderItem.IsolateAncestores(selectedFiles); - if (isolatedFiles.Length > 0) { - if (isolatedFiles[0].IsAbsoluteRootType) { - // Just perform a full reload - ScanThread(false, token); - return; - } - - // Group all files into lists for each similar parent - Dictionary> refreshFilesMap = new Dictionary>(); - for (int i = 0; i < isolatedFiles.Length; i++) { - FileItemBase file = isolatedFiles[i]; - FolderItem parent = file.FileParent; - if (!refreshFilesMap.TryGetValue(parent, out List parentFiles)) { - parentFiles = new List(); - refreshFilesMap.Add(parent, parentFiles); - } - parentFiles.Add(file); - } - - // Convert the refresh files to an array - refreshFiles = new RefreshFiles[refreshFilesMap.Count]; - int index = 0; - foreach (var pair in refreshFilesMap) - refreshFiles[index++] = new RefreshFiles(pair); - - // Next remove the files' children from the tree - foreach (RefreshFiles parentFile in refreshFiles) { - FolderItem parent = parentFile.Parent; - FolderItem fileCollection = parent.GetFileCollection(); - int count = parentFile.Files.Count; - for (int i = 0; i < count; i++) { - if (parentFile.Files[i] is FolderItem folder) - folder.ClearItems(); - } - } - - // Measures to ensure garbage collection - selectedFiles = null; - isolatedFiles = null; - refreshFilesMap = null; - - if (AsyncChecks(token)) - return; - - ScanThread(true, token); - } - } - - /// Reloads the scanned file tree from the beginning. - public void ReloadAsync() { - if (!IsOpen) - throw new InvalidOperationException("No scan is open to reload!"); - ThrowIfScanning(); - lock (threadLock) { - ScanPrepare(true); - rootPaths = driveSelectResult.GetResultPaths(); - scanThread = new Thread(() => ScanThread(false, cancel.Token)) { - Priority = settings.ScanPriority, - Name = "File Reload", - }; - scanThread.Start(); - } - } - - #endregion - } + set => SetProperty(ref driveSelectResult, value); + }*/ + + /// Gets the root paths to scan. + public string[] RootPaths { + get => rootPaths; + set => SetProperty(ref rootPaths, value); + } + + /// Gets the root item of the scanned/scanning file tree. + public RootItem RootItem { + get => VolatileGet(ref rootItem); + protected set { + lock (volatileLock) { + if (rootItem == value) + return; + // Unhooks the events from the IScanningService + rootItem?.Dispose(); + rootItem = value; + } + OnPropertyChanged(); + } + } + + /// Gets how long the scan has been going on for. Or how long the scan took. + public TimeSpan ScanTime => scanWatch.Elapsed; + + /// Gets the amount of time taken to validate the file tree while scanning. + public TimeSpan ValidateTime => validateWatch.Elapsed; + + /// Gets the current state of the scan. + public ScanState ScanState { + get => scanState; + set { + bool suspendedChanged = false; + bool scanningChanged = false; + bool scanningNotRefreshingChanged = false; + bool finishedChanged = false; + bool openChanged = false; + lock (volatileLock) { + if (scanState == value) + return; + + bool suspendedBefore = IsSuspended; + bool scanningBefore = IsScanning; + bool scanningNotRefreshingBefore = IsScanningAndNotRefreshing; + bool finishedBefore = IsFinished; + bool openBefore = IsOpen; + + scanState = value; + + suspendedChanged = suspendedBefore != IsSuspended; + scanningChanged = scanningBefore != IsScanning; + scanningNotRefreshingChanged = scanningNotRefreshingBefore != IsScanningAndNotRefreshing; + finishedChanged = finishedBefore != IsFinished; + openChanged = openBefore != IsOpen; + + if (suspendedChanged) { + if (IsSuspended) + scanWatch.Stop(); + else + scanWatch.Start(); + } + } + OnPropertyChanged(); + OnPropertyChangedIf(suspendedChanged, nameof(IsSuspended)); + OnPropertyChangedIf(scanningChanged, nameof(IsScanning)); + OnPropertyChangedIf(scanningNotRefreshingChanged, nameof(IsScanningAndNotRefreshing)); + OnPropertyChangedIf(finishedChanged, nameof(IsFinished)); + OnPropertyChangedIf(openChanged, nameof(IsOpen)); + } + } + /// Gets the current progress state of the scan. + public ScanProgressState ProgressState { + get => VolatileGet(ref progressState); + protected set => VolatileSet(ref progressState, value); + } + + /// Gets if the scanner can guarantee some estimate of scan progress. + public bool CanDisplayProgress { + get => VolatileGet(ref canDisplayProgress); + protected set => VolatileSet(ref canDisplayProgress, value); + } + /// Gets the progress of the scan, or 1 if the scan is ended. + public double Progress { + get { + lock (volatileLock) { + if (canDisplayProgress) { + switch (progressState) { + case ScanProgressState.Started: + return (double) totalScannedSize / (totalSize - totalFreeSpace); + case ScanProgressState.Ending: + case ScanProgressState.Ended: + return 1d; + } + } + return 0d; + } + } + } + /// Gets if the scanner is scanning or cancelling a scan. + public bool IsScanning { + get { + lock (volatileLock) + return scanState == ScanState.Scanning || scanState == ScanState.Cancelling; + } + } + // Todo: We can probably remove this + /// Gets if the scanner is scanning or cancelling a scan, but not refreshing. + public bool IsScanningAndNotRefreshing { + get { + lock (volatileLock) + return (scanState == ScanState.Scanning || scanState == ScanState.Cancelling) && + !isRefreshing; + } + } + /// Gets if the scanner is refreshing. + public bool IsRefreshing { + get => VolatileGet(ref isRefreshing); + protected set => VolatileSet(ref isRefreshing, value); + } + /// Gets if the scanner has a successfully finished scan. + public bool IsFinished { + get => VolatileGet(ref scanState) == ScanState.Finished; + } + /// Gets if a finished or cancelled scanned file tree is open. + public bool IsOpen { + get { + lock (volatileLock) + return scanState == ScanState.Finished || scanState == ScanState.Cancelled; + } + } + /// Gets or sets if the current scan operation is suspended. + public bool IsSuspended { + get { + lock (resumeLock) { + if (!disposed) + return !resumeEvent.WaitOne(0); + } + return false; + } + set { + lock (resumeLock) { + lock (volatileLock) { + //if (!IsScanning) + // throw new InvalidOperationException("Cannot changed suspended state while not scanning!"); + if (IsSuspended == value) + return; + + if (!disposed) { + if (value) + resumeEvent.Reset(); + else + resumeEvent.Set(); + } + } + } + OnPropertyChanged(); + } + } + /// Gets if an asynchronous scan thread is running. + public bool IsAsync { + get { + lock (volatileLock) + return scanTask != null && !scanTask.IsCompleted; + } + } + /// Gets if an asynchronous scan thread is running. + public Exception ExceptionResult { + get => VolatileGet(ref exceptionResult); + private set => VolatileSet(ref exceptionResult, value); + } + + /// Gets if the UI refreshing should be supressed due to validation. + public bool SuppressFileTreeRefresh { + get => VolatileGet(ref suppressRefresh); + private set => VolatileSet(ref suppressRefresh, value); + } + + #endregion + + #region IDisposable Implementation + + /// Disposes of the scanning service. + public async ValueTask DisposeAsync() { + if (!disposed) { + disposed = true; + + using (scanTask) + using (cancel) + using (validateTimer) + using (resumeEvent) { + cancel?.Cancel(); + await (scanTask ?? Task.CompletedTask); + } + } + } + + /// Disposes of the scanning service. + /*protected virtual void Dispose(bool disposing) { + }*/ + + #endregion + + #region Protected Properties + + /// Gets or sets the total size that has been scanned so far. + protected long TotalScannedSize { + get { lock (volatileLock) return totalScannedSize; } + set { lock (volatileLock) totalScannedSize = value; } + } + /// Gets or sets the total size for all scanned roots. + protected long TotalSize { + get { lock (volatileLock) return totalSize; } + set { lock (volatileLock) totalSize = value; } + } + /// Gets or sets the total free space for all scanned roots. + protected long TotalFreeSpace { + get { lock (volatileLock) return totalFreeSpace; } + set { lock (volatileLock) totalFreeSpace = value; } + } + + #endregion + + #region Protected Methods + + /// Checks if the scan operation is suspended and waits until resume if it is. + protected bool AsyncChecks(CancellationToken token) { + if (disposed) + return true; + + if (!resumeEvent.WaitOne(0)) { + StopValidateTimer(); + // Let's validate before suspension so that things are up to date + BasicValidate(); + resumeEvent.WaitOne(); + StartValidateTimer(); + validationRequested = false; + } + else if (validationRequested) { + StopValidateTimer(); + BasicValidate(); + StartValidateTimer(); + validationRequested = false; + } + return token.IsCancellationRequested; + } + + /// Performs a basic validation of the file tree being scanned. + private void BasicValidate() { + if (RootItem != null) { + ui.Invoke(() => { + Stopwatch validateWatch = Stopwatch.StartNew(); + SuppressFileTreeRefresh = true; + RootItem.BasicValidate(); + SuppressFileTreeRefresh = false; + TimeSpan validateTime = validateWatch.Elapsed; + Debug.WriteLine($"Took {validateTime.TotalMilliseconds}ms to validate"); + }); + } + } + + #endregion + + #region Drives + + /// Scans and returns all valid drive items. + /// + /// All valid drive items. + public DriveItem[] ScanDrives() { + List drives = new List(); + DriveInfo[] driveInfos = DriveInfo.GetDrives(); + for (int i = 0; i < driveInfos.Length; i++) { + DriveInfo driveInfo = driveInfos[i]; + if (IsDriveValid(driveInfo)) + drives.Add(new DriveItem(driveInfo)); + } + return drives.ToArray(); + } + + /// Scans and returns all valid drive names. + /// + /// All valid drive names. + public string[] ScanDriveNames() { + List paths = new List(); + DriveInfo[] driveInfos = DriveInfo.GetDrives(); + for (int i = 0; i < driveInfos.Length; i++) { + DriveInfo driveInfo = driveInfos[i]; + if (IsDriveValid(driveInfo)) + paths.Add(driveInfo.Name); + } + return paths.ToArray(); + } + + /// Gets if the drive is valid for use. + /// + /// The drive to check. + /// True if the drive is valid. + public bool IsDriveValid(DriveInfo driveInfo) { + return driveInfo.IsReady && + driveInfo.DriveType != DriveType.Unknown && + driveInfo.DriveType != DriveType.NoRootDirectory; + } + + #endregion + + #region Abstract Methods + + /// Runs the scan process. + /// + /// The root paths to scan. + /// The scan cancellation token. + //protected abstract void Scan(string[] rootPaths, CancellationToken token); + + /// Cleanup called as a scan finishes. + //protected abstract void FinishedCleanup(); + /// Cleanup called when a scanned file tree is closed. + //protected abstract void ClosedCleanup(); + + #endregion + + #region File Management + + /// Permanently deletes the file. + /// + /// The path of the file to delete. + /// True if the operation was successful. + public bool DeleteFile(FileItemBase file) { + return DeleteOrRecycleFile(file, false); + } + + /// Sends the file or directory to the recycle bin. + /// + /// The path of the file to delete. + /// True if the operation was successful. + public bool RecycleFile(FileItemBase file) { + return DeleteOrRecycleFile(file, true); + } + + /// Deletes or recycles the file based on the conditional value. + /// + /// The path of the file to delete. + /// True if the file should be recycled. + /// True if the operation was successful. + public bool DeleteOrRecycleFile(FileItemBase file, bool recycle) { + ThrowIfScanning(); + if (!file.IsFileType || file.Type == FileItemType.Volume) + throw new InvalidOperationException("Can only delete files or folders"); + if (os.DeleteOrRecycleFile(file.FullName, recycle)) { + // File was successfully deleted, let's remove it from the file tree + // Set IsRefreshing to trigger any required UI invalidation + IsRefreshing = true; + FolderItem parent = file.Parent; + parent.RemoveItem(file); + parent.UpdwardsFullValidate(); + IsRefreshing = false; + return true; + } + return false; + } + + #endregion + + #region Public Refreshing + + /// Reloads the selected files. + /// + /// The files to reload. + public void RefreshFilesAsync(IEnumerable selectedFiles) { + if (!IsOpen) + throw new InvalidOperationException("No scan is open to refresh!"); + ThrowIfScanning(); + lock (threadLock) { + ScanPrepare(true); + Debug.Assert(scanTask == null); + scanTask = Task.Run(() => RefreshThread(selectedFiles, cancel.Token)); + } + } + + private void RefreshThread(IEnumerable selectedFiles, CancellationToken token) { + FileItemBase[] isolatedFiles = FolderItem.IsolateAncestores(selectedFiles); + if (isolatedFiles.Length > 0) { + if (isolatedFiles[0].IsAbsoluteRootType) { + // Just perform a full reload + ScanThread(false, token); + return; + } + + // Group all files into lists for each similar parent + Dictionary> refreshFilesMap = new Dictionary>(); + for (int i = 0; i < isolatedFiles.Length; i++) { + FileItemBase file = isolatedFiles[i]; + FolderItem parent = file.FileParent; + if (!refreshFilesMap.TryGetValue(parent, out List parentFiles)) { + parentFiles = new List(); + refreshFilesMap.Add(parent, parentFiles); + } + parentFiles.Add(file); + } + + // Convert the refresh files to an array + refreshFiles = new RefreshFiles[refreshFilesMap.Count]; + int index = 0; + foreach (var pair in refreshFilesMap) + refreshFiles[index++] = new RefreshFiles(pair); + + // Next remove the files' children from the tree + foreach (RefreshFiles parentFile in refreshFiles) { + FolderItem parent = parentFile.Parent; + FolderItem fileCollection = parent.GetFileCollection(); + int count = parentFile.Files.Count; + for (int i = 0; i < count; i++) { + if (parentFile.Files[i] is FolderItem folder) + folder.ClearItems(); + } + } + + // Measures to ensure garbage collection + selectedFiles = null; + isolatedFiles = null; + refreshFilesMap = null; + + if (AsyncChecks(token)) + return; + + ScanThread(true, token); + } + } + + /// Reloads the scanned file tree from the beginning. + public void ReloadAsync() { + if (!IsOpen) + throw new InvalidOperationException("No scan is open to reload!"); + ThrowIfScanning(); + lock (threadLock) { + ScanPrepare(true); + rootPaths = driveSelectResult.GetResultPaths(); + Debug.Assert(scanTask == null); + scanTask = Task.Run(() => ScanThread(false, cancel.Token)); + } + } + + #endregion + } } diff --git a/WinDirStat.Net.Wpf.Base/Services/SettingsService.cs b/WinDirStat.Net.Wpf.Base/Services/SettingsService.cs index 20bb9e9..7536e6f 100644 --- a/WinDirStat.Net.Wpf.Base/Services/SettingsService.cs +++ b/WinDirStat.Net.Wpf.Base/Services/SettingsService.cs @@ -1,21 +1,17 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Text; using System.Threading; -using System.Threading.Tasks; using System.Windows.Media; using System.Windows.Media.Imaging; -using GalaSoft.MvvmLight; using WinDirStat.Net.Model.Drives; using WinDirStat.Net.Rendering; using WinDirStat.Net.Structures; -namespace WinDirStat.Net.Services { - /// The service for containing all program settings. - public partial class SettingsService : ObservableObjectEx { +namespace WinDirStat.Net.Services { + /// The service for containing all program settings. + public partial class SettingsService : ObservableObjectEx { #region Fields @@ -104,7 +100,7 @@ public SettingsService(UIService ui, /// Gets or sets the default mode for selecting paths to scan. public DriveSelectMode DriveSelectMode { get => driveSelectMode; - set => Set(ref driveSelectMode, value); + set => SetProperty(ref driveSelectMode, value); } /// Gets or sets the selected drives from the individual list. @@ -112,15 +108,15 @@ public string[] SelectedDrives { get => selectedDrives; set { if (value == null || value.Any(s => string.IsNullOrEmpty(s))) - throw new ArgumentNullException(nameof(SelectedDrives)); - Set(ref selectedDrives, value); + throw new ArgumentNullException(nameof(SelectedDrives)); + SetProperty(ref selectedDrives, value); } } /// Gets or sets the selected folder path. public string SelectedFolderPath { get => selectedFolderPath; - set => Set(ref selectedFolderPath, value); + set => SetProperty(ref selectedFolderPath, value); } #endregion @@ -130,31 +126,31 @@ public string SelectedFolderPath { /// Gets or sets the thread priority for scanning the file tree. public ThreadPriority ScanPriority { get => scanPriority; - set => Set(ref scanPriority, value); + set => SetProperty(ref scanPriority, value); } /// Gets or sets the thread priority for rendering the treemap. public ThreadPriority RenderPriority { get => renderPriority; - set => Set(ref renderPriority, value); + set => SetProperty(ref renderPriority, value); } /// Gets or sets how often the RAM Usage is updated. public TimeSpan RAMInterval { get => ramInterval; - set => Set(ref ramInterval, value); + set => SetProperty(ref ramInterval, value); } /// Gets or sets how often the scan status is updated. public TimeSpan StatusInterval { get => statusInterval; - set => Set(ref statusInterval, value); + set => SetProperty(ref statusInterval, value); } /// Gets or sets how often the scanned file tree is updated in the UI. public TimeSpan ValidateInterval { get => validateInterval; - set => Set(ref validateInterval, value); + set => SetProperty(ref validateInterval, value); } #endregion @@ -164,13 +160,13 @@ public TimeSpan ValidateInterval { /// Gets or sets if free space items are displayed for drives. public bool ShowFreeSpace { get => showFreeSpace; - set => Set(ref showFreeSpace, value); + set => SetProperty(ref showFreeSpace, value); } /// Gets or sets if unknown space items are displayed for drives. public bool ShowUnknown { get => showUnknown; - set => Set(ref showUnknown, value); + set => SetProperty(ref showUnknown, value); } /// @@ -179,7 +175,7 @@ public bool ShowUnknown { /// public bool ShowTotalSpace { get => showTotalSpace; - set => Set(ref showTotalSpace, value); + set => SetProperty(ref showTotalSpace, value); } #endregion @@ -189,31 +185,31 @@ public bool ShowTotalSpace { /// Gets or sets if the file types list should be shown. public bool ShowFileTypes { get => showFileTypes; - set => Set(ref showFileTypes, value); + set => SetProperty(ref showFileTypes, value); } /// Gets or sets if the treemap should be shown. public bool ShowTreemap { get => showTreemap; - set => Set(ref showTreemap, value); + set => SetProperty(ref showTreemap, value); } /// Gets or sets if the tool bar should be shown. public bool ShowToolBar { get => showToolBar; - set => Set(ref showToolBar, value); + set => SetProperty(ref showToolBar, value); } /// Gets or sets if the status bar should be shown. public bool ShowStatusBar { get => showStatusBar; - set => Set(ref showStatusBar, value); + set => SetProperty(ref showStatusBar, value); } /// Gets or sets the setting for how icons are cached for file tree items. public IconCacheMode IconCacheMode { get => iconCacheMode; - set => Set(ref iconCacheMode, value); + set => SetProperty(ref iconCacheMode, value); } #endregion @@ -226,14 +222,14 @@ public TreemapOptions TreemapOptions { set { treemapOptions = value; UpdateFilePalettePreviews(); - RaisePropertyChanged(); + OnPropertyChanged(); } } /// Gets or sets the treemap highlight color. public Rgba32Color HighlightColor { get => highlightColor; - set => Set(ref highlightColor, value); + set => SetProperty(ref highlightColor, value); } /// Gets the array of the prepared (equalized) file palette colors. @@ -274,8 +270,8 @@ public void SetFilePalette(IEnumerable filePalette) { this.filePalette = filePalette.ToArray(); this.equalizedFilePalette = ColorSpace.EqualizeColors(filePalette); UpdateFilePalettePreviews(); - RaisePropertyChanged(nameof(FilePalette)); - RaisePropertyChanged(nameof(OriginalFilePalette)); + OnPropertyChanged(nameof(FilePalette)); + OnPropertyChanged(nameof(OriginalFilePalette)); } #endregion @@ -300,7 +296,7 @@ public Rgb24Color GetSubtreePaletteColor(int level) { /// The new collection of colors to use. public void SetSubtreePalette(IEnumerable subtreePalette) { this.subtreePalette = subtreePalette.ToArray(); - RaisePropertyChanged(nameof(SubtreePalette)); + OnPropertyChanged(nameof(SubtreePalette)); } #endregion @@ -316,7 +312,7 @@ protected void UpdateFilePalettePreviews() { for (int i = 0; i < filePalettePreviews.Length; i++) { DrawFilePalettePreview(ref filePalettePreviews[i], equalizedFilePalette[i]); } - RaisePropertyChanged(nameof(FilePalettePreviews)); + OnPropertyChanged(nameof(FilePalettePreviews)); } /// Draws a single file palette preview. diff --git a/WinDirStat.Net.Wpf.Base/Services/UIService.cs b/WinDirStat.Net.Wpf.Base/Services/UIService.cs index 5547c6f..ea4b9a2 100644 --- a/WinDirStat.Net.Wpf.Base/Services/UIService.cs +++ b/WinDirStat.Net.Wpf.Base/Services/UIService.cs @@ -1,198 +1,173 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; using System.Windows; using System.Windows.Threading; -using WinDirStat.Net.Services; -namespace WinDirStat.Net.Services { - /// A service for UI interactions. - public class UIService { - - #region Fields - - /// The UI dispatcher. - public Dispatcher Dispatcher { get; } - - #endregion - - #region Constructors - - /// Constructs the . - public UIService() { - Dispatcher = Application.Current.Dispatcher; - } - - #endregion - - #region Dispatcher - - /// Invokes the action on the UI thread. - /// - /// The action to invoke. - public void Invoke(Action action) { - try { - Dispatcher.Invoke(action); - } - catch (TaskCanceledException) { } - } - - /// Invokes the function on the UI thread. - /// - /// The function to invoke. - /// The result of the function. - public T Invoke(Func action) { - return Dispatcher.Invoke(action); - } - - /// Invokes the action asynchronously on the UI thread. - /// - /// The action to invoke. - /// True if the action should use normal priority. - public void BeginInvoke(Action action, bool normalPriority) { - Dispatcher.BeginInvoke(action, GetPriority(normalPriority)); - } - - /// Checks if the current thread is the UI thread. - /// - /// True if the current thread is the UI thread. - public bool CheckAccess() { - return Dispatcher.CheckAccess(); - } - - #endregion - - #region Shutdown - - /// Shuts down the application. - public void Shutdown() { - Dispatcher.InvokeShutdown(); - } - - public event EventHandler ShuttingDown { - add => Dispatcher.ShutdownStarted += value; - remove => Dispatcher.ShutdownStarted -= value; - } - - #endregion - - #region Create Timer - - /// Creates a new stopped UI timer. - /// - /// The interval for the timer. - /// True if the timer runs at normal priority. - /// The callback on the timer tick event. - /// The newly created timer. - public UITimer CreateTimer(TimeSpan interval, bool normalPriority, Action callback) { - return new UITimer(interval, normalPriority, callback, false); - } - /// Creates a new running UI timer. - /// - /// The interval for the timer. - /// True if the timer runs at normal priority. - /// The callback on the timer tick event. - /// The newly created timer. - public UITimer StartTimer(TimeSpan interval, bool normalPriority, Action callback) { - return new UITimer(interval, normalPriority, callback, true); - } - - #endregion - - public static DispatcherPriority GetPriority(bool normalPriority) { - return (normalPriority ? DispatcherPriority.Normal : DispatcherPriority.Background); - } - } - - /// A timer that runs its callbacks on the UI thread. - public class UITimer { - - #region Fields - - /// The wrapped dispatcher timer. - private readonly DispatcherTimer dispatcherTimer; - /// The event handler callback constructed from the action. - private EventHandler handlerCallback; - /// The action used for the callback. - private Action callback; - - #endregion - - #region Constructors - - /// Constructs the see . - /// - /// The interval for the timer. - /// True if the timer runs at normal priority. - /// The callback on the timer tick event. - /// True if the timer should start running. - public UITimer(TimeSpan interval, bool normalPriority, Action callback, bool start) { - this.callback = callback ?? throw new ArgumentNullException(nameof(callback)); - handlerCallback = (o, s) => callback(); - dispatcherTimer = new DispatcherTimer( - interval, - UIService.GetPriority(normalPriority), - handlerCallback, - Application.Current.Dispatcher); - if (!start) - dispatcherTimer.Stop(); - } - - #endregion - - #region Properties - - /// Gets or sets the callback method for the timer. - public Action Callback { - get => callback; - set { - if (callback != value) { - callback = value ?? throw new ArgumentNullException(nameof(Callback)); - dispatcherTimer.Tick -= handlerCallback; - handlerCallback = (o, s) => callback(); - dispatcherTimer.Tick += handlerCallback; - } - } - } - /// Gets or sets the interval for the timer. - public TimeSpan Interval { - get => dispatcherTimer.Interval; - set => dispatcherTimer.Interval = value; - } - /// Gets or sets if the timer is running. - public bool IsRunning { - get => dispatcherTimer.IsEnabled; - set { - if (dispatcherTimer.IsEnabled != value) { - if (value) - dispatcherTimer.Start(); - else - dispatcherTimer.Stop(); - } - } - } - - #endregion - - #region Start/Stop - - /// Starts the timer. - public void Start() { - dispatcherTimer.Start(); - } - /// Stops the timer. - public void Stop() { - dispatcherTimer.Stop(); - } - /// Restarts the timer. - public void Restart() { - dispatcherTimer.Stop(); - dispatcherTimer.Start(); - } - - #endregion - } +namespace WinDirStat.Net.Services { + /// A service for UI interactions. + public class UIService { + + #region Fields + + /// The UI dispatcher. + public Dispatcher Dispatcher { get; } + + #endregion + + #region Constructors + + /// Constructs the . + public UIService() { + Dispatcher = Application.Current.Dispatcher; + } + + #endregion + + #region Dispatcher + + /// Invokes the action on the UI thread. + /// + /// The action to invoke. + public void Invoke(Action action) => Dispatcher.Invoke(action); + + /// Invokes the function on the UI thread. + /// + /// The function to invoke. + /// The result of the function. + public T Invoke(Func action) => Dispatcher.Invoke(action); + + /// Invokes the action asynchronously on the UI thread. + /// + /// The action to invoke. + /// True if the action should use normal priority. + public void BeginInvoke(Action action, bool normalPriority) => Dispatcher.BeginInvoke(action, GetPriority(normalPriority)); + + /// Checks if the current thread is the UI thread. + /// + /// True if the current thread is the UI thread. + public bool CheckAccess() => Dispatcher.CheckAccess(); + + #endregion + + #region Shutdown + + /// Shuts down the application. + public void Shutdown() => Dispatcher.InvokeShutdown(); + + public event EventHandler ShuttingDown { + add => Dispatcher.ShutdownStarted += value; + remove => Dispatcher.ShutdownStarted -= value; + } + + #endregion + + #region Create Timer + + /// Creates a new stopped UI timer. + /// + /// The interval for the timer. + /// True if the timer runs at normal priority. + /// The callback on the timer tick event. + /// The newly created timer. + public UITimer CreateTimer(TimeSpan interval, bool normalPriority, Action callback) => new UITimer(interval, normalPriority, callback, false); + /// Creates a new running UI timer. + /// + /// The interval for the timer. + /// True if the timer runs at normal priority. + /// The callback on the timer tick event. + /// The newly created timer. + public UITimer StartTimer(TimeSpan interval, bool normalPriority, Action callback) => new UITimer(interval, normalPriority, callback, true); + + #endregion + + public static DispatcherPriority GetPriority(bool normalPriority) => normalPriority ? DispatcherPriority.Normal : DispatcherPriority.Background; + } + + /// A timer that runs its callbacks on the UI thread. + public class UITimer { + + #region Fields + + /// The wrapped dispatcher timer. + private readonly DispatcherTimer dispatcherTimer; + /// The event handler callback constructed from the action. + private EventHandler handlerCallback; + /// The action used for the callback. + private Action callback; + + #endregion + + #region Constructors + + /// Constructs the see . + /// + /// The interval for the timer. + /// True if the timer runs at normal priority. + /// The callback on the timer tick event. + /// True if the timer should start running. + public UITimer(TimeSpan interval, bool normalPriority, Action callback, bool start) { + this.callback = callback ?? throw new ArgumentNullException(nameof(callback)); + handlerCallback = (o, s) => callback(); + dispatcherTimer = new DispatcherTimer( + interval, + UIService.GetPriority(normalPriority), + handlerCallback, + Application.Current.Dispatcher); + if (!start) + dispatcherTimer.Stop(); + } + + #endregion + + #region Properties + + /// Gets or sets the callback method for the timer. + public Action Callback { + get => callback; + set { + if (callback != value) { + callback = value ?? throw new ArgumentNullException(nameof(Callback)); + dispatcherTimer.Tick -= handlerCallback; + handlerCallback = (o, s) => callback(); + dispatcherTimer.Tick += handlerCallback; + } + } + } + /// Gets or sets the interval for the timer. + public TimeSpan Interval { + get => dispatcherTimer.Interval; + set => dispatcherTimer.Interval = value; + } + /// Gets or sets if the timer is running. + public bool IsRunning { + get => dispatcherTimer.IsEnabled; + set { + if (dispatcherTimer.IsEnabled != value) { + if (value) + dispatcherTimer.Start(); + else + dispatcherTimer.Stop(); + } + } + } + + #endregion + + #region Start/Stop + + /// Starts the timer. + public void Start() { + dispatcherTimer.Start(); + } + /// Stops the timer. + public void Stop() { + dispatcherTimer.Stop(); + } + /// Restarts the timer. + public void Restart() { + dispatcherTimer.Stop(); + dispatcherTimer.Start(); + } + + #endregion + } } diff --git a/WinDirStat.Net.Wpf.Base/Utils/ArrayExtensions.cs b/WinDirStat.Net.Wpf.Base/Utils/ArrayExtensions.cs index dab61b2..30a4a9a 100644 --- a/WinDirStat.Net.Wpf.Base/Utils/ArrayExtensions.cs +++ b/WinDirStat.Net.Wpf.Base/Utils/ArrayExtensions.cs @@ -19,254 +19,6 @@ public enum BlockCastAlign { /// Extensions for 1-dimensional objects. public static class ArrayExtensions { - #region Memset (Single) - - /// Populates the entire array with the specified value. - /// The array to fill. - /// The value to populate the array with. - /// Returns the same array that was populated. - /// Created by TowerOfBricks: - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - public static void Memset(this Array array, object value) { - Memset(array, value, 0, array.Length); - } - - /// - /// Populates the specified section of the array with the specified value. - /// - /// - /// The array to fill. - /// The value to populate the array with. - /// The index to start populating the array at. - /// The number of elements to populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - /// - /// or is less than zero. - /// - public static void Memset(this Array array, object value, int startIndex, - int length) - { - if (length < 0) - throw new ArgumentOutOfRangeException(nameof(length), - $"{nameof(length)} '{length}' is less than zero!"); - - int block = Math.Min(32, length); - int index = startIndex; - int end = startIndex + block; - - while (index < end) - array.SetValue(value, index++); - - end = startIndex + length; - while (index < end) { - Array.Copy(array, startIndex, array, index, Math.Min(block, end - index)); - index += block; - block *= 2; - } - } - - /// Populates the entire array with the specified value. - /// The element type of the array. - /// The array to fill. - /// The value to populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - public static void Memset(this T[] array, T value) { - Memset(array, value, 0, array.Length); - } - - /// - /// Populates the specified section of the array with the specified value. - /// - /// - /// The element type of the array. - /// The array to fill. - /// The value to populate the array with. - /// The index to start populating the array at. - /// The number of elements to populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - /// - /// or is less than zero. - /// - public static void Memset(this T[] array, T value, int startIndex, - int length) - { - if (length < 0) - throw new ArgumentOutOfRangeException(nameof(length), - $"{nameof(length)} '{length}' is less than zero!"); - - int block = Math.Min(32, length); - int index = startIndex; - int end = startIndex + block; - - while (index < end) - array[index++] = value; - - end = startIndex + length; - while (index < end) { - Array.Copy(array, startIndex, array, index, Math.Min(block, end - index)); - index += block; - block *= 2; - } - } - - #endregion - - #region Memset (Multiple) - - /// Populates the entire array with the specified repeating values. - /// The array to fill. - /// The ordered values to repeatedly populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - /// - /// has a length of zero. - /// - /// is null. - public static void Memset(this Array array, Array values) { - array.Memset(values, 0, array.Length); - } - - /// - /// Populates the specified section of the array with the specified repeating values. - /// - /// - /// The array to fill. - /// The ordered values to repeatedly populate the array with. - /// The index to start populating the array at. - /// The number of single elements to populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - /// - /// or is less than zero. - /// - /// - /// has a length of zero. - /// - /// is null. - public static void Memset(this Array array, Array values, int startIndex, - int length) - { - if (length < 0) - throw new ArgumentOutOfRangeException(nameof(length), - $"{nameof(length)} '{length}' is less than zero!"); - else if (values == null) - throw new ArgumentNullException(nameof(values)); - else if (values.Length == 0) - throw new ArgumentException($"{nameof(values)} has a length of zero!", - nameof(values)); - - // Make sure the starting block is divisible by the number of values. - int block = Math.Max(values.Length, (32 / values.Length) * values.Length); - int index = startIndex; - int end = startIndex + block; - - for (int i = 0; i < block; i++) - array.SetValue(values.GetValue(i), index++); - - end = startIndex + length; - while (index < end) { - Array.Copy(array, 0, array, index, Math.Min(block, end - index)); - index += block; - block *= 2; - } - } - - /// Populates the entire array with the specified repeating values. - /// The element type of the array. - /// The array to fill. - /// The ordered values to repeatedly populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - /// - /// has a length of zero. - /// - /// is null. - public static void Memset(this T[] array, params T[] values) { - array.Memset(values, 0, array.Length); - } - - /// - /// Populates the specified section of the array with the specified repeating values. - /// - /// - /// The element type of the array. - /// The array to fill. - /// The ordered values to repeatedly populate the array with. - /// The index to start populating the array at. - /// The number of single elements to populate the array with. - /// Returns the same array that was populated. - /// - /// - /// Modified version of Memset created by TowerOfBricks: Source - /// - /// - /// or is less than zero. - /// - /// has a length of zero. - /// - /// is null. - public static void Memset(this T[] array, T[] values, int startIndex, - int length) - { - if (length < 0) - throw new ArgumentOutOfRangeException(nameof(length), - $"{nameof(length)} '{length}' is less than zero!"); - else if (values == null) - throw new ArgumentNullException(nameof(values)); - else if (values.Length == 0) - throw new ArgumentException($"{nameof(values)} has a length of zero!", - nameof(values)); - - // Make sure the starting block is divisible by the number of values. - int block = Math.Max(values.Length, (32 / values.Length) * values.Length); - int index = startIndex; - int end = startIndex + block; - - for (int i = 0; i < block; i++) - array[index++] = values[i]; - - end = startIndex + length; - while (index < end) { - Array.Copy(array, 0, array, index, Math.Min(block, end - index)); - index += block; - block *= 2; - } - } - - #endregion - #region Contains /// Returns true if the array contains the specified value. diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/Commands/IRelayCommand.Generic.cs b/WinDirStat.Net.Wpf.Base/ViewModel/Commands/IRelayCommand.Generic.cs deleted file mode 100644 index 12203d9..0000000 --- a/WinDirStat.Net.Wpf.Base/ViewModel/Commands/IRelayCommand.Generic.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; - -namespace WinDirStat.Net.ViewModel.Commands { - /// An interface for working with any type of RelayCommand. - public interface IRelayCommand : IRelayCommandBase { - - /// Executes the method with a parameter. - void Execute(T parameter); - } -} diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/Commands/IRelayCommand.cs b/WinDirStat.Net.Wpf.Base/ViewModel/Commands/IRelayCommand.cs deleted file mode 100644 index e7123c9..0000000 --- a/WinDirStat.Net.Wpf.Base/ViewModel/Commands/IRelayCommand.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; - -namespace WinDirStat.Net.ViewModel.Commands { - /// An interface for working with any type of RelayCommand. - public interface IRelayCommand : IRelayCommandBase { - - /// Executes the method without a parameter. - void Execute(); - } -} diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/Commands/IRelayCommandBase.cs b/WinDirStat.Net.Wpf.Base/ViewModel/Commands/IRelayCommandBase.cs deleted file mode 100644 index ab2e2f9..0000000 --- a/WinDirStat.Net.Wpf.Base/ViewModel/Commands/IRelayCommandBase.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; - -namespace WinDirStat.Net.ViewModel.Commands { - /// A base interface for working with any type of RelayCommand. - public interface IRelayCommandBase : ICommand { - - /// Raises the event. - void RaiseCanExecuteChanged(); - } -} diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/Comparers/SortComparer.cs b/WinDirStat.Net.Wpf.Base/ViewModel/Comparers/SortComparer.cs index bd6f19d..7647772 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/Comparers/SortComparer.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/Comparers/SortComparer.cs @@ -1,134 +1,123 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using GalaSoft.MvvmLight; - -namespace WinDirStat.Net.ViewModel.Comparers { - /// A helper class for view model comparers. - /// The type of the view model. - /// The type that representings the sort mode. - public abstract class SortComparer : ObservableObject, IComparer, IComparer { - - #region Fields - - /// The current sort direction. - private ListSortDirection direction; - /// The current sort mode. - private TSortMode mode; - /// The current sort comparison. - private Comparison comparison; - - #endregion - - #region Constructor - - /// - /// Constructs the with the specified sort mode in ascending order. - /// - /// - /// The sort mode to start with. - protected SortComparer(TSortMode mode) { - Mode = mode; - } - - /// - /// Constructs the with the specified sort mode and direction. - /// - /// - /// The sort mode to start with. - /// The sort direction to start with. - protected SortComparer(TSortMode mode, ListSortDirection direction) { - Mode = mode; - Direction = direction; - } - - #endregion - - #region IComparer - - /// Compares the two items based on the sort mode and direction. - /// - /// The first item to compare. - /// The second item to compare. - /// The comparison result. - public int Compare(T a, T b) { - int diff = comparison(a, b); - // Always sort alphabetically after initial sort - if (diff == 0) - return SecondaryCompare(a, b); - if (direction == ListSortDirection.Ascending) - return diff; - else - return -diff; - } - /// Compares the two items based on the sort mode and direction. - /// - /// The first item to compare. - /// The second item to compare. - /// The comparison result. - int IComparer.Compare(object a, object b) { - return Compare((T) a, (T) b); - } - - #endregion - - #region Sort Settings - - /// Gets the mode that determines the primary comparison method. - public TSortMode Mode { - get => mode; - set { - if (!mode.Equals(value)) { - mode = value; - comparison = GetSortComparison(mode); - RaisePropertyChanged(); - } - } - } - /// Gets the direction of the sorting. - public ListSortDirection Direction { - get => direction; - set { - if (direction != value) { - direction = value; - RaisePropertyChanged(); - RaisePropertyChanged(nameof(IsDescending)); - } - } - } - /// Gets if the sort direction is in descending order. - public bool IsDescending { - get => direction == ListSortDirection.Descending; - set { - if (IsDescending != value) { - if (value) - direction = ListSortDirection.Descending; - else - direction = ListSortDirection.Ascending; - RaisePropertyChanged(nameof(Direction)); - RaisePropertyChanged(); - } - } - } - - #endregion - - #region Abstract Methods - - /// A secondary comparison that's called when the sort mode comparison returns 0. - /// - /// The first item to compare. - /// The second item to compare. - /// The comparison result. - protected abstract int SecondaryCompare(T a, T b); - - /// Gets the comparison method for the specified sort mode. - /// - /// The mode to get the comparison of. - /// The comparison to use. - protected abstract Comparison GetSortComparison(TSortMode mode); - - #endregion - } -} +using Microsoft.Toolkit.Mvvm.ComponentModel; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; + +namespace WinDirStat.Net.ViewModel.Comparers { + /// A helper class for view model comparers. + /// The type of the view model. + /// The type that representings the sort mode. + public abstract class SortComparer : ObservableObject, IComparer, IComparer { + + #region Fields + + /// The current sort direction. + private ListSortDirection direction; + /// The current sort mode. + private TSortMode mode; + /// The current sort comparison. + private Comparison comparison; + + #endregion + + #region Constructor + + /// + /// Constructs the with the specified sort mode in ascending order. + /// + /// + /// The sort mode to start with. + protected SortComparer(TSortMode mode) { + Mode = mode; + } + + /// + /// Constructs the with the specified sort mode and direction. + /// + /// + /// The sort mode to start with. + /// The sort direction to start with. + protected SortComparer(TSortMode mode, ListSortDirection direction) { + Mode = mode; + Direction = direction; + } + + #endregion + + #region IComparer + + /// Compares the two items based on the sort mode and direction. + /// + /// The first item to compare. + /// The second item to compare. + /// The comparison result. + public int Compare(T a, T b) { + int diff = comparison(a, b); + // Always sort alphabetically after initial sort + if (diff == 0) + return SecondaryCompare(a, b); + if (direction == ListSortDirection.Ascending) + return diff; + else + return -diff; + } + /// Compares the two items based on the sort mode and direction. + /// + /// The first item to compare. + /// The second item to compare. + /// The comparison result. + int IComparer.Compare(object a, object b) { + return Compare((T) a, (T) b); + } + + #endregion + + #region Sort Settings + + /// Gets the mode that determines the primary comparison method. + public TSortMode Mode { + get => mode; + set { + if (!mode.Equals(value)) { + mode = value; + comparison = GetSortComparison(mode); + OnPropertyChanged(); + } + } + } + /// Gets the direction of the sorting. + public ListSortDirection Direction { + get => direction; + set { + if (SetProperty(ref this.direction, value)) { + OnPropertyChanged(nameof(IsDescending)); + } + } + } + /// Gets if the sort direction is in descending order. + public bool IsDescending { + get => direction == ListSortDirection.Descending; + set => this.Direction = value ? ListSortDirection.Descending : ListSortDirection.Ascending; + } + + #endregion + + #region Abstract Methods + + /// A secondary comparison that's called when the sort mode comparison returns 0. + /// + /// The first item to compare. + /// The second item to compare. + /// The comparison result. + protected abstract int SecondaryCompare(T a, T b); + + /// Gets the comparison method for the specified sort mode. + /// + /// The mode to get the comparison of. + /// The comparison to use. + protected abstract Comparison GetSortComparison(TSortMode mode); + + #endregion + } +} diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/DriveSelectViewModel.Commands.cs b/WinDirStat.Net.Wpf.Base/ViewModel/DriveSelectViewModel.Commands.cs index 7c73468..688e401 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/DriveSelectViewModel.Commands.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/DriveSelectViewModel.Commands.cs @@ -1,13 +1,9 @@ -using System; -using System.Collections.Generic; +using Microsoft.Toolkit.Mvvm.Input; using System.Linq; -using System.Text; -using System.Threading.Tasks; using WinDirStat.Net.Model.Drives; -using WinDirStat.Net.ViewModel.Commands; -namespace WinDirStat.Net.ViewModel { - partial class DriveSelectViewModel { +namespace WinDirStat.Net.ViewModel { + partial class DriveSelectViewModel { public IRelayCommand OK => GetCommand(OnOK); diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/DriveSelectViewModel.cs b/WinDirStat.Net.Wpf.Base/ViewModel/DriveSelectViewModel.cs index 5e11d20..abdf289 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/DriveSelectViewModel.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/DriveSelectViewModel.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using GalaSoft.MvvmLight; +using Microsoft.Toolkit.Mvvm.ComponentModel; using WinDirStat.Net.Model.Drives; using WinDirStat.Net.Services; using WinDirStat.Net.ViewModel; @@ -95,7 +95,7 @@ public DriveSelectMode Mode { if (mode != value) { mode = value; ValidateSelection(); - RaisePropertyChanged(); + OnPropertyChanged(); } } } @@ -108,7 +108,7 @@ public string FolderPath { folderPath = value; if (mode == DriveSelectMode.Folder) ValidateSelection(); - RaisePropertyChanged(); + OnPropertyChanged(); } } } @@ -119,7 +119,7 @@ public bool IsValidSelection { private set { if (validSelection != value) { validSelection = value; - RaisePropertyChanged(); + OnPropertyChanged(); } } } @@ -127,7 +127,7 @@ private set { /// Gets the result root paths. public DriveSelectResult Result { get => result; - private set => Set(ref result, value); + private set => SetProperty(ref result, value); } #endregion diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/Drives/DriveItemViewModel.cs b/WinDirStat.Net.Wpf.Base/ViewModel/Drives/DriveItemViewModel.cs index 0f237a0..88f9371 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/Drives/DriveItemViewModel.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/Drives/DriveItemViewModel.cs @@ -1,94 +1,89 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Microsoft.Toolkit.Mvvm.ComponentModel; +using System.IO; using System.Windows.Media; -using GalaSoft.MvvmLight; using WinDirStat.Net.Model.Drives; using WinDirStat.Net.Services; using WinDirStat.Net.Utils; namespace WinDirStat.Net.ViewModel.Drives { - /// The view model that represents a drive item. - public class DriveItemViewModel : ObservableObject { - - #region Fields - - /// The collection containing this drive item view model. - private readonly DriveItemViewModelCollection drives; - /// The model that this view model represents. - public DriveItem Model { get; } - - /// The display icon for the drive. - private ImageSource icon; - /// The display name for the drive. - private string displayName; - - #endregion - - #region Constructors - - /// Constructs the see . - /// - /// The collection containing this drive item view model. - /// The model that this view model represents. - public DriveItemViewModel(DriveItemViewModelCollection drives, DriveItem model) { - this.drives = drives; - Model = model; - - IconAndName iconName = IconCache.CacheIconAndDisplayName(Name); - if (iconName != null) { - Icon = iconName.Icon; - DisplayName = iconName.Name; - } - else { - Icon = IconCache.VolumeIcon; - DisplayName = $"({PathUtils.TrimSeparatorEnd(Name)})"; - } - } - - #endregion - - #region Properties - - /// Gets the display icon for the drive. - public ImageSource Icon { - get => icon; - private set => Set(ref icon, value); - } - - /// Gets the display name for the drive. - public string DisplayName { - get => displayName; - private set => Set(ref displayName, value); - } - - /// Gets the name/path of the drive. - public string Name => Model.Name; - /// Gets the total size of the drive. - public long TotalSize => Model.TotalSize; - /// Gets the freespace on the drive in bytes. - public long FreeSpace => Model.FreeSpace; - /// Gets the type of the drive. - public DriveType DriveType => Model.DriveType; - /// Gets the partition format of the drive. - public string DriveFormat => Model.DriveFormat; - /// Gets the used space on the drive in bytes. - public long UsedSpace => Model.UsedSpace; - /// Gets the used percentage of the drive. - public double Percent => Model.Percent; - - /// Gets the icon cache service. - private IconCacheService IconCache => drives.IconCache; - - /// Gets the program settings service. - private SettingsService Settings => drives.Settings; - - /// Gets the icon cache mode setting. - private IconCacheMode CacheMode => drives.Settings.IconCacheMode; - - #endregion - } + /// The view model that represents a drive item. + public class DriveItemViewModel : ObservableObject { + + #region Fields + + /// The collection containing this drive item view model. + private readonly DriveItemViewModelCollection drives; + /// The model that this view model represents. + public DriveItem Model { get; } + + /// The display icon for the drive. + private ImageSource icon; + /// The display name for the drive. + private string displayName; + + #endregion + + #region Constructors + + /// Constructs the see . + /// + /// The collection containing this drive item view model. + /// The model that this view model represents. + public DriveItemViewModel(DriveItemViewModelCollection drives, DriveItem model) { + this.drives = drives; + Model = model; + + IconAndName iconName = IconCache.CacheIconAndDisplayName(Name); + if (iconName != null) { + Icon = iconName.Icon; + DisplayName = iconName.Name; + } + else { + Icon = IconCache.VolumeIcon; + DisplayName = $"({PathUtils.TrimSeparatorEnd(Name)})"; + } + } + + #endregion + + #region Properties + + /// Gets the display icon for the drive. + public ImageSource Icon { + get => icon; + private set => SetProperty(ref icon, value); + } + + /// Gets the display name for the drive. + public string DisplayName { + get => displayName; + private set => SetProperty(ref displayName, value); + } + + /// Gets the name/path of the drive. + public string Name => Model.Name; + /// Gets the total size of the drive. + public long TotalSize => Model.TotalSize; + /// Gets the freespace on the drive in bytes. + public long FreeSpace => Model.FreeSpace; + /// Gets the type of the drive. + public DriveType DriveType => Model.DriveType; + /// Gets the partition format of the drive. + public string DriveFormat => Model.DriveFormat; + /// Gets the used space on the drive in bytes. + public long UsedSpace => Model.UsedSpace; + /// Gets the used percentage of the drive. + public double Percent => Model.Percent; + + /// Gets the icon cache service. + private IconCacheService IconCache => drives.IconCache; + + /// Gets the program settings service. + private SettingsService Settings => drives.Settings; + + /// Gets the icon cache mode setting. + private IconCacheMode CacheMode => drives.Settings.IconCacheMode; + + #endregion + } } diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/Extensions/ExtensionItemViewModel.cs b/WinDirStat.Net.Wpf.Base/ViewModel/Extensions/ExtensionItemViewModel.cs index 3a4a860..f591d82 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/Extensions/ExtensionItemViewModel.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/Extensions/ExtensionItemViewModel.cs @@ -1,191 +1,193 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Microsoft.Toolkit.Mvvm.ComponentModel; +using System; +using System.Windows; using System.Windows.Media; -using GalaSoft.MvvmLight; +using System.Windows.Threading; using WinDirStat.Net.Model.Extensions; using WinDirStat.Net.Services; -namespace WinDirStat.Net.ViewModel.Extensions { - /// The view model that represents an . - public class ExtensionItemViewModel : ObservableObject, IDisposable { - - #region Constants - - /// The used to represent a non-file. - public static readonly ExtensionItemViewModel NotAFile = new ExtensionItemViewModel(); - - #endregion - - #region Fields - - /// The collection containing this item. - private readonly ExtensionItemViewModelCollection extensions; - /// Gets the model that this view model represents. - public ExtensionItem Model { get; } - - /// The icon of the associated file type. - private ImageSource icon; - /// The type name of the associated file type. - private string typeName; - /// The cache state for the icon. - private IconCacheState cacheState; - /// True if events have been hooked to the model. - private bool eventsHooked; - /// The preview image for the file palette color. - private ImageSource preview; - - #endregion - - #region Constructors - - /// - /// Constructs an used to represent a non-file. - /// - private ExtensionItemViewModel() { - Model = ExtensionItem.NotAFile; - } - - /// Constructs an . - /// - /// The collection containing this item. - /// The model that this view model item represents. - public ExtensionItemViewModel(ExtensionItemViewModelCollection extensions, ExtensionItem model) { - this.extensions = extensions; - Model = model; - icon = IconCache.FileIcon; - if (IsEmptyExtension || Extension.Contains(" ")) { - // Extensions with spaces have no rights, so says Windows - typeName = "File"; - cacheState = IconCacheState.Cached; - } - else { - typeName = model.Extension.TrimStart('.').ToUpper() + " File"; - if (CacheMode >= IconCacheMode.FileType) - LoadIcon(); - } - HookEvents(); - } - - /// Disposes of the . - /*~ExtensionItemViewModel() { +namespace WinDirStat.Net.ViewModel.Extensions { + /// The view model that represents an . + public class ExtensionItemViewModel : ObservableObject, IDisposable { + + #region Constants + + /// The used to represent a non-file. + public static readonly ExtensionItemViewModel NotAFile = new ExtensionItemViewModel(); + + #endregion + + #region Fields + + /// The collection containing this item. + private readonly ExtensionItemViewModelCollection extensions; + /// Gets the model that this view model represents. + public ExtensionItem Model { get; } + + /// The icon of the associated file type. + private ImageSource icon; + /// The type name of the associated file type. + private string typeName; + /// The cache state for the icon. + private IconCacheState cacheState; + /// True if events have been hooked to the model. + private bool eventsHooked; + /// The preview image for the file palette color. + private ImageSource preview; + + #endregion + + #region Constructors + + /// + /// Constructs an used to represent a non-file. + /// + private ExtensionItemViewModel() { + Model = ExtensionItem.NotAFile; + } + + /// Constructs an . + /// + /// The collection containing this item. + /// The model that this view model item represents. + public ExtensionItemViewModel(ExtensionItemViewModelCollection extensions, ExtensionItem model) { + this.extensions = extensions; + Model = model; + icon = IconCache.FileIcon; + if (IsEmptyExtension || Extension.Contains(" ")) { + // Extensions with spaces have no rights, so says Windows + typeName = "File"; + cacheState = IconCacheState.Cached; + } + else { + typeName = model.Extension.TrimStart('.').ToUpper() + " File"; + if (CacheMode >= IconCacheMode.FileType) + LoadIcon(); + } + HookEvents(); + } + + /// Disposes of the . + /*~ExtensionItemViewModel() { Dispose(); - }*/ - - #endregion - - #region Event Handlers - - private void OnModelChanged(ExtensionItem sender, ExtensionItemEventArgs e) { - switch (e.Action) { - case ExtensionItemAction.ColorChanged: - Preview = Settings.GetFilePalettePreview(e.Index); - break; - case ExtensionItemAction.GetViewModel: - e.ViewModel = this; - break; - } - } - - #endregion - - #region CacheIcon - - /// Attempts to load the icon if it has not already been loaded. - public void LoadIcon() { - if (cacheState == IconCacheState.NotCached) { - cacheState = IconCacheState.Caching; - IconCache.CacheFileTypeAsync(Extension, OnCacheIconAndTypeName); - } - } - - /// The callback for asynchronously caching the file type icon and type name. - /// - /// The resulting icon and type name. - private void OnCacheIconAndTypeName(IconAndName iconName) { - if (iconName != null) { - Icon = iconName.Icon; - TypeName = iconName.Name; - } - // Even if "I failed, I failed, I failed", we're not gonna reattempt this - cacheState = IconCacheState.Cached; - } - - #endregion - - #region Properties - - /// Gets the name of the extension with the dot. - public string Extension => Model.Extension; - /// Gets the total size of all the files that use this extension. - public long Size => Model.Size; - /// Gets the number of files that use this extension. - public int FileCount => Model.FileCount; - /// Gets this extension's size relative to the total used space. - public double Percent => Model.Percent; - /// Gets if this extension is the empty extension with nothing after the dot. - public bool IsEmptyExtension => Model.IsEmptyExtension; - - /// Gets the icon of the associated file type. - public ImageSource Icon { - get => icon; - private set => Set(ref icon, value); - } - - /// Gets the type name of the associated file type. - public string TypeName { - get => typeName; - private set => Set(ref typeName, value); - } - - /// Gets the preview image for the file palette color. - public ImageSource Preview { - get => preview; - internal set => Set(ref preview, value); - } - - /// Gets the cache state for the icon. - public IconCacheState CacheState { - get => cacheState; - private set => Set(ref cacheState, value); - } - - /// Gets the icon cache service. - private IconCacheService IconCache => extensions.IconCache; - - /// Gets the program settings service. - private SettingsService Settings => extensions.Settings; - - /// Gets the icon cache mode setting. - private IconCacheMode CacheMode => extensions.Settings.IconCacheMode; - - #endregion - - #region IDisposable Implementation - - /// Disposes of the . - public void Dispose() { - UnhookEvents(); - } - - /// Hooks up events to the model changed event. - private void HookEvents() { - if (!eventsHooked) { - eventsHooked = true; - Model.Changed += OnModelChanged; - } - } - - /// Unhooks events from the model changed event. - private void UnhookEvents() { - if (eventsHooked) { - eventsHooked = false; - Model.Changed -= OnModelChanged; - } - } - - #endregion - } + }*/ + + #endregion + + #region Event Handlers + + private void OnModelChanged(ExtensionItem sender, ExtensionItemEventArgs e) { + switch (e.Action) { + case ExtensionItemAction.ColorChanged: + Preview = Settings.GetFilePalettePreview(e.Index); + break; + case ExtensionItemAction.GetViewModel: + e.ViewModel = this; + break; + } + } + + #endregion + + #region CacheIcon + + /// Attempts to load the icon if it has not already been loaded. + public void LoadIcon() { + if (cacheState > IconCacheState.NotCached) + return; + + cacheState = IconCacheState.Caching; + Application.Current.Dispatcher.BeginInvoke(() => { + var icon = IconCache.CacheFileType(Extension); + OnCacheIconAndTypeName(icon); + }, DispatcherPriority.Background); + } + + /// The callback for asynchronously caching the file type icon and type name. + /// + /// The resulting icon and type name. + private void OnCacheIconAndTypeName(IconAndName iconName) { + if (iconName != null) { + Icon = iconName.Icon; + TypeName = iconName.Name; + } + // Even if "I failed, I failed, I failed", we're not gonna reattempt this + cacheState = IconCacheState.Cached; + } + + #endregion + + #region Properties + + /// Gets the name of the extension with the dot. + public string Extension => Model.Extension; + /// Gets the total size of all the files that use this extension. + public long Size => Model.Size; + /// Gets the number of files that use this extension. + public int FileCount => Model.FileCount; + /// Gets this extension's size relative to the total used space. + public double Percent => Model.Percent; + /// Gets if this extension is the empty extension with nothing after the dot. + public bool IsEmptyExtension => Model.IsEmptyExtension; + + /// Gets the icon of the associated file type. + public ImageSource Icon { + get => icon; + private set => SetProperty(ref icon, value); + } + + /// Gets the type name of the associated file type. + public string TypeName { + get => typeName; + private set => SetProperty(ref typeName, value); + } + + /// Gets the preview image for the file palette color. + public ImageSource Preview { + get => preview; + internal set => SetProperty(ref preview, value); + } + + /// Gets the cache state for the icon. + public IconCacheState CacheState { + get => cacheState; + private set => SetProperty(ref cacheState, value); + } + + /// Gets the icon cache service. + private IconCacheService IconCache => extensions.IconCache; + + /// Gets the program settings service. + private SettingsService Settings => extensions.Settings; + + /// Gets the icon cache mode setting. + private IconCacheMode CacheMode => extensions.Settings.IconCacheMode; + + #endregion + + #region IDisposable Implementation + + /// Disposes of the . + public void Dispose() { + UnhookEvents(); + } + + /// Hooks up events to the model changed event. + private void HookEvents() { + if (!eventsHooked) { + eventsHooked = true; + Model.Changed += OnModelChanged; + } + } + + /// Unhooks events from the model changed event. + private void UnhookEvents() { + if (eventsHooked) { + eventsHooked = false; + Model.Changed -= OnModelChanged; + } + } + + #endregion + } } diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/Extensions/ExtensionItemViewModelCollection.cs b/WinDirStat.Net.Wpf.Base/ViewModel/Extensions/ExtensionItemViewModelCollection.cs index 9d7e401..6a59396 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/Extensions/ExtensionItemViewModelCollection.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/Extensions/ExtensionItemViewModelCollection.cs @@ -3,17 +3,14 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using WinDirStat.Net.Model.Extensions; using WinDirStat.Net.Services; using WinDirStat.Net.Utils; using static WinDirStat.Net.Model.Extensions.ExtensionItem; -namespace WinDirStat.Net.ViewModel.Extensions { - /// A collection manager for s. - public class ExtensionItemViewModelCollection +namespace WinDirStat.Net.ViewModel.Extensions { + /// A collection manager for s. + public class ExtensionItemViewModelCollection : ObservablePropertyCollectionObject, IReadOnlyList { #region Fields @@ -76,7 +73,7 @@ private bool IsNotOpen { isNotOpen = value; if (extensions.Count > 0) { UI.Invoke(() => { - RaisePropertyChanged(nameof(Count)); + OnPropertyChanged(nameof(Count)); RaiseCollectionChanged(NotifyCollectionChangedAction.Reset); }); } diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/Files/FileItemViewModel.TreeNode.cs b/WinDirStat.Net.Wpf.Base/ViewModel/Files/FileItemViewModel.TreeNode.cs index d1f89a1..e4f35e5 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/Files/FileItemViewModel.TreeNode.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/Files/FileItemViewModel.TreeNode.cs @@ -139,9 +139,9 @@ public bool IsHidden { isHidden = value; if (parent != null) UpdateIsVisible(parent.isVisible && parent.isExpanded, true); - RaisePropertyChanged(); + OnPropertyChanged(); if (Parent != null) - Parent.RaisePropertyChanged(nameof(ShowExpander)); + Parent.OnPropertyChanged(nameof(ShowExpander)); } } } @@ -156,7 +156,7 @@ public bool IsSelected { set { if (isSelected != value) { isSelected = value; - RaisePropertyChanged(); + OnPropertyChanged(); } } } @@ -168,7 +168,7 @@ public bool IsSelected { internal protected void RaiseChildrenReset() { Stopwatch watch = Stopwatch.StartNew(); GetListRoot().treeFlattener.NodesReset(); - Console.WriteLine($"Took {watch.ElapsedMilliseconds}ms to reset"); + Debug.WriteLine($"Took {watch.ElapsedMilliseconds}ms to reset"); } internal protected void OnChildrenReset(List newList, List oldList) { @@ -218,25 +218,24 @@ internal protected void OnChildrenReset(List newList, List 0) { if (oldList.Count > 0) { if (newList[newList.Count - 1] != oldList[oldList.Count - 1]) { - oldList[oldList.Count - 1].RaisePropertyChanged(nameof(IsLast)); - newList[newList.Count - 1].RaisePropertyChanged(nameof(IsLast)); + oldList[oldList.Count - 1].OnPropertyChanged(nameof(IsLast)); + newList[newList.Count - 1].OnPropertyChanged(nameof(IsLast)); } } else { - newList[newList.Count - 1].RaisePropertyChanged(nameof(IsLast)); + newList[newList.Count - 1].OnPropertyChanged(nameof(IsLast)); } } else if (oldList.Count > 0) { - oldList[oldList.Count - 1].RaisePropertyChanged(nameof(IsLast)); + oldList[oldList.Count - 1].OnPropertyChanged(nameof(IsLast)); } //RaiseIsLastChangedIfNeeded(e); } internal protected void OnChildrenChanged(NotifyCollectionChangedEventArgs e) { - Debug.WriteLine(e.Action); if (e.OldItems != null) { foreach (FileItemViewModel node in e.OldItems) { Debug.Assert(node.parent == this); @@ -296,7 +295,7 @@ internal protected void OnChildrenChanged(NotifyCollectionChangedEventArgs e) { } } - RaisePropertyChanged(nameof(ShowExpander)); + OnPropertyChanged(nameof(ShowExpander)); RaiseIsLastChangedIfNeeded(e); } #endregion @@ -319,7 +318,7 @@ public bool IsExpanded { OnCollapsing(); } UpdateChildIsVisible(true); - RaisePropertyChanged(); + OnPropertyChanged(); } } } @@ -335,11 +334,11 @@ public bool IsExpanded { IsExpanded = false; if (canExpandRecursively) { canExpandRecursively = false; - RaisePropertyChanged("CanExpandRecursively"); + OnPropertyChanged("CanExpandRecursively"); } } - RaisePropertyChanged("LazyLoading"); - RaisePropertyChanged("ShowExpander"); + OnPropertyChanged("LazyLoading"); + OnPropertyChanged("ShowExpander"); } }*/ @@ -416,7 +415,7 @@ public bool IsEditing { set { if (isEditing != value) { isEditing = value; - RaisePropertyChanged(); + OnPropertyChanged(); } } } @@ -468,7 +467,7 @@ void SetIsChecked(bool? value, bool update) { } } - RaisePropertyChanged("IsChecked"); + OnPropertyChanged("IsChecked"); } } @@ -539,7 +538,7 @@ public bool IsCut private set { isCut = value; - RaisePropertyChanged("IsCut"); + OnPropertyChanged("IsCut"); } } @@ -696,15 +695,15 @@ void RaiseIsLastChangedIfNeeded(NotifyCollectionChangedEventArgs e) { case NotifyCollectionChangedAction.Add: if (e.NewStartingIndex == Children.Count - 1) { if (Children.Count > 1) { - Children[Children.Count - 2].RaisePropertyChanged("IsLast"); + Children[Children.Count - 2].OnPropertyChanged("IsLast"); } - Children[Children.Count - 1].RaisePropertyChanged("IsLast"); + Children[Children.Count - 1].OnPropertyChanged("IsLast"); } break; case NotifyCollectionChangedAction.Remove: if (e.OldStartingIndex == Children.Count) { if (Children.Count > 0) { - Children[Children.Count - 1].RaisePropertyChanged("IsLast"); + Children[Children.Count - 1].OnPropertyChanged("IsLast"); } } break; @@ -723,18 +722,18 @@ void RaiseIsLastChangedIfNeeded(NotifyCollectionChangedEventArgs e) { }*/ /*public event PropertyChangedEventHandler PropertyChanged; - protected internal void RaisePropertyChanged(string name) { - //visualInfo?.RaisePropertyChanged(this, new PropertyChangedEventArgs(name)); + protected internal void OnPropertyChanged(string name) { + //visualInfo?.OnPropertyChanged(this, new PropertyChangedEventArgs(name)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } protected internal void RaisePropertiesChanged(params string[] names) { for (int i = 0; i < names.Length; i++) - RaisePropertyChanged(names[i]); + OnPropertyChanged(names[i]); } - protected internal void AutoRaisePropertyChanged([CallerMemberName] string name = null) { - //visualInfo?.RaisePropertyChanged(this, new PropertyChangedEventArgs(name)); + protected internal void AutoOnPropertyChanged([CallerMemberName] string name = null) { + //visualInfo?.OnPropertyChanged(this, new PropertyChangedEventArgs(name)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); }*/ diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/Files/FileItemViewModel.cs b/WinDirStat.Net.Wpf.Base/ViewModel/Files/FileItemViewModel.cs index 9a366ee..00782e9 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/Files/FileItemViewModel.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/Files/FileItemViewModel.cs @@ -1,21 +1,18 @@ -using System; +using Microsoft.Toolkit.Mvvm.ComponentModel; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Media; -using GalaSoft.MvvmLight; using WinDirStat.Net.Model.Files; using WinDirStat.Net.Services; using WinDirStat.Net.Utils; using WinDirStat.Net.ViewModel.Extensions; -namespace WinDirStat.Net.ViewModel.Files { - /// A view model for displaying models. - public partial class FileItemViewModel : ObservableObject, IDisposable { +namespace WinDirStat.Net.ViewModel.Files { + /// A view model for displaying models. + public partial class FileItemViewModel : ObservableObject, IDisposable { #region Constants @@ -76,12 +73,12 @@ public FileItemViewModel(MainViewModel viewModel, FileItemBase model) { /// Gets the parent of the item. public FileItemViewModel Parent { get => parent; - private set => Set(ref parent, value); + private set => SetProperty(ref parent, value); } /// Gets the icon of the item. public ImageSource Icon { get => icon; - private set => Set(ref icon, value); + private set => SetProperty(ref icon, value); } /// Gets the overlay icon if there is one. @@ -99,8 +96,8 @@ public ImageSource OverlayIcon { public string DisplayName { get => displayName; private set { - if (Set(ref displayName, value)) - RaisePropertyChanged(nameof(Header)); + if (SetProperty(ref displayName, value)) + OnPropertyChanged(nameof(Header)); } } @@ -199,8 +196,8 @@ public bool Exists { private set { if (exists != value) { exists = value; - RaisePropertyChanged(); - RaisePropertyChanged(nameof(OverlayIcon)); + OnPropertyChanged(); + OnPropertyChanged(nameof(OverlayIcon)); } } } @@ -234,9 +231,12 @@ private void LoadIcon(bool basicLoad = false) { case FileItemType.File: if (cacheMode >= IconCacheMode.FileType) { SetIcon(ExtensionItem.Icon); - if (cacheMode >= IconCacheMode.Individual) { - IconCache.CacheIconAsync(FullName, OnCacheFileIcon); - } + if (cacheMode >= IconCacheMode.Individual) { + UI.BeginInvoke(() => { + var namedIcon = IconCache.CacheIconAndDisplayName(FullName); + OnCacheFileIcon(namedIcon.Icon); + }, false); + } else if (ExtensionItem.CacheState != IconCacheState.Cached) { // Hook an event to wait for the cache state to change isWaitingForExtensionIcon = true; @@ -248,9 +248,13 @@ private void LoadIcon(bool basicLoad = false) { } break; case FileItemType.Directory: - SetIcon(IconCache.FolderIcon); - if (cacheMode >= IconCacheMode.Individual) - IconCache.CacheIconAsync(FullName, OnCacheFolderIcon); + SetIcon(IconCache.FolderIcon); + if (cacheMode >= IconCacheMode.Individual) { + UI.BeginInvoke(() => { + var namedIcon = IconCache.CacheIconAndDisplayName(FullName); + OnCacheFolderIcon(namedIcon.Icon); + }, false); + } break; case FileItemType.Volume: if (cacheMode >= IconCacheMode.Individual) { @@ -301,7 +305,7 @@ private void OnExtensionItemPropertyChanged(object sender, PropertyChangedEventA private bool SetIcon(ImageSource icon) { if (icon != null) { this.icon = icon; - RaisePropertyChanged(nameof(Icon)); + OnPropertyChanged(nameof(Icon)); return true; } return false; @@ -315,12 +319,12 @@ private bool SetIcon(ImageSource icon) { private bool SetIcon(ImageSource icon, ImageSource defaultIcon) { if (icon != null) { this.icon = icon; - RaisePropertyChanged(nameof(Icon)); + OnPropertyChanged(nameof(Icon)); return true; } else if (defaultIcon != null) { icon = defaultIcon; - RaisePropertyChanged(nameof(Icon)); + OnPropertyChanged(nameof(Icon)); } return false; } @@ -335,20 +339,20 @@ private bool SetIconAndDisplayName(IconAndName iconName, ImageSource defaultIcon if (iconName != null) { icon = iconName.Icon; displayName = iconName.Name; - RaisePropertyChanged(nameof(Icon)); - RaisePropertyChanged(nameof(DisplayName)); - RaisePropertyChanged(nameof(Header)); + OnPropertyChanged(nameof(Icon)); + OnPropertyChanged(nameof(DisplayName)); + OnPropertyChanged(nameof(Header)); return true; } else { if (defaultIcon != null) { icon = defaultIcon; - RaisePropertyChanged(nameof(Icon)); + OnPropertyChanged(nameof(Icon)); } if (defaultName != null) { displayName = defaultName; - RaisePropertyChanged(nameof(DisplayName)); - RaisePropertyChanged(nameof(Header)); + OnPropertyChanged(nameof(DisplayName)); + OnPropertyChanged(nameof(Header)); } } return false; @@ -377,8 +381,8 @@ private void OnCacheFolderIcon(ImageSource icon) { else { displayName = Name; } - RaisePropertyChanged(nameof(Icon)); - RaisePropertyChanged(nameof(Header)); + OnPropertyChanged(nameof(Icon)); + OnPropertyChanged(nameof(Header)); }*/ #endregion @@ -457,18 +461,18 @@ private void OnModelChanged(FileItemBase sender, FileItemEventArgs e) { /// Raises changes in the view model due to model validation. private void OnModelValidated(bool sortOrder) { UI.Invoke(() => { - RaisePropertyChanged(nameof(Percent)); - RaisePropertyChanged(nameof(Size)); - RaisePropertyChanged(nameof(LastWriteTime)); + OnPropertyChanged(nameof(Percent)); + OnPropertyChanged(nameof(Size)); + OnPropertyChanged(nameof(LastWriteTime)); if (Model.IsContainerType) { - RaisePropertyChanged(nameof(ItemCount)); - RaisePropertyChanged(nameof(FileCount)); - RaisePropertyChanged(nameof(SubdirCount)); + OnPropertyChanged(nameof(ItemCount)); + OnPropertyChanged(nameof(FileCount)); + OnPropertyChanged(nameof(SubdirCount)); } if (children != null) { int count = children.Count; for (int i = 0; i < count; i++) - children[i].RaisePropertyChanged(nameof(Percent)); + children[i].OnPropertyChanged(nameof(Percent)); if (sortOrder && isExpanded) children.Sort(ViewModel.FileComparer.Compare); } @@ -489,7 +493,7 @@ private void OnModelChildrenAdded(List newChildren, int index) { } else if (newChildren.Count == Model.ChildCount) { // We had no children before - UI.Invoke(() => RaisePropertyChanged(nameof(ShowExpander))); + UI.Invoke(() => OnPropertyChanged(nameof(ShowExpander))); } } @@ -509,7 +513,7 @@ private void OnModelChildrenRemoved(List oldChildren) { } else if (oldChildren.Count > 0 && Model.ChildCount == 0) { // We have no children now - UI.Invoke(() => RaisePropertyChanged(nameof(ShowExpander))); + UI.Invoke(() => OnPropertyChanged(nameof(ShowExpander))); } } @@ -520,7 +524,7 @@ private void OnModelChildrenCleared() { if (children != null) children.Clear(); } - RaisePropertyChanged(nameof(ShowExpander)); + OnPropertyChanged(nameof(ShowExpander)); }); } diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/Graph/FileGraphViewModel.cs b/WinDirStat.Net.Wpf.Base/ViewModel/Graph/FileGraphViewModel.cs deleted file mode 100644 index d8a5095..0000000 --- a/WinDirStat.Net.Wpf.Base/ViewModel/Graph/FileGraphViewModel.cs +++ /dev/null @@ -1,257 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Rendering; -using WinDirStat.Net.Services; -using WinDirStat.Net.Structures; - -namespace WinDirStat.Net.ViewModel.Graph { - /// The view model for a file treemap display. - public partial class FileGraphViewModel : ViewModelBaseEx { - - #region Private Enums - - /// The modes for highlighting the graph view. - protected enum HighlightMode { - None, - Extension, - Selection, - } - - #endregion - - #region Fields - - public SettingsService Settings { get; } - public TreemapRenderer Treemap { get; } - public UIService UI { get; } - - - private Point2I treemapSize; - private WriteableBitmap treemap; - private Point2I highlightSize; - private WriteableBitmap highlight; - private WriteableBitmap disabledTreemap; - private WriteableBitmap disabledHighlight; - - /// True if the graph is currently dimmed. - private volatile bool isDimmed; - /// True if the running render thread has finished rendering the treemap. - private volatile bool treemapRendered; - /// True if the running render thread is rendering the treemap. - private volatile bool fullRender; - - /// The root treemap item. - private FileItemBase rootItem; - /// The hovered treemap item. - private FileItemBase hoverItem; - - /// The selected file items to highlight. - private FileItemBase[] selection; - /// The extension to highlight. - private string extension; - /// The current mode for highlighting. - private HighlightMode highlightMode; - - /// True if rendering should be done on a separate thread. - private bool renderAsynchronously; - - /// True if resizing is in progress. - private bool resizing; - /// The timer to delay rendering while resizing. - private readonly UITimer resizeTimer; - - /// The thread where the asynchronous rendering is done. - private Thread renderThread; - - /// The current mouse position of inside the graph. - private Point2I mousePosition; - /// True if the mouse is inside the graph. - private bool isMouseOver; - - #endregion - - #region Constructors - - /// Constructs the . - public FileGraphViewModel(SettingsService settings, - TreemapRendererFactory treemapFactory, - UIService ui) - { - Settings = settings; - Treemap = treemapFactory.Create(); - UI = ui; - - Settings.PropertyChanged += OnSettingsPropertyChanged; - - resizeTimer = UI.CreateTimer(TimeSpan.FromSeconds(0.05), true, OnResizeTick); - } - - #endregion - - #region Events Handlers - - private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - case nameof(SettingsService.TreemapOptions): - case nameof(SettingsService.FilePalette): - RenderAsync(); - break; - case nameof(SettingsService.HighlightColor): - if (highlightMode != HighlightMode.None) - RenderHighlight(treemapSize); - break; - case nameof(SettingsService.RenderPriority): - if (renderThread != null && renderThread.IsAlive) - renderThread.Priority = Settings.RenderPriority; - break; - } - } - - private void OnResizeTick() { - - } - - #endregion - - #region Private Properties - - /// Gets if anything is in the process of being rendered. - private bool IsRendering => renderThread?.IsAlive ?? false; - /// Gets if the treemap is in the process of being rendered. - private bool IsRenderingTreemap => renderThread?.IsAlive ?? false && fullRender; - - /// Gets the treemap highlight color. - private Rgba32Color Options => Settings.HighlightColor; - - #endregion - - #region Properties - - #endregion - - #region Rendering - - private void UpdateDimmed() { - IsDimmed = IsRenderingTreemap || resizing || !IsEnabled; - } - - /// Clears the current render. - private void Clear() { - AbortRender(); - treemap = null; - highlight = null; - treemapSize = Point2I.Zero; - highlightSize = Point2I.Zero; - } - - /// Aborts the current render in progress. - public void AbortRender(bool waitForExit = true) { - if (renderThread != null) { - renderThread.Abort(); - renderThread = null; - UpdateDimmed(); - } - } - - private void RenderHighlightAsync() { - fullRender = !treemapRendered; - RenderAsyncImpl(); - } - - private void RenderAsync() { - fullRender = true; - RenderAsyncImpl(); - } - - private void RenderAsyncImpl() { - if (IsEnabled && rootItem != null) { - AbortRender(); - treemapRendered = false; - //IsDimmed = true; - Point2I size = new Point2I((int) ActualWidth, (int) ActualHeight); - renderThread = new Thread(() => RenderThread(size)) { - Priority = Settings.RenderPriority, - Name = "File GraphView Render", - }; - renderThread.Start(); - UpdateDimmed(); - } - } - - private void RenderThread(Point2I size) { - try { - if (size.X != 0 && size.Y != 0) { - if (fullRender) { - RenderTreemap(size); - } - treemapRendered = true; - if (highlightMode != HighlightMode.None) { - RenderHighlight(size); - } - } - UI.Invoke(() => { - // Let the control know we're not rendering anymore - renderThread = null; - imageTreemap.Source = treemap; - if (highlightMode != HighlightMode.None) - imageHighlight.Source = highlight; - UpdateDimmed(); - }); - } - catch (ThreadAbortException) { } - catch (Exception ex) { - Stopwatch sw = Stopwatch.StartNew(); - UI.Invoke(() => { - Console.WriteLine(ex.ToString()); - renderThread = null; - UpdateDimmed(); - UpdateHover(); - }); - Console.WriteLine($"Took {sw.ElapsedMilliseconds}ms to invoke EXCEPTION Dispatcher"); - } - } - - private void RenderTreemap(Point2I size) { - Stopwatch sw = Stopwatch.StartNew(); - if (treemap == null || treemapSize.X != size.X || treemapSize.Y != size.Y) { - treemapSize = size; - UI.Invoke(() => { - treemap = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); - }); - } - Treemap.DrawTreemap(treemap, new Rectangle2I(size), rootItem); - //Treemap.DrawTreemap(treemap, new Rectangle2I(size), fileRoot, options); - Console.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render treemap"); - } - private void RenderHighlight(Point2I size) { - Stopwatch sw = Stopwatch.StartNew(); - if (highlight == null || highlightSize.X != size.X || highlightSize.Y != size.Y) { - highlightSize = size; - UI.Invoke(() => { - highlight = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); - }); - Trace.WriteLine($"Took {sw.ElapsedMilliseconds}ms to setup highlight bitmap"); - } - sw.Restart(); - if (highlightMode == HighlightMode.Extension) { - Treemap.HighlightExtensions(highlight, new Rectangle2I(size), rootItem, Settings.HighlightColor, extension); - } - else if (highlightMode == HighlightMode.Selection) { - Treemap.HighlightItems(highlight, new Rectangle2I(size), Settings.HighlightColor, selection); - } - Trace.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render highlight"); - Trace.WriteLine(""); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/Graph/GraphViewModel.cs b/WinDirStat.Net.Wpf.Base/ViewModel/Graph/GraphViewModel.cs deleted file mode 100644 index b29ad0d..0000000 --- a/WinDirStat.Net.Wpf.Base/ViewModel/Graph/GraphViewModel.cs +++ /dev/null @@ -1,419 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using GalaSoft.MvvmLight; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Rendering; -using WinDirStat.Net.Services; -using WinDirStat.Net.Structures; - -namespace WinDirStat.Net.ViewModel.Graph { - /// The base view model for a treemap display. - public partial class GraphViewModel : ViewModelBase { - - #region Private Enums - - /// The modes for highlighting the graph view. - protected enum HighlightMode { - None, - Extension, - Selection, - } - - #endregion - - #region Fields - - private readonly object volatileLock = new object(); - - private readonly SettingsService settings; - private readonly TreemapRenderer treemap; - private readonly UIService ui; - - - private Point2I treemapSize; - private Point2I highlightSize; - - private WriteableBitmap treemapImage; - private WriteableBitmap highlightImage; - private WriteableBitmap disabledTreemapImage; - private WriteableBitmap disabledHighlightImage; - - private ImageSource treemapDisplayImage; - private ImageSource highlightDisplayImage; - - private Point2I dimensions; - - - /// The root treemap item. - private volatile ITreemapItem rootItem; - - // Hover - /// The hovered treemap item. - private ITreemapItem hoverItem; - /// The current mouse position of inside the graph. - private Point2I mousePosition; - /// True if the mouse is inside the graph. - private bool isMouseOver; - - // Highlight - /// The selected treemap items to highlight. - private ITreemapItem[] selection; - /// The extension to highlight. - private string extension; - /// The current mode for highlighting. - private HighlightMode highlightMode; - - // Display - /// True if the graph is currently dimmed. - private volatile bool isDimmed; - /// True if the graph is enabled. - private volatile bool isEnabled; - - // Rendering - /// True if rendering should be done on a separate thread. - private bool renderAsynchronously; - /// True if the running render thread has finished rendering the treemap. - private volatile bool treemapRendered; - /// True if the running render thread is rendering the treemap. - private volatile bool fullRender; - /// True if resizing is in progress. - private volatile bool resizing; - /// The timer to delay rendering while resizing. - private readonly UITimer resizeTimer; - /// The thread where the asynchronous rendering is done. - private Thread renderThread; - - private Rgb24Color highlightColor; - - #endregion - - #region Constructors - - /// Constructs the . - public GraphViewModel(SettingsService settings, - TreemapRendererFactory treemapFactory, - UIService ui) - { - this.settings = settings; - treemap = treemapFactory.Create(); - this.ui = ui; - - this.settings.PropertyChanged += OnSettingsPropertyChanged; - - resizeTimer = this.ui.CreateTimer(TimeSpan.FromSeconds(0.05), true, OnResizeTick); - isEnabled = true; - } - - #endregion - - #region Events Handlers - - private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - /*case nameof(SettingsService.TreemapOptions): - case nameof(SettingsService.FilePalette): - Render(); - break; - case nameof(SettingsService.HighlightColor): - if (highlightMode != HighlightMode.None) - RenderHighlight(treemapSize); - break;*/ - case nameof(SettingsService.RenderPriority): - ui.Invoke(() => { - if (renderThread != null && renderThread.IsAlive) - renderThread.Priority = settings.RenderPriority; - }); - break; - } - } - - private void OnResizeTick() { - - } - - #endregion - - #region Private Properties - - /// Gets if anything is in the process of being rendered. - private bool IsRenderingAsync => renderThread?.IsAlive ?? false; - /// Gets if the treemap is in the process of being rendered. - private bool IsRenderingTreemap => renderThread?.IsAlive ?? false && fullRender; - - /// Gets or sets the treemap highlight color. - public Rgba32Color HighlightColor { - get => highlightColor; - set => Set(ref highlightColor, value); - } - - #endregion - - #region Properties - - /// Gets if the graph view should be dimmed due to rendering or being disabled. - public bool IsDimmed { - get => isDimmed; - protected set { - if (isDimmed != value) { - isDimmed = value; - - if (isDimmed) - HoverItem = null; - else if (isMouseOver) - UpdateHover(); - - RaisePropertyChanged(); - } - } - } - - /// Gets if the graph view is visually enabled. - public bool IsEnabled { - get => isEnabled; - private set { - if (isEnabled != value) { - isEnabled = value; - UpdateDimmed(); - if (!isEnabled) { - AbortRender(); - disabledTreemapImage = treemapImage; - disabledHighlightImage = highlightImage; - TreemapImage = disabledTreemapImage; - HighlightImage = disabledHighlightImage; - } - else { - disabledTreemapImage = null; - disabledHighlightImage = null; - RaisePropertyChanged(nameof(TreemapImage)); - // GraphView will render if (!IsEnabled and RootItem != null) - Render(); - } - RaisePropertyChanged(); - } - } - } - - /// Gets or sets the dimensions of the graph view. - public Point2I Dimensions { - get => dimensions; - set => Set(ref dimensions, value); - } - - /// Gets or sets the current mouse position inside the graph. - public Point2I MousePosition { - get => mousePosition; - set => Set(ref mousePosition, value); - } - - /// ets or sets if the mouse is inside the graph. - public bool IsMouseOver { - get => isMouseOver; - set => Set(ref isMouseOver, value); - } - - /// Gets the image to display the treemap. - public ImageSource TreemapImage { - get => treemapDisplayImage; - private set => Set(ref treemapDisplayImage, value); - } - - /// Gets the image to display the highlight. - public ImageSource HighlightImage { - get => highlightDisplayImage; - private set => Set(ref highlightDisplayImage, value); - } - - public ITreemapItem HoverItem { - get => hoverItem; - set => Set(ref hoverItem, value); - } - - public ITreemapItem RootItem { - get => rootItem; - set { - if (rootItem != value) { - rootItem = value; - - if (rootItem == null) { - AbortRender(); - } - - HighlightNone(); - HoverItem = null; - if (rootItem != null) - Render(); - else - Clear(); - - RaisePropertyChanged(); - } - } - } - - #endregion - - #region Rendering - - public void Refresh() { - Render(); - } - - private void Render() { - if (renderAsynchronously) - RenderAsyncImpl(); - else - RenderImpl(); - } - - private void RenderHighlight() { - fullRender = !treemapRendered; - if (IsRenderingAsync) { - RenderAsyncImpl(); - } - else if (!isDimmed && rootItem != null) { - RenderImpl(); - } - } - - /// Updates the dimmed settings. - private void UpdateDimmed() { - IsDimmed = IsRenderingTreemap || resizing || !IsEnabled; - } - - /// Clears the current render. - private void Clear() { - AbortRender(); - treemapImage = null; - highlightImage = null; - treemapSize = Point2I.Zero; - highlightSize = Point2I.Zero; - } - - /// Aborts the current render in progress. - public void AbortRender(bool waitForExit = true) { - if (renderThread != null) { - renderThread.Abort(); - renderThread = null; - UpdateDimmed(); - } - } - - private void RenderImpl() { - if (IsEnabled && rootItem != null) { - AbortRender(); - treemapRendered = false; - Point2I size = dimensions; - renderThread = null; - RenderThread(size); - } - } - - private void RenderAsyncImpl() { - if (IsEnabled && rootItem != null) { - AbortRender(); - treemapRendered = false; - //IsDimmed = true; - Point2I size = dimensions; - renderThread = new Thread(() => RenderThread(size)) { - Priority = settings.RenderPriority, - Name = "File GraphView Render", - }; - renderThread.Start(); - UpdateDimmed(); - } - } - - private void RenderThread(Point2I size) { - try { - if (size.X != 0 && size.Y != 0) { - if (fullRender) { - RenderTreemap(size); - } - treemapRendered = true; - if (highlightMode != HighlightMode.None) { - RenderHighlight(size); - } - } - ui.Invoke(() => { - // Let the control know we're not rendering anymore - renderThread = null; - TreemapImage = treemapImage; - if (highlightMode != HighlightMode.None) - HighlightImage = highlightImage; - UpdateDimmed(); - }); - } - catch (ThreadAbortException) { } - catch (Exception ex) { - Stopwatch sw = Stopwatch.StartNew(); - ui.Invoke(() => { - Console.WriteLine(ex.ToString()); - renderThread = null; - UpdateDimmed(); - UpdateHover(); - }); - Console.WriteLine($"Took {sw.ElapsedMilliseconds}ms to invoke EXCEPTION Dispatcher"); - } - } - - private void RenderTreemap(Point2I size) { - Stopwatch sw = Stopwatch.StartNew(); - if (treemapImage == null || treemapSize.X != size.X || treemapSize.Y != size.Y) { - treemapSize = size; - ui.Invoke(() => { - treemapImage = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); - }); - } - treemap.DrawTreemap(treemapImage, new Rectangle2I(size), rootItem); - //Treemap.DrawTreemap(treemap, new Rectangle2I(size), fileRoot, options); - Console.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render treemap"); - } - private void RenderHighlight(Point2I size) { - Stopwatch sw = Stopwatch.StartNew(); - if (highlightImage == null || highlightSize.X != size.X || highlightSize.Y != size.Y) { - highlightSize = size; - ui.Invoke(() => { - highlightImage = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); - }); - Trace.WriteLine($"Took {sw.ElapsedMilliseconds}ms to setup highlight bitmap"); - } - sw.Restart(); - if (highlightMode == HighlightMode.Extension) { - treemap.HighlightExtensions(highlightImage, new Rectangle2I(size), (FileItemBase) rootItem, settings.HighlightColor, extension); - } - else if (highlightMode == HighlightMode.Selection) { - treemap.HighlightItems(highlightImage, new Rectangle2I(size), settings.HighlightColor, selection); - } - Trace.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render highlight"); - Trace.WriteLine(""); - } - - #endregion - - #region Hover - - private void UpdateHover() { - if (rootItem == null) { - HoverItem = null; - return; - } - if (hoverItem != null) { - Rectangle2I rc = HoverItem.Rectangle; - if (rc.Contains(mousePosition)) - return; // Hover is the same - } - HoverItem = TreemapRenderer.FindItemAtPoint(rootItem, mousePosition); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/MainViewModel.Commands.cs b/WinDirStat.Net.Wpf.Base/ViewModel/MainViewModel.Commands.cs index b5f6c90..5153f5c 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/MainViewModel.Commands.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/MainViewModel.Commands.cs @@ -1,21 +1,14 @@ -using System; +using Microsoft.Toolkit.Mvvm.Input; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; +using System.Threading.Tasks; using System.Windows; -using System.Windows.Input; -using System.Windows.Media; using WinDirStat.Net.Model.Drives; using WinDirStat.Net.Model.Files; using WinDirStat.Net.Services; -using WinDirStat.Net.ViewModel.Commands; -namespace WinDirStat.Net.ViewModel { - partial class MainViewModel { +namespace WinDirStat.Net.ViewModel { + partial class MainViewModel { #region File Menu @@ -145,7 +138,7 @@ private void OnClose() { private void OnCancel() { Scanning.Cancel(false); } - private void OnElevate() { + private async void OnElevate() { // Dialog warn progress will be lost. // If yes, close then start new process. MessageBoxResult result = MessageBoxResult.Yes; @@ -158,16 +151,16 @@ private void OnElevate() { try { OS.StartNewElevated(); UI.Shutdown(); - Dispose(); + await DisposeAsync(); } catch { Dialogs.ShowError(WindowOwner, "Failed to start elevated process!", "Error"); } } } - private void OnExit() { + private async void OnExit() { UI.Shutdown(); - Dispose(); + await DisposeAsync(); } #endregion diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/MainViewModel.Methods.cs b/WinDirStat.Net.Wpf.Base/ViewModel/MainViewModel.Methods.cs index 8a20847..87d3399 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/MainViewModel.Methods.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/MainViewModel.Methods.cs @@ -1,78 +1,73 @@ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; +using System.Threading.Tasks; +using System.Windows; using WinDirStat.Net.Services; using WinDirStat.Net.Utils; namespace WinDirStat.Net.ViewModel { - partial class MainViewModel { - - public void Loaded() { - } - - public void SortFiles() { - SuppressFileTreeRefresh = true; - RootItem?.Sort(FileComparer.Compare); - SuppressFileTreeRefresh = false; - } - - public void SortExtensions() { - Extensions.Sort(ExtensionComparer.Compare); - } - - public void ActivateItem() { - // TODO: Determine the default action for each item type - } - - public void UpdateEmptyRecycleBin() { - UpdateEmptyRecycleBin(false); - } - public void UpdateEmptyRecycleBin(bool force) { - lock (recycleLock) { - if ((recycleInfoThread == null || !recycleInfoThread.IsAlive) && - (lastRecycleWatch == null || lastRecycleWatch.Elapsed > TimeSpan.FromSeconds(1)) || force) { - recycleInfoThread = new Thread(UpdateEmptyRecycleBinThread) { - Name = "Update Recycle Bin Info", - }; - recycleInfoThread.Start(); - } - } - } - private void UpdateEmptyRecycleBinThread() { - Debug.WriteLine("UpdateEmptyRecycleBin"); - RecycleBinInfo info = OS.GetAllRecycleBinInfo(); - string label = "Empty Recycle Bins"; - if (info != null) { - label += " ("; - if (info.ItemCount == 0 && info.Size == 0) { - label += "Empty"; - } - else { - label += $"{info.ItemCount:N0} "; - if (info.ItemCount == 1) - label += $"Item"; - else - label += $"Items"; - label += $", {FormatBytes.Format(info.Size)}"; - } - label += ")"; - } - EmptyRecycleBinLabel = label; - allRecycleBinInfo = info; - EmptyRecycleBin.RaiseCanExecuteChanged(); - if (lastRecycleWatch == null) - lastRecycleWatch = Stopwatch.StartNew(); - else - lastRecycleWatch.Restart(); - } - - public void WindowShown() { - Open.Execute(); - } - } + partial class MainViewModel { + + public void Loaded() { + } + + public void SortFiles() { + SuppressFileTreeRefresh = true; + RootItem?.Sort(FileComparer.Compare); + SuppressFileTreeRefresh = false; + } + + public void SortExtensions() { + Extensions.Sort(ExtensionComparer.Compare); + } + + public void ActivateItem() { + // TODO: Determine the default action for each item type + } + + public void UpdateEmptyRecycleBin() { + UpdateEmptyRecycleBin(false); + } + + public void UpdateEmptyRecycleBin(bool force) { + if (!ReadyForUpdate()) + return; + + recycleInfoTask = Task.Run(UpdateEmptyRecycleBinThread); + return; + + bool NotAlreadyRunning() => recycleInfoTask?.IsCompleted ?? true; + bool TimerIsReady() => lastRecycleWatch == null || lastRecycleWatch.Elapsed > TimeSpan.FromSeconds(1); + bool ReadyForUpdate() => force || (NotAlreadyRunning() && TimerIsReady()); + } + private void UpdateEmptyRecycleBinThread() { + Debug.WriteLine("UpdateEmptyRecycleBin"); + RecycleBinInfo info = OS.GetAllRecycleBinInfo(); + string label = "Empty Recycle Bins"; + if (info != null) { + label += " ("; + if (info.ItemCount == 0 && info.Size == 0) { + label += "Empty"; + } + else { + label += $"{info.ItemCount:N0} "; + if (info.ItemCount == 1) + label += $"Item"; + else + label += $"Items"; + label += $", {FormatBytes.Format(info.Size)}"; + } + label += ")"; + } + EmptyRecycleBinLabel = label; + allRecycleBinInfo = info; + Application.Current.Dispatcher.Invoke(EmptyRecycleBin.NotifyCanExecuteChanged); + lastRecycleWatch ??= new Stopwatch(); + lastRecycleWatch.Restart(); + } + + public void WindowShown() { + Open.Execute(); + } + } } diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/MainViewModel.cs b/WinDirStat.Net.Wpf.Base/ViewModel/MainViewModel.cs index f44f7c6..da9b025 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/MainViewModel.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/MainViewModel.cs @@ -1,17 +1,11 @@ using System; -using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; -using System.IO; using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; using System.Threading; -using System.Threading.Tasks; -using System.Windows.Input; -using GalaSoft.MvvmLight; +using System.Threading.Tasks; using WinDirStat.Net.Model.Files; using WinDirStat.Net.Rendering; using WinDirStat.Net.Services; @@ -20,373 +14,378 @@ using WinDirStat.Net.ViewModel.Extensions; using WinDirStat.Net.ViewModel.Files; -namespace WinDirStat.Net.ViewModel { - /// The main view model for the program. - public partial class MainViewModel : ViewModelWindow { - - #region Fields - - public SettingsService Settings { get; } - public ScanningService Scanning { get; } - public IconCacheService IconCache { get; } - public UIService UI { get; } - public BitmapFactory BitmapFactory { get; } - /// Gets the images service. - public ImagesServiceBase Images { get; } - public ClipboardService Clipboard { get; } - public OSService OS { get; } - public IMyDialogService Dialogs { get; } - public TreemapRenderer Treemap { get; } - - public ExtensionItemViewModelCollection Extensions { get; } - - public ObservableCollection SelectedFiles { get; } - public FileItemViewModel SelectedFile { get; private set; } - private ExtensionItemViewModel selectedExtension; - - public FileComparer FileComparer { get; } - public ExtensionComparer ExtensionComparer { get; } - - private long gcRAMUsage; - private FileItemViewModel rootItem; - private RootItem graphViewRootItem; - private readonly UITimer ramTimer; - private readonly UITimer statusTimer; - - private RecycleBinInfo allRecycleBinInfo; - private string emptyRecycleBinLabel; - - private bool suppressRefresh; - - private Thread recycleInfoThread; - - private readonly object recycleLock = new object(); - - private Stopwatch lastRecycleWatch; - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the MainViewModel class. - /// - public MainViewModel(SettingsService settings, - ScanningService scanning, - IconCacheService iconCache, - UIService ui, - BitmapFactory bitmapFactory, - ImagesServiceBase images, - ClipboardService clipboard, - OSService os, - IMyDialogService dialogs, - TreemapRendererFactory treemapFactory, - RelayCommandFactory relayFactory) - : base(relayFactory) - { - Settings = settings; - Scanning = scanning; - IconCache = iconCache; - UI = ui; - BitmapFactory = bitmapFactory; - Images = images; - Clipboard = clipboard; - OS = os; - Dialogs = dialogs; - Treemap = treemapFactory.Create(); - - Settings.PropertyChanged += OnSettingsPropertyChanged; - Scanning.PropertyChanged += OnScanningPropertyChanged; - - Extensions = new ExtensionItemViewModelCollection(this); - - SelectedFiles = new ObservableCollection(); - SelectedFiles.CollectionChanged += OnSelectedFilesChanged; - - FileComparer = new FileComparer(); - ExtensionComparer = new ExtensionComparer(); - UpdateEmptyRecycleBin(); - - GCRAMUsage = GC.GetTotalMemory(false); - if (IsInDesignMode) { - // Code runs in Blend --> create design time data. - } - else { - // Code runs "for real" - ramTimer = UI.StartTimer(Settings.RAMInterval, true, OnRAMUsageTick); - statusTimer = UI.CreateTimer(Settings.StatusInterval, true, OnStatusTick); - } - } - - #endregion - - #region Properties - - /// Gets the title to display for the window. - public override string Title { - get { - string title = "WinDirStat.Net"; - if (Scanning.ProgressState != ScanProgressState.NotStarted) { - var paths = Scanning.RootPaths.Select(p => PathUtils.TrimSeparatorEnd(p)); - title = $"{string.Join("|", paths)} - {title}"; - } - if (OS.IsElevated) - title += " (Administrator)"; - return title; - } - } - - /// Gets the Garbage Collector's RAM Usage. - public long GCRAMUsage { - get => gcRAMUsage; - set => Set(ref gcRAMUsage, value); - } - - /// Gets the root file tree item. - public FileItemViewModel RootItem { - get => rootItem; - private set { - if (rootItem != value) { - if (rootItem != null) { - SuppressFileTreeRefresh = true; - rootItem.IsExpanded = false; - SuppressFileTreeRefresh = false; - rootItem.Dispose(); - } - rootItem = value; - RaisePropertyChanged(); - } - } - } - - /// Gets treemap's root file tree item. - public RootItem GraphViewRootItem { - get => graphViewRootItem; - private set => Set(ref graphViewRootItem, value); - } - - #endregion - - #region ScanProperties - - /// Gets if a scan operation is in progress. - public bool IsScanning => Scanning.IsScanning; - /// Gets if a refresh operation is in progress. - public bool IsRefreshing => Scanning.IsRefreshing; - /// Gets if a scan is finished and open. - public bool IsOpen => Scanning.IsOpen; - /// Gets the scan time. - public TimeSpan ScanTime => Scanning.ScanTime; - /// Gets the scan progress. - public double ScanProgress => Scanning.Progress; - /// Gets if scan progress can be displayed. - public bool CanDisplayScanProgress => Scanning.CanDisplayProgress; - - /// Gets or sets if the current scan operation is suspended. - public bool IsScanSuspended { - get => Scanning.IsSuspended; - set => Scanning.IsSuspended = value; - } - - ///Gets if the file list has a selection. - public bool HasFileSelection => SelectedFile != null; - - ///Gets the file type list selection. - public ExtensionItemViewModel SelectedExtension { - get => selectedExtension; - set { - if (selectedExtension != value) { - bool hasSelectionChanged = ((selectedExtension == null) != (value == null)); - selectedExtension = value; - RaisePropertyChanged(); - if (hasSelectionChanged) - RaisePropertyChanged(nameof(HasExtensionSelection)); - } - } - } - - ///Gets if the file type list has a selection. - public bool HasExtensionSelection => selectedExtension != null; - - /// Gets the label to display for the empty recycle bin command. - public string EmptyRecycleBinLabel { - get => emptyRecycleBinLabel; - private set => Set(ref emptyRecycleBinLabel, value); - } - - /// Gets if the UI refreshing should be supressed due to validation. - public bool SuppressFileTreeRefresh { - get => suppressRefresh || Scanning.SuppressFileTreeRefresh; - private set { - if (suppressRefresh != value) { - suppressRefresh = value; - if (!Scanning.SuppressFileTreeRefresh) { - if (!suppressRefresh) - RootItem?.RaiseChildrenReset(); - RaisePropertyChanged(nameof(SuppressFileTreeRefresh)); - } - } - } - } - - #endregion - - #region Visibility Properties - - /// Gets if the file types list should be hidden. - public bool HideFileTypes { - get => (!Settings.ShowFileTypes || (!Scanning.IsRefreshing && !Scanning.IsOpen)) && !IsInDesignMode; - } - /// Gets if the treemap view should be hidden. - public bool HideTreemap { - get => (!Settings.ShowTreemap || (!Scanning.IsRefreshing && !Scanning.IsOpen)) && !IsInDesignMode; - } - /// Gets if the toolbar should be hidden. - public bool HideToolBar => !Settings.ShowToolBar && !IsInDesignMode; - /// Gets if the status bar should be hidden. - public bool HideStatusBar => !Settings.ShowStatusBar && !IsInDesignMode; - /// Gets if the graph view is enabled and able to refres. - public bool GraphViewEnabled => Settings.ShowTreemap && !Scanning.IsRefreshing && Scanning.IsOpen; - /// - /// Gets if the elevate command should be hidden due to the process already being elevated. - /// - public bool HideElevateCommand => OS.IsElevated; - - #endregion - - #region Event Handlers - - private void OnRAMUsageTick() { - GCRAMUsage = GC.GetTotalMemory(false); - } - - private void OnStatusTick() { - RaisePropertyChanged(nameof(ScanTime)); - RaisePropertyChanged(nameof(ScanProgress)); - } - - private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e) { - UI.Invoke(() => { - switch (e.PropertyName) { - case nameof(SettingsService.RAMInterval): - ramTimer.Interval = Settings.RAMInterval; - break; - case nameof(SettingsService.StatusInterval): - statusTimer.Interval = Settings.StatusInterval; - break; - case nameof(SettingsService.ShowFileTypes): - RaisePropertyChanged(nameof(HideFileTypes)); - break; - case nameof(SettingsService.ShowTreemap): - RaisePropertyChanged(nameof(HideTreemap)); - RaisePropertyChanged(nameof(GraphViewEnabled)); - break; - case nameof(SettingsService.ShowToolBar): - RaisePropertyChanged(nameof(HideToolBar)); - break; - case nameof(SettingsService.ShowStatusBar): - RaisePropertyChanged(nameof(HideStatusBar)); - break; - } - }); - } - - private void OnScanningPropertyChanged(object sender, PropertyChangedEventArgs e) { - UI.Invoke(() => { - switch (e.PropertyName) { - case nameof(ScanningService.RootItem): - if (Scanning.RootItem == null) { - GraphViewRootItem = null; - RootItem = null; - } - else { - RootItem = new FileItemViewModel(this, Scanning.RootItem); - } - break; - case nameof(ScanningService.ProgressState): - switch (Scanning.ProgressState) { - case ScanProgressState.Starting: - //GraphViewRootItem = null; - break; - case ScanProgressState.Started: - statusTimer.Start(); - break; - case ScanProgressState.Ending: - statusTimer.Stop(); - break; - case ScanProgressState.Ended: - Extensions.Sort(ExtensionComparer.Compare); - GraphViewRootItem = Scanning.RootItem; - break; - case ScanProgressState.NotStarted: - GraphViewRootItem = null; - RootItem?.Dispose(); - RootItem = null; - //UpdateEmptyRecycleBin(); - break; - } - RaisePropertyChanged(nameof(Title)); - RaisePropertyChanged(nameof(ScanProgress)); - break; - case nameof(ScanningService.ScanState): - RaisePropertyChanged(nameof(HideFileTypes)); - RaisePropertyChanged(nameof(HideTreemap)); - RaisePropertyChanged(nameof(HideToolBar)); - RaisePropertyChanged(nameof(HideStatusBar)); - break; - case nameof(ScanningService.ScanTime): - RaisePropertyChanged(nameof(ScanTime)); - break; - case nameof(ScanningService.Progress): - RaisePropertyChanged(nameof(ScanProgress)); - break; - case nameof(ScanningService.CanDisplayProgress): - RaisePropertyChanged(nameof(CanDisplayScanProgress)); - break; - case nameof(ScanningService.IsOpen): - RaisePropertyChanged(nameof(IsOpen)); - RaisePropertyChanged(nameof(GraphViewEnabled)); - break; - case nameof(ScanningService.IsScanning): - RaisePropertyChanged(nameof(IsScanning)); - break; - case nameof(ScanningService.IsRefreshing): - RaisePropertyChanged(nameof(IsRefreshing)); - RaisePropertyChanged(nameof(GraphViewEnabled)); - //if (!Scanning.IsRefreshing) - // UpdateEmptyRecycleBin(); - break; - case nameof(ScanningService.SuppressFileTreeRefresh): - if (!suppressRefresh) { - RootItem?.RaiseChildrenReset(); - RaisePropertyChanged(nameof(SuppressFileTreeRefresh)); - } - break; - } - }); - } - - private void OnSelectedFilesChanged(object sender, NotifyCollectionChangedEventArgs e) { - FileItemViewModel newSelectedFile = SelectedFiles.FirstOrDefault(); - if (SelectedFile != newSelectedFile) { - SelectedFile = newSelectedFile; - RaisePropertyChanged(nameof(SelectedFile)); - if ((SelectedFile == null) != (newSelectedFile == null)) - RaisePropertyChanged(nameof(HasFileSelection)); - } - } - - #endregion - - #region IDisposable Implementation - - public void Dispose() { - Scanning.Dispose(); - statusTimer.Stop(); - ramTimer.Stop(); - } - - #endregion - - } +namespace WinDirStat.Net.ViewModel { + /// The main view model for the program. + public partial class MainViewModel : ViewModelWindow, IAsyncDisposable { + + #region Fields + + public SettingsService Settings { get; } + public ScanningService Scanning { get; } + public IconCacheService IconCache { get; } + public UIService UI { get; } + public BitmapFactory BitmapFactory { get; } + /// Gets the images service. + public ImagesServiceBase Images { get; } + public ClipboardService Clipboard { get; } + public OSService OS { get; } + public IMyDialogService Dialogs { get; } + public TreemapRenderer Treemap { get; } + + public ExtensionItemViewModelCollection Extensions { get; } + + public ObservableCollection SelectedFiles { get; } + public FileItemViewModel SelectedFile { get; private set; } + private ExtensionItemViewModel selectedExtension; + + public FileComparer FileComparer { get; } + public ExtensionComparer ExtensionComparer { get; } + + private long gcRAMUsage; + private FileItemViewModel rootItem; + private RootItem graphViewRootItem; + private readonly UITimer ramTimer; + private readonly UITimer statusTimer; + + private RecycleBinInfo allRecycleBinInfo; + private string emptyRecycleBinLabel; + + private bool suppressRefresh; + + private Task recycleInfoTask; + + private Stopwatch lastRecycleWatch; + + private bool disposed; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the MainViewModel class. + /// + public MainViewModel(SettingsService settings, + ScanningService scanning, + IconCacheService iconCache, + UIService ui, + BitmapFactory bitmapFactory, + ImagesServiceBase images, + ClipboardService clipboard, + OSService os, + IMyDialogService dialogs, + TreemapRendererFactory treemapFactory, + RelayCommandFactory relayFactory) + : base(relayFactory) { + Settings = settings; + Scanning = scanning; + IconCache = iconCache; + UI = ui; + BitmapFactory = bitmapFactory; + Images = images; + Clipboard = clipboard; + OS = os; + Dialogs = dialogs; + Treemap = treemapFactory.Create(); + + Settings.PropertyChanged += OnSettingsPropertyChanged; + Scanning.PropertyChanged += OnScanningPropertyChanged; + + Extensions = new ExtensionItemViewModelCollection(this); + + SelectedFiles = new ObservableCollection(); + SelectedFiles.CollectionChanged += OnSelectedFilesChanged; + + FileComparer = new FileComparer(); + ExtensionComparer = new ExtensionComparer(); + UpdateEmptyRecycleBin(); + + GCRAMUsage = GC.GetTotalMemory(false); + { + // Code runs "for real" + ramTimer = UI.StartTimer(Settings.RAMInterval, true, OnRAMUsageTick); + statusTimer = UI.CreateTimer(Settings.StatusInterval, true, OnStatusTick); + } + } + + #endregion + + #region Properties + + /// Gets the title to display for the window. + public override string Title { + get { + string title = "WinDirStat.Net"; + if (Scanning.ProgressState != ScanProgressState.NotStarted) { + var paths = Scanning.RootPaths.Select(p => PathUtils.TrimSeparatorEnd(p)); + title = $"{string.Join("|", paths)} - {title}"; + } + if (OS.IsElevated) + title += " (Administrator)"; + return title; + } + } + + /// Gets the Garbage Collector's RAM Usage. + public long GCRAMUsage { + get => gcRAMUsage; + set => SetProperty(ref gcRAMUsage, value); + } + + /// Gets the root file tree item. + public FileItemViewModel RootItem { + get => rootItem; + private set { + if (rootItem != value) { + if (rootItem != null) { + SuppressFileTreeRefresh = true; + rootItem.IsExpanded = false; + SuppressFileTreeRefresh = false; + rootItem.Dispose(); + } + rootItem = value; + OnPropertyChanged(); + } + } + } + + /// Gets treemap's root file tree item. + public RootItem GraphViewRootItem { + get => graphViewRootItem; + private set => SetProperty(ref graphViewRootItem, value); + } + + #endregion + + #region ScanProperties + + /// Gets if a scan operation is in progress. + public bool IsScanning => Scanning.IsScanning; + /// Gets if a refresh operation is in progress. + public bool IsRefreshing => Scanning.IsRefreshing; + /// Gets if a scan is finished and open. + public bool IsOpen => Scanning.IsOpen; + /// Gets the scan time. + public TimeSpan ScanTime => Scanning.ScanTime; + /// Gets the scan progress. + public double ScanProgress => Scanning.Progress; + /// Gets if scan progress can be displayed. + public bool CanDisplayScanProgress => Scanning.CanDisplayProgress; + + /// Gets or sets if the current scan operation is suspended. + public bool IsScanSuspended { + get => Scanning.IsSuspended; + set => Scanning.IsSuspended = value; + } + + ///Gets if the file list has a selection. + public bool HasFileSelection => SelectedFile != null; + + ///Gets the file type list selection. + public ExtensionItemViewModel SelectedExtension { + get => selectedExtension; + set { + if (selectedExtension != value) { + bool hasSelectionChanged = ((selectedExtension == null) != (value == null)); + selectedExtension = value; + OnPropertyChanged(); + if (hasSelectionChanged) + OnPropertyChanged(nameof(HasExtensionSelection)); + } + } + } + + ///Gets if the file type list has a selection. + public bool HasExtensionSelection => selectedExtension != null; + + /// Gets the label to display for the empty recycle bin command. + public string EmptyRecycleBinLabel { + get => emptyRecycleBinLabel; + private set => SetProperty(ref emptyRecycleBinLabel, value); + } + + /// Gets if the UI refreshing should be supressed due to validation. + public bool SuppressFileTreeRefresh { + get => suppressRefresh || Scanning.SuppressFileTreeRefresh; + private set { + if (suppressRefresh != value) { + suppressRefresh = value; + if (!Scanning.SuppressFileTreeRefresh) { + if (!suppressRefresh) + RootItem?.RaiseChildrenReset(); + OnPropertyChanged(nameof(SuppressFileTreeRefresh)); + } + } + } + } + + #endregion + + #region Visibility Properties + + /// Gets if the file types list should be hidden. + public bool HideFileTypes { + get => !Settings.ShowFileTypes || (!Scanning.IsRefreshing && !Scanning.IsOpen); + } + /// Gets if the treemap view should be hidden. + public bool HideTreemap { + get => !Settings.ShowTreemap || (!Scanning.IsRefreshing && !Scanning.IsOpen); + } + /// Gets if the toolbar should be hidden. + public bool HideToolBar => !Settings.ShowToolBar; + /// Gets if the status bar should be hidden. + public bool HideStatusBar => !Settings.ShowStatusBar; + /// Gets if the graph view is enabled and able to refres. + public bool GraphViewEnabled => Settings.ShowTreemap && !Scanning.IsRefreshing && Scanning.IsOpen; + /// + /// Gets if the elevate command should be hidden due to the process already being elevated. + /// + public bool HideElevateCommand => OS.IsElevated; + + #endregion + + #region Event Handlers + + private void OnRAMUsageTick() { + GCRAMUsage = GC.GetTotalMemory(false); + } + + private void OnStatusTick() { + OnPropertyChanged(nameof(ScanTime)); + OnPropertyChanged(nameof(ScanProgress)); + } + + private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e) { + UI.Invoke(() => { + switch (e.PropertyName) { + case nameof(SettingsService.RAMInterval): + ramTimer.Interval = Settings.RAMInterval; + break; + case nameof(SettingsService.StatusInterval): + statusTimer.Interval = Settings.StatusInterval; + break; + case nameof(SettingsService.ShowFileTypes): + OnPropertyChanged(nameof(HideFileTypes)); + break; + case nameof(SettingsService.ShowTreemap): + OnPropertyChanged(nameof(HideTreemap)); + OnPropertyChanged(nameof(GraphViewEnabled)); + break; + case nameof(SettingsService.ShowToolBar): + OnPropertyChanged(nameof(HideToolBar)); + break; + case nameof(SettingsService.ShowStatusBar): + OnPropertyChanged(nameof(HideStatusBar)); + break; + } + }); + } + + private void OnScanningPropertyChanged(object sender, PropertyChangedEventArgs e) { + UI.Invoke(() => { + switch (e.PropertyName) { + case nameof(ScanningService.RootItem): + if (Scanning.RootItem == null) { + GraphViewRootItem = null; + RootItem = null; + } + else { + RootItem = new FileItemViewModel(this, Scanning.RootItem); + } + break; + case nameof(ScanningService.ProgressState): + switch (Scanning.ProgressState) { + case ScanProgressState.Starting: + //GraphViewRootItem = null; + break; + case ScanProgressState.Started: + statusTimer.Start(); + break; + case ScanProgressState.Ending: + statusTimer.Stop(); + break; + case ScanProgressState.Ended: + Extensions.Sort(ExtensionComparer.Compare); + GraphViewRootItem = Scanning.RootItem; + break; + case ScanProgressState.NotStarted: + GraphViewRootItem = null; + RootItem?.Dispose(); + RootItem = null; + //UpdateEmptyRecycleBin(); + break; + } + OnPropertyChanged(nameof(Title)); + OnPropertyChanged(nameof(ScanProgress)); + break; + case nameof(ScanningService.ScanState): + OnPropertyChanged(nameof(HideFileTypes)); + OnPropertyChanged(nameof(HideTreemap)); + OnPropertyChanged(nameof(HideToolBar)); + OnPropertyChanged(nameof(HideStatusBar)); + break; + case nameof(ScanningService.ScanTime): + OnPropertyChanged(nameof(ScanTime)); + break; + case nameof(ScanningService.Progress): + OnPropertyChanged(nameof(ScanProgress)); + break; + case nameof(ScanningService.CanDisplayProgress): + OnPropertyChanged(nameof(CanDisplayScanProgress)); + break; + case nameof(ScanningService.IsOpen): + OnPropertyChanged(nameof(IsOpen)); + OnPropertyChanged(nameof(GraphViewEnabled)); + break; + case nameof(ScanningService.IsScanning): + OnPropertyChanged(nameof(IsScanning)); + break; + case nameof(ScanningService.IsRefreshing): + OnPropertyChanged(nameof(IsRefreshing)); + OnPropertyChanged(nameof(GraphViewEnabled)); + //if (!Scanning.IsRefreshing) + // UpdateEmptyRecycleBin(); + break; + case nameof(ScanningService.SuppressFileTreeRefresh): + if (!suppressRefresh) { + RootItem?.RaiseChildrenReset(); + OnPropertyChanged(nameof(SuppressFileTreeRefresh)); + } + break; + } + }); + } + + private void OnSelectedFilesChanged(object sender, NotifyCollectionChangedEventArgs e) { + FileItemViewModel newSelectedFile = SelectedFiles.FirstOrDefault(); + if (SelectedFile != newSelectedFile) { + SelectedFile = newSelectedFile; + OnPropertyChanged(nameof(SelectedFile)); + if ((SelectedFile == null) != (newSelectedFile == null)) + OnPropertyChanged(nameof(HasFileSelection)); + } + } + + #endregion + + #region IAsyncDisposable Implementation + + public async ValueTask DisposeAsync() { + if (disposed) + return; + + disposed = true; + await using (Scanning) { + statusTimer.Stop(); + ramTimer.Stop(); + } + + GC.SuppressFinalize(this); + } + + public async void Dispose() => await DisposeAsync(); + + #endregion + + } } diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/ViewModelRelayCommand.cs b/WinDirStat.Net.Wpf.Base/ViewModel/ViewModelRelayCommand.cs index c4cb6e2..6a1382d 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/ViewModelRelayCommand.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/ViewModelRelayCommand.cs @@ -1,135 +1,110 @@ -using System; +using Microsoft.Toolkit.Mvvm.ComponentModel; +using Microsoft.Toolkit.Mvvm.Input; +using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Windows.Input; -using GalaSoft.MvvmLight; using WinDirStat.Net.Services; -using WinDirStat.Net.ViewModel.Commands; -namespace WinDirStat.Net.ViewModel { - /// An addition to the class with extra helper functions. - public abstract class ViewModelRelayCommand : ViewModelBase { - - #region Fields - - /// The list of loaded commands. - private readonly Dictionary commands = new Dictionary(); - - private readonly RelayCommandFactory relayFactory; - - #endregion - - #region Constructors - - public ViewModelRelayCommand(RelayCommandFactory relayFactory) { - this.relayFactory = relayFactory; - } - - #endregion - - #region Properties - - /// Gets all commands created with . - public IEnumerable Commands => commands.Values; - - #endregion - - #region GetCommand (Basic) - - /// - /// Gets the commnd if one exists, or assigns the passed command. - /// - /// - /// The new command to assign if one does not exist. - /// The name of the command. - /// The command from the command list. - protected TCommand GetCommand(TCommand newCommand, - [CallerMemberName] string commandName = null) - where TCommand : ICommand - { - if (!commands.TryGetValue(commandName, out ICommand command)) { - command = newCommand; - commands.Add(commandName, command); - } - return (TCommand) command; - } - - /// - /// Gets the commnd if one exists, or assigns calls the specified create command function. - /// - /// - /// The function to create the new command if one does not exist. - /// The name of the command. - /// The command from the command list. - protected TCommand GetCommand(Func createCommand, - [CallerMemberName] string commandName = null) - where TCommand : ICommand - { - if (!commands.TryGetValue(commandName, out ICommand command)) { - command = createCommand(); - commands.Add(commandName, command); - } - return (TCommand) command; - } - - #endregion - - #region GetCommand (IRelayCommand) - - /// Gets or creates a new command with the specified parameters. - /// - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected IRelayCommand GetCommand(Action execute, bool keepTargetAlive = false, - [CallerMemberName] string commandName = null) - { - return GetCommand(execute, null, keepTargetAlive, commandName); - } - - /// Gets or creates a new command with the specified parameters. - /// - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected IRelayCommand GetCommand(Action execute, Func canExecute, - bool keepTargetAlive = false, [CallerMemberName] string commandName = null) - { - return GetCommand(() => relayFactory.Create(execute, canExecute, keepTargetAlive), commandName); - } - - #endregion - - #region GetCommand (IRelayCommand) - - /// Gets or creates a new command with the specified parameters. - /// - /// The parameter type of the command. - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected IRelayCommand GetCommand(Action execute, bool keepTargetAlive = false, - [CallerMemberName] string commandName = null) - { - return GetCommand(execute, null, keepTargetAlive, commandName); - } - - /// Gets or creates a new command with the specified parameters. - /// - /// The parameter type of the command. - /// The execute method for the command. - /// The optional canExecute method for the command. - /// The name of the command to get or set. - /// The existing or created command. - protected IRelayCommand GetCommand(Action execute, Func canExecute, - bool keepTargetAlive = false, [CallerMemberName] string commandName = null) - { - return GetCommand(() => relayFactory.Create(execute, canExecute, keepTargetAlive), commandName); - } - - #endregion - } +namespace WinDirStat.Net.ViewModel { + /// An addition to the class with extra helper functions. + public abstract class ViewModelRelayCommand : ObservableRecipient { + + #region Fields + + /// The list of loaded commands. + private readonly ConcurrentDictionary commands = new(); + + private readonly RelayCommandFactory relayFactory; + + #endregion + + #region Constructors + + public ViewModelRelayCommand(RelayCommandFactory relayFactory) { + this.relayFactory = relayFactory; + } + + #endregion + + #region Properties + + /// Gets all commands created with . + public IEnumerable Commands => commands.Values; + + #endregion + + #region GetCommand (Basic) + + /// + /// Gets the commnd if one exists, or assigns the passed command. + /// + /// + /// The new command to assign if one does not exist. + /// The name of the command. + /// The command from the command list. + protected TCommand GetCommand(TCommand newCommand, [CallerMemberName] string commandName = null) + where TCommand : ICommand + => (TCommand) commands.GetOrAdd(commandName, newCommand); + + /// + /// Gets the commnd if one exists, or assigns calls the specified create command function. + /// + /// + /// The function to create the new command if one does not exist. + /// The name of the command. + /// The command from the command list. + protected TCommand GetCommand(Func createCommand, [CallerMemberName] string commandName = null) + where TCommand : ICommand + => (TCommand) commands.GetOrAdd(commandName, _ => createCommand()); + + #endregion + + #region GetCommand (IRelayCommand) + + /// Gets or creates a new command with the specified parameters. + /// + /// The execute method for the command. + /// The optional canExecute method for the command. + /// The name of the command to get or set. + /// The existing or created command. + protected IRelayCommand GetCommand(Action execute, [CallerMemberName] string commandName = null) + => GetCommand(execute, null, commandName); + + /// Gets or creates a new command with the specified parameters. + /// + /// The execute method for the command. + /// The optional canExecute method for the command. + /// The name of the command to get or set. + /// The existing or created command. + protected IRelayCommand GetCommand(Action execute, Func canExecute, [CallerMemberName] string commandName = null) + => GetCommand(() => relayFactory.Create(execute, canExecute), commandName); + + #endregion + + #region GetCommand (IRelayCommand) + + /// Gets or creates a new command with the specified parameters. + /// + /// The parameter type of the command. + /// The execute method for the command. + /// The optional canExecute method for the command. + /// The name of the command to get or set. + /// The existing or created command. + protected IRelayCommand GetCommand(Action execute, [CallerMemberName] string commandName = null) + => GetCommand(execute, null, commandName); + + /// Gets or creates a new command with the specified parameters. + /// + /// The parameter type of the command. + /// The execute method for the command. + /// The optional canExecute method for the command. + /// The name of the command to get or set. + /// The existing or created command. + protected IRelayCommand GetCommand(Action execute, Predicate canExecute, [CallerMemberName] string commandName = null) + => GetCommand(() => relayFactory.Create(execute, canExecute), commandName); + + #endregion + } } diff --git a/WinDirStat.Net.Wpf.Base/ViewModel/ViewModelWindow.cs b/WinDirStat.Net.Wpf.Base/ViewModel/ViewModelWindow.cs index 928133c..b6181c6 100644 --- a/WinDirStat.Net.Wpf.Base/ViewModel/ViewModelWindow.cs +++ b/WinDirStat.Net.Wpf.Base/ViewModel/ViewModelWindow.cs @@ -1,16 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Windows; -using System.Windows.Input; -using System.Windows.Media; -using GalaSoft.MvvmLight; -using GalaSoft.MvvmLight.CommandWpf; +using System.Windows; using WinDirStat.Net.Services; -namespace WinDirStat.Net.ViewModel { - /// An addition to the class with extra helper functions. - public abstract class ViewModelWindow : ViewModelRelayCommand { +namespace WinDirStat.Net.ViewModel { + /// An addition to the class with extra helper functions. + public abstract class ViewModelWindow : ViewModelRelayCommand { #region Fields @@ -37,7 +30,7 @@ public ViewModelWindow(RelayCommandFactory relayFactory) : base(relayFactory) { /// Gets or sets the window owning this view model. public Window WindowOwner { get => windowOwner; - set => Set(ref windowOwner, value); + set => SetProperty(ref windowOwner, value); } #endregion diff --git a/WinDirStat.Net.Wpf.Base/WinDirStat.Net.Wpf.Base.csproj b/WinDirStat.Net.Wpf.Base/WinDirStat.Net.Wpf.Base.csproj index 3476f38..da4fe5e 100644 --- a/WinDirStat.Net.Wpf.Base/WinDirStat.Net.Wpf.Base.csproj +++ b/WinDirStat.Net.Wpf.Base/WinDirStat.Net.Wpf.Base.csproj @@ -1,101 +1,85 @@ - - - - net462 - WinDirStat.Net - true - latest - Debug;Release - - - - TRACE;DEBUG;WINDOWS;WPF - full - true - - - - TRACE;WINDOWS;WPF - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Native\Win32.cs - - - Rendering\TreemapRenderer.cs - - - Services\ScanningService.cs - - - Services\SettingsService.cs - - - ViewModel\DriveSelectViewModel.cs - - - ViewModel\MainViewModel.cs - - - ViewModel\Commands\RelayUICommand.cs - - - ViewModel\Files\FileItemViewModel.cs - - - - - - - - - - - - - - - - - - - - + + + net5.0-windows + WinDirStat.Net + true + latest + Debug;Release + true + + + TRACE;DEBUG;WINDOWS;WPF + full + true + + + TRACE;WINDOWS;WPF + + + + + + + + + + + + + + + + + + + + + all + + + + + + + + + + + Native\Win32.cs + + + Rendering\TreemapRenderer.cs + + + Services\ScanningService.cs + + + Services\SettingsService.cs + + + ViewModel\DriveSelectViewModel.cs + + + ViewModel\MainViewModel.cs + + + ViewModel\Commands\RelayUICommand.cs + + + ViewModel\Files\FileItemViewModel.cs + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WinDirStat.Net.Wpf.Single/App.xaml.cs b/WinDirStat.Net.Wpf.Single/App.xaml.cs index 51eda24..327e24a 100644 --- a/WinDirStat.Net.Wpf.Single/App.xaml.cs +++ b/WinDirStat.Net.Wpf.Single/App.xaml.cs @@ -1,94 +1,99 @@ using System; -using System.Collections.Generic; -using System.Configuration; using System.Globalization; using System.IO; -using System.Linq; using System.Reflection; -using System.Threading.Tasks; using System.Windows; using System.Windows.Media.Imaging; using WinDirStat.Net.Wpf.Windows; -namespace WinDirStat.Net.Wpf { - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application { - #region Constants - - private static readonly string[] assemblyExtensions = { ".dll", ".exe" }; - - #endregion - - #region Constructors - - /// - /// Constructs the app and sets up embedded assembly resolving. - /// - public App() { - AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssemblies; - // Call this to avoid referencing assemblies before the assembly resolver can be added. - Initialize(); - } - - /// - /// Called to avoid referencing assemblies before the assembly resolver can be added. - /// - private void Initialize() { - ErrorMessageBox.ProgramName = "WinDirStat.Net"; - ErrorMessageBox.HyperlinkName = "GitHub Page"; - ErrorMessageBox.HyperlinkUri = new Uri(@"https://github.com/trigger-death/WinDirStat.Net"); - ErrorMessageBox.ErrorIcon = new BitmapImage(new Uri("pack://application:,,,/Resources/App.ico")); - ErrorMessageBox.GlobalHook(this); - } - - #endregion - - #region Event Handlers - - /// - /// Resolves assemblies that may be embedded in the executable. - /// - private Assembly OnResolveAssemblies(object sender, ResolveEventArgs args) { - AssemblyName assemblyName = new AssemblyName(args.Name); - string assemblyPath; - - if (TryResolveAssembly(assemblyName, out Assembly assembly)) - return assembly; - assemblyPath = CultureInfo.CurrentCulture.TwoLetterISOLanguageName; - if (TryResolveAssembly(assemblyPath, assemblyName, out assembly)) - return assembly; - assemblyPath = CultureInfo.CurrentCulture.ToString(); - if (TryResolveAssembly(assemblyPath, assemblyName, out assembly)) - return assembly; - - return null; - } - - #endregion - - #region TryResolveAssembly - - private bool TryResolveAssembly(AssemblyName assemblyName, out Assembly assembly) { - return TryResolveAssembly(null, assemblyName, out assembly); - } - private bool TryResolveAssembly(string path, AssemblyName assemblyName, out Assembly assembly) { - foreach (string ext in assemblyExtensions) { - string startPath = Path.Combine(AppContext.BaseDirectory, "bin"); - if (path != null && !Path.IsPathRooted(path)) - startPath = Path.Combine(startPath, path); - - path = Path.Combine(startPath, assemblyName.Name + ext); - if (File.Exists(path)) { - assembly = Assembly.LoadFile(path); - return true; - } - } - assembly = null; - return false; - } - - #endregion - } +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + +namespace WinDirStat.Net.Wpf { + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application { + #region Constants + + private static readonly string[] assemblyExtensions = { ".dll", ".exe" }; + + #endregion + + #region Constructors + + /// + /// Constructs the app and sets up embedded assembly resolving. + /// + public App() { + AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssemblies; + // Call this to avoid referencing assemblies before the assembly resolver can be added. + Initialize(); + } + + /// + /// Called to avoid referencing assemblies before the assembly resolver can be added. + /// + private void Initialize() { + ErrorMessageBox.ProgramName = "WinDirStat.Net"; + ErrorMessageBox.HyperlinkName = "GitHub Page"; + ErrorMessageBox.HyperlinkUri = new Uri(@"https://github.com/trigger-death/WinDirStat.Net"); + ErrorMessageBox.ErrorIcon = new BitmapImage(new Uri("pack://application:,,,/Resources/App.ico")); + ErrorMessageBox.GlobalHook(this); + } + + #endregion + + #region Event Handlers + + /// + /// Resolves assemblies that may be embedded in the executable. + /// + private Assembly OnResolveAssemblies(object sender, ResolveEventArgs args) { + AssemblyName assemblyName = new AssemblyName(args.Name); + string assemblyPath; + + if (TryResolveAssembly(assemblyName, out Assembly assembly)) + return assembly; + assemblyPath = CultureInfo.CurrentCulture.TwoLetterISOLanguageName; + if (TryResolveAssembly(assemblyPath, assemblyName, out assembly)) + return assembly; + assemblyPath = CultureInfo.CurrentCulture.ToString(); + if (TryResolveAssembly(assemblyPath, assemblyName, out assembly)) + return assembly; + + return null; + } + + #endregion + + #region TryResolveAssembly + + private bool TryResolveAssembly(AssemblyName assemblyName, out Assembly assembly) { + return TryResolveAssembly(null, assemblyName, out assembly); + } + private bool TryResolveAssembly(string path, AssemblyName assemblyName, out Assembly assembly) { + foreach (string ext in assemblyExtensions) { + string startPath = Path.Combine(AppContext.BaseDirectory, "bin"); + if (path != null && !Path.IsPathRooted(path)) + startPath = Path.Combine(startPath, path); + + path = Path.Combine(startPath, assemblyName.Name + ext); + if (File.Exists(path)) { + assembly = Assembly.LoadFile(path); + return true; + } + } + assembly = null; + return false; + } + + #endregion + } } diff --git a/WinDirStat.Net.Wpf.Single/Commands/IRelayInfoCommand.cs b/WinDirStat.Net.Wpf.Single/Commands/IRelayInfoCommand.cs index 7129ad2..5b3d0d8 100644 --- a/WinDirStat.Net.Wpf.Single/Commands/IRelayInfoCommand.cs +++ b/WinDirStat.Net.Wpf.Single/Commands/IRelayInfoCommand.cs @@ -1,29 +1,22 @@ -using System; -using System.Collections.Generic; +using Microsoft.Toolkit.Mvvm.Input; using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; using System.Windows.Media; -using WinDirStat.Net.ViewModel; -using WinDirStat.Net.ViewModel.Commands; using WinDirStat.Net.Wpf.Input; -namespace WinDirStat.Net.Wpf.Commands { - public interface IRelayInfoCommand : IRelayCommandBase, INotifyPropertyChanged { - - #region Properties - - /// Gets or sets the UI specific info for the command. - RelayInfo Info { get; set; } - /// Gets the display text for the command. - string Text { get; } - /// Gets the display icon for the command. - ImageSource Icon { get; } - /// Gets the input gesture for the command. - AnyKeyGesture InputGesture { get; } - - #endregion - } +namespace WinDirStat.Net.Wpf.Commands { + public interface IRelayInfoCommand : IRelayCommand, INotifyPropertyChanged { + + #region Properties + + /// Gets or sets the UI specific info for the command. + RelayInfo Info { get; set; } + /// Gets the display text for the command. + string Text { get; } + /// Gets the display icon for the command. + ImageSource Icon { get; } + /// Gets the input gesture for the command. + AnyKeyGesture InputGesture { get; } + + #endregion + } } diff --git a/WinDirStat.Net.Wpf.Single/Commands/RelayInfo.cs b/WinDirStat.Net.Wpf.Single/Commands/RelayInfo.cs index 904051a..19fcf5b 100644 --- a/WinDirStat.Net.Wpf.Single/Commands/RelayInfo.cs +++ b/WinDirStat.Net.Wpf.Single/Commands/RelayInfo.cs @@ -7,7 +7,7 @@ using System.Windows; using System.Windows.Input; using System.Windows.Media; -using GalaSoft.MvvmLight; +using Microsoft.Toolkit.Mvvm.ComponentModel; using WinDirStat.Net.Wpf.Input; namespace WinDirStat.Net.Wpf.Commands { @@ -32,40 +32,40 @@ public partial class RelayInfo : ObservableObject { /// Gets the display the name of the command to assign this info to. public string Name { get => name; - set => Set(ref name, value); + set => SetProperty(ref name, value); } /// Gets the display text for the command. public string Text { get => text; - set => Set(ref text, value); + set => SetProperty(ref text, value); } /// Gets the display icon for the command. public ImageSource Icon { get => icon; - set => Set(ref icon, value); + set => SetProperty(ref icon, value); } /// Gets or sets the key for . public Key Key { get => key; set { - if (Set(ref key, value)) - RaisePropertyChanged(nameof(InputGesture)); + if (SetProperty(ref key, value)) + OnPropertyChanged(nameof(InputGesture)); } } /// Gets or sets the modifier keys for . public ModifierKeys Modifiers { get => modifiers; set { - if (Set(ref modifiers, value)) - RaisePropertyChanged(nameof(InputGesture)); + if (SetProperty(ref modifiers, value)) + OnPropertyChanged(nameof(InputGesture)); } } /// Gets or sets the override display text for . public string InputGestureDisplayText { get => inputGestureDisplayText; set { - if (Set(ref inputGestureDisplayText, value)) - RaisePropertyChanged(nameof(InputGesture)); + if (SetProperty(ref inputGestureDisplayText, value)) + OnPropertyChanged(nameof(InputGesture)); } } diff --git a/WinDirStat.Net.Wpf.Single/Commands/RelayInfoCollection.cs b/WinDirStat.Net.Wpf.Single/Commands/RelayInfoCollection.cs index 2071a19..0cf7997 100644 --- a/WinDirStat.Net.Wpf.Single/Commands/RelayInfoCollection.cs +++ b/WinDirStat.Net.Wpf.Single/Commands/RelayInfoCollection.cs @@ -5,19 +5,16 @@ using System.ComponentModel; using System.Linq; using System.Reflection; -using System.Text; -using System.Threading.Tasks; using System.Windows.Input; -using WinDirStat.Net.ViewModel.Commands; - -namespace WinDirStat.Net.Wpf.Commands { - /// - /// A collection for defining relay command infos in XAML. - /// - /// - /// Why is this not using the correct generic type you ask? Becaues the designer is shit. - /// - public class RelayInfoCollection : ObservableCollection { + +namespace WinDirStat.Net.Wpf.Commands { + /// + /// A collection for defining relay command infos in XAML. + /// + /// + /// Why is this not using the correct generic type you ask? Becaues the designer is shit. + /// + public class RelayInfoCollection : ObservableCollection { #region Fields diff --git a/WinDirStat.Net.Wpf.Single/Commands/RelayInfoCommand.Generic.cs b/WinDirStat.Net.Wpf.Single/Commands/RelayInfoCommand.Generic.cs index 6104407..8a19e88 100644 --- a/WinDirStat.Net.Wpf.Single/Commands/RelayInfoCommand.Generic.cs +++ b/WinDirStat.Net.Wpf.Single/Commands/RelayInfoCommand.Generic.cs @@ -1,141 +1,105 @@ -using System; -using System.Collections.Generic; +using Microsoft.Toolkit.Mvvm.Input; +using System; using System.ComponentModel; -using System.Linq; using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; using System.Windows.Media; -using GalaSoft.MvvmLight.CommandWpf; -using WinDirStat.Net.ViewModel; -using WinDirStat.Net.ViewModel.Commands; using WinDirStat.Net.Wpf.Input; -namespace WinDirStat.Net.Wpf.Commands { - public class RelayInfoCommand : RelayCommand, IRelayInfoCommand, IRelayCommand { - - #region Fields - - /// The UI specific info for the command. - private RelayInfo info; - - #endregion - - #region Constructors - - /// Constructs the . - /// - /// - /// The execution logic. IMPORTANT: If the action causes a closure, you must set to true to avoid side effects. - /// - /// - /// If true, the target of the Action will be kept as a hard reference, which might cause a memory - /// leak. You should only set this parameter to true if the action is causing a closures. - /// See http://galasoft.ch/s/mvvmweakaction. - /// - /// - /// is null. - public RelayInfoCommand(Action execute, bool keepTargetAlive = false) - : base(execute, null, keepTargetAlive) - { - } - - /// Constructs the . - /// - /// - /// The execution logic. IMPORTANT: If the action causes a closure, you must set to true to avoid side effects. - /// - /// - /// The execution status logic. IMPORTANT: If the func causes a closure, you must set to true to avoid side effects. - /// - /// - /// If true, the target of the Action will be kept as a hard reference, which might cause a memory - /// leak. You should only set this parameter to true if the action is causing a closures. - /// See http://galasoft.ch/s/mvvmweakaction. - /// - /// - /// is null. - public RelayInfoCommand(Action execute, Func canExecute, bool keepTargetAlive = false) - : base(execute, canExecute, keepTargetAlive) - { - } - - #endregion - - #region Properties - - /// Gets or sets the UI specific info for the command. - public RelayInfo Info { - get => info; - set { - if (info != value) { - if (info != null) - info.PropertyChanged -= OnInfoPropertyChanged; - info = value; - if (info != null) - info.PropertyChanged += OnInfoPropertyChanged; - RaisePropertyChanged(); - } - } - } - - /// Gets the display text for the command. - public string Text => info?.Text; - /// Gets the display icon for the command. - public ImageSource Icon => info?.Icon; - /// Gets the input gesture for the command. - public AnyKeyGesture InputGesture => info?.InputGesture; - - #endregion - - #region Events - - /// Called when a property has changed. - public event PropertyChangedEventHandler PropertyChanged; - - #endregion - - #region Execute - - /// Executes the method with a parameter. - public void Execute(T parameter) => Execute((object) parameter); - - #endregion - - #region Private PropertyChanged - - private void RaisePropertyChanged([CallerMemberName] string propertyName = null) { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - private bool Set(ref T2 field, T2 newValue, [CallerMemberName] string propertyName = null) { - if (EqualityComparer.Default.Equals(field, newValue)) { - return false; - } - - field = newValue; - RaisePropertyChanged(propertyName); - return true; - } - - #endregion - - #region Event Handlers - - private void OnInfoPropertyChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - case nameof(RelayInfo.Text): - case nameof(RelayInfo.Icon): - case nameof(RelayInfo.InputGesture): - RaisePropertyChanged(e.PropertyName); - break; - } - } - - #endregion - } +namespace WinDirStat.Net.Wpf.Commands { + public class RelayInfoCommand : IRelayInfoCommand, IRelayCommand { + + #region Fields + + private readonly RelayCommand command; + + /// The UI specific info for the command. + private RelayInfo info; + + #endregion + + #region Constructors + + public RelayInfoCommand(Action execute) { + command = new(execute); + } + + public RelayInfoCommand(Action execute, Predicate canExecute) { + command = new(execute, canExecute); + } + + #endregion + + #region Properties + + /// Gets or sets the UI specific info for the command. + public RelayInfo Info { + get => info; + set { + if (info != value) { + if (info != null) + info.PropertyChanged -= OnInfoPropertyChanged; + info = value; + if (info != null) + info.PropertyChanged += OnInfoPropertyChanged; + OnPropertyChanged(); + } + } + } + + /// Gets the display text for the command. + public string Text => info?.Text; + /// Gets the display icon for the command. + public ImageSource Icon => info?.Icon; + /// Gets the input gesture for the command. + public AnyKeyGesture InputGesture => info?.InputGesture; + + #endregion + + #region Events + + /// Called when a property has changed. + public event PropertyChangedEventHandler PropertyChanged; + public event EventHandler CanExecuteChanged { + add => command.CanExecuteChanged += value; + remove => command.CanExecuteChanged -= value; + } + + #endregion + + #region Execute + + public void NotifyCanExecuteChanged() => command.NotifyCanExecuteChanged(); + + public bool CanExecute(object parameter) => command.CanExecute(parameter); + + public void Execute(object parameter = null) => command.Execute(parameter); + + public bool CanExecute(T? parameter) => command.CanExecute(parameter); + + public void Execute(T? parameter) => command.Execute(parameter); + + #endregion + + #region Private PropertyChanged + + private void OnPropertyChanged([CallerMemberName] string propertyName = null) { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + #endregion + + #region Event Handlers + + private void OnInfoPropertyChanged(object sender, PropertyChangedEventArgs e) { + switch (e.PropertyName) { + case nameof(RelayInfo.Text): + case nameof(RelayInfo.Icon): + case nameof(RelayInfo.InputGesture): + OnPropertyChanged(e.PropertyName); + break; + } + } + + #endregion + } } \ No newline at end of file diff --git a/WinDirStat.Net.Wpf.Single/Commands/RelayInfoCommand.cs b/WinDirStat.Net.Wpf.Single/Commands/RelayInfoCommand.cs index 6987ab8..3bf0d0f 100644 --- a/WinDirStat.Net.Wpf.Single/Commands/RelayInfoCommand.cs +++ b/WinDirStat.Net.Wpf.Single/Commands/RelayInfoCommand.cs @@ -1,141 +1,101 @@ -using System; -using System.Collections.Generic; +using Microsoft.Toolkit.Mvvm.Input; +using System; using System.ComponentModel; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; +using System.Runtime.CompilerServices; using System.Windows.Media; -using GalaSoft.MvvmLight.CommandWpf; -using WinDirStat.Net.ViewModel; -using WinDirStat.Net.ViewModel.Commands; using WinDirStat.Net.Wpf.Input; namespace WinDirStat.Net.Wpf.Commands { - public class RelayInfoCommand : RelayCommand, IRelayInfoCommand, IRelayCommand { - - #region Fields - - /// The UI specific info for the command. - private RelayInfo info; - - #endregion - - #region Constructors - - /// Constructs the . - /// - /// - /// The execution logic. IMPORTANT: If the action causes a closure, you must set to true to avoid side effects. - /// - /// - /// If true, the target of the Action will be kept as a hard reference, which might cause a memory - /// leak. You should only set this parameter to true if the action is causing a closures. - /// See http://galasoft.ch/s/mvvmweakaction. - /// - /// - /// is null. - public RelayInfoCommand(Action execute, bool keepTargetAlive = false) - : base(execute, null, keepTargetAlive) - { - } - - /// Constructs the . - /// - /// - /// The execution logic. IMPORTANT: If the action causes a closure, you must set to true to avoid side effects. - /// - /// - /// The execution status logic. IMPORTANT: If the func causes a closure, you must set to true to avoid side effects. - /// - /// - /// If true, the target of the Action will be kept as a hard reference, which might cause a memory - /// leak. You should only set this parameter to true if the action is causing a closures. - /// See http://galasoft.ch/s/mvvmweakaction. - /// - /// - /// is null. - public RelayInfoCommand(Action execute, Func canExecute, bool keepTargetAlive = false) - : base(execute, canExecute, keepTargetAlive) - { - } - - #endregion - - #region Properties - - /// Gets or sets the UI specific info for the command. - public RelayInfo Info { - get => info; - set { - if (info != value) { - if (info != null) - info.PropertyChanged -= OnInfoPropertyChanged; - info = value; - if (info != null) - info.PropertyChanged += OnInfoPropertyChanged; - RaisePropertyChanged(); - } - } - } - - /// Gets the display text for the command. - public string Text => info?.Text; - /// Gets the display icon for the command. - public ImageSource Icon => info?.Icon; - /// Gets the input gesture for the command. - public AnyKeyGesture InputGesture => info?.InputGesture; - - #endregion - - #region Events - - /// Called when a property has changed. - public event PropertyChangedEventHandler PropertyChanged; - - #endregion - - #region Execute - - /// Executes the method without a parameter. - public void Execute() => Execute(null); - - #endregion - - #region Private PropertyChanged - - private void RaisePropertyChanged([CallerMemberName] string propertyName = null) { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - private bool Set(ref T field, T newValue, [CallerMemberName] string propertyName = null) { - if (EqualityComparer.Default.Equals(field, newValue)) { - return false; - } - - field = newValue; - RaisePropertyChanged(propertyName); - return true; - } - - #endregion - - #region Event Handlers - - private void OnInfoPropertyChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - case nameof(RelayInfo.Text): - case nameof(RelayInfo.Icon): - case nameof(RelayInfo.InputGesture): - RaisePropertyChanged(e.PropertyName); - break; - } - } - - #endregion - } + public class RelayInfoCommand : IRelayInfoCommand, IRelayCommand { + + #region Fields + + private readonly RelayCommand command; + + /// The UI specific info for the command. + private RelayInfo info; + + #endregion + + #region Constructors + + public RelayInfoCommand(Action execute) { + command = new(execute); + } + + public RelayInfoCommand(Action execute, Func canExecute) { + command = new(execute, canExecute); + } + + #endregion + + #region Properties + + /// Gets or sets the UI specific info for the command. + public RelayInfo Info { + get => info; + set { + if (info != value) { + if (info != null) + info.PropertyChanged -= OnInfoPropertyChanged; + info = value; + if (info != null) + info.PropertyChanged += OnInfoPropertyChanged; + OnPropertyChanged(); + } + } + } + + /// Gets the display text for the command. + public string Text => info?.Text; + /// Gets the display icon for the command. + public ImageSource Icon => info?.Icon; + /// Gets the input gesture for the command. + public AnyKeyGesture InputGesture => info?.InputGesture; + + #endregion + + #region Events + + /// Called when a property has changed. + public event PropertyChangedEventHandler PropertyChanged; + public event EventHandler CanExecuteChanged { + add => command.CanExecuteChanged += value; + remove => command.CanExecuteChanged -= value; + } + + #endregion + + #region Execute + + public void NotifyCanExecuteChanged() => command.NotifyCanExecuteChanged(); + + public bool CanExecute(object parameter) => command.CanExecute(parameter); + + public void Execute(object parameter = null) => command.Execute(parameter); + + #endregion + + #region Private PropertyChanged + + private void OnPropertyChanged([CallerMemberName] string propertyName = null) { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + #endregion + + #region Event Handlers + + private void OnInfoPropertyChanged(object sender, PropertyChangedEventArgs e) { + switch (e.PropertyName) { + case nameof(RelayInfo.Text): + case nameof(RelayInfo.Icon): + case nameof(RelayInfo.InputGesture): + OnPropertyChanged(e.PropertyName); + break; + } + } + + #endregion + } } \ No newline at end of file diff --git a/WinDirStat.Net.Wpf.Single/Controls/FileList/FileTreeViewItem.cs b/WinDirStat.Net.Wpf.Single/Controls/FileList/FileTreeViewItem.cs index 3ceaa65..48e31bb 100644 --- a/WinDirStat.Net.Wpf.Single/Controls/FileList/FileTreeViewItem.cs +++ b/WinDirStat.Net.Wpf.Single/Controls/FileList/FileTreeViewItem.cs @@ -32,13 +32,11 @@ public class FileTreeViewItem : ListViewItem { static FileTreeViewItem() { DefaultStyleKeyProperty.OverrideMetadata(typeof(FileTreeViewItem), new FrameworkPropertyMetadata(typeof(FileTreeViewItem))); - } - - public FileItemViewModel Node { - get { return DataContext as FileItemViewModel; } - } - - public FileTreeNodeView NodeView { get; internal set; } + } + + public FileItemViewModel Node => DataContext as FileItemViewModel; + + public FileTreeNodeView NodeView { get; internal set; } public FileTreeView ParentTreeView { get; internal set; } protected override void OnKeyDown(KeyEventArgs e) { @@ -92,7 +90,12 @@ protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { } }*/ - protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { + protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { + //this can happen when Node is a DisconnectedItem + if(Node == null) { + return; + } + if (wasDoubleClick) { wasDoubleClick = false; Node.ActivateItem(); diff --git a/WinDirStat.Net.Wpf.Single/Controls/FocusExtension.cs b/WinDirStat.Net.Wpf.Single/Controls/FocusExtension.cs index 6dd4d42..a54aefd 100644 --- a/WinDirStat.Net.Wpf.Single/Controls/FocusExtension.cs +++ b/WinDirStat.Net.Wpf.Single/Controls/FocusExtension.cs @@ -88,25 +88,19 @@ private static void OnIsKeyboardFocusedPropertyChanged(DependencyObject d, Depen private static void OnGotFocus(object sender, RoutedEventArgs e) { FrameworkElement element = (FrameworkElement) sender; - Console.WriteLine("GotFocus"); SetIsFocused(element, true); } private static void OnLostFocus(object sender, RoutedEventArgs e) { FrameworkElement element = (FrameworkElement) sender; - Console.WriteLine("LostFocus"); SetIsFocused(element, false); } private static void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { FrameworkElement element = (FrameworkElement) sender; - //SetIsFocused(element, true); - Console.WriteLine("LostKeyboardFocus"); } private static void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { FrameworkElement element = (FrameworkElement) sender; - //SetIsFocused(element, false); - Console.WriteLine("GotKeyboardFocus"); } } } diff --git a/WinDirStat.Net.Wpf.Single/Controls/GraphView.xaml.cs b/WinDirStat.Net.Wpf.Single/Controls/GraphView.xaml.cs index dbec237..13d92df 100644 --- a/WinDirStat.Net.Wpf.Single/Controls/GraphView.xaml.cs +++ b/WinDirStat.Net.Wpf.Single/Controls/GraphView.xaml.cs @@ -1,146 +1,132 @@ using System; using System.Collections; -using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; -using System.Drawing; -using System.Drawing.Imaging; using System.Linq; -using System.Text; using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; using System.Windows.Threading; -using WinDirStat.Net.Utils; -//using Bitmap = System.Drawing.Bitmap; -//using Graphics = System.Drawing.Graphics; -using Brush = System.Drawing.Brush; -using Pen = System.Drawing.Pen; -using Color = System.Drawing.Color; -using Rectangle = System.Drawing.Rectangle; using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Structures; using WinDirStat.Net.Rendering; using WinDirStat.Net.Services; -using WinDirStat.Net.Wpf.ViewModel; +using WinDirStat.Net.Structures; using WinDirStat.Net.ViewModel; using WinDirStat.Net.Wpf.Utils; -namespace WinDirStat.Net.Wpf.Controls { - public class GraphViewHoverEventArgs : RoutedEventArgs { - - public FileItemBase Hover; - - public GraphViewHoverEventArgs(RoutedEvent routedEvent, FileItemBase hover) - : base(routedEvent) - { - Hover = hover; - } - } - - public delegate void GraphViewHoverEventHandler(object sender, GraphViewHoverEventArgs e); - - - /// - /// Interaction logic for WpfGraphView.xaml - /// - public partial class GraphView : UserControl { - - public enum HighlightMode { - None, - Extension, - Selection, - } - - public static readonly DependencyProperty RootProperty = - DependencyProperty.Register("Root", typeof(FileItemBase), typeof(GraphView), - new FrameworkPropertyMetadata(null, OnRootChanged)); - - private static void OnRootChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is GraphView graphView) { - FileItemBase root = graphView.Root; - if (root == null) { - graphView.AbortRender(); - } - - graphView.root = root; - graphView.HighlightNone(); - graphView.Hover = null; - if (root != null) { - //lock (graphView.drawBitmapLock) - graphView.RenderAsync(); - } - else { - graphView.Clear(); - } - - } - } - - public FileItemBase Root { - get => (FileItemBase) GetValue(RootProperty); - set => SetValue(RootProperty, value); - } - - private static readonly DependencyPropertyKey HoverPropertyKey = - DependencyProperty.RegisterReadOnly("Hover", typeof(FileItemBase), typeof(GraphView), - new FrameworkPropertyMetadata(null, OnHoverChanged)); - - public static readonly DependencyProperty HoverProperty = - HoverPropertyKey.DependencyProperty; - - private static void OnHoverChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is GraphView graphView) { - FileItemBase hover = e.NewValue as FileItemBase; - graphView.HasHover = hover != null; - graphView.RaiseEvent(new GraphViewHoverEventArgs(HoverChangedEvent, hover)); - } - } - - public FileItemBase Hover { - get => (FileItemBase) GetValue(HoverProperty); - private set => SetValue(HoverPropertyKey, value); - } - - private static readonly DependencyPropertyKey HasHoverPropertyKey = - DependencyProperty.RegisterReadOnly("HasHover", typeof(bool), typeof(GraphView), - new FrameworkPropertyMetadata(false)); - - public static readonly DependencyProperty HasHoverProperty = - HasHoverPropertyKey.DependencyProperty; - - public bool HasHover { - get => (bool) GetValue(HasHoverProperty); - private set => SetValue(HasHoverPropertyKey, value); - } - - public static readonly RoutedEvent HoverChangedEvent = - EventManager.RegisterRoutedEvent("HoverChanged", RoutingStrategy.Bubble, - typeof(GraphViewHoverEventHandler), typeof(GraphView)); - - public event GraphViewHoverEventHandler HoverChanged { - add => AddHandler(HoverChangedEvent, value); - remove => RemoveHandler(HoverChangedEvent, value); - } - - private static readonly DependencyProperty RenderPriorityProperty = - DependencyProperty.Register("RenderPriority", typeof(ThreadPriority), typeof(GraphView), - new FrameworkPropertyMetadata(ThreadPriority.BelowNormal)); - - public ThreadPriority RenderPriority { - get => (ThreadPriority) GetValue(RenderPriorityProperty); - set => SetValue(RenderPriorityProperty, value); - } - - /*private static readonly DependencyProperty ForceDimmedProperty = +namespace WinDirStat.Net.Wpf.Controls { + public class GraphViewHoverEventArgs : RoutedEventArgs { + + public FileItemBase Hover; + + public GraphViewHoverEventArgs(RoutedEvent routedEvent, FileItemBase hover) + : base(routedEvent) { + Hover = hover; + } + } + + public delegate void GraphViewHoverEventHandler(object sender, GraphViewHoverEventArgs e); + + + /// + /// Interaction logic for WpfGraphView.xaml + /// + public partial class GraphView : UserControl { + + public enum HighlightMode { + None, + Extension, + Selection, + } + + public static readonly DependencyProperty RootProperty = + DependencyProperty.Register("Root", typeof(FileItemBase), typeof(GraphView), + new FrameworkPropertyMetadata(null, OnRootChanged)); + + private static async void OnRootChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { + if (d is not GraphView graphView) + return; + + FileItemBase root = graphView.Root; + //if (root == null) { + // await graphView.AbortRenderAsync(); + //} + + graphView.root = root; + graphView.HighlightNone(); + graphView.Hover = null; + if (root != null) { + await graphView.RenderAsync(); + } + else { + var render = graphView.renderTask; + if (render != null) { + await render; + } + graphView.Clear(); + } + } + + public FileItemBase Root { + get => (FileItemBase) GetValue(RootProperty); + set => SetValue(RootProperty, value); + } + + private static readonly DependencyPropertyKey HoverPropertyKey = + DependencyProperty.RegisterReadOnly("Hover", typeof(FileItemBase), typeof(GraphView), + new FrameworkPropertyMetadata(null, OnHoverChanged)); + + public static readonly DependencyProperty HoverProperty = + HoverPropertyKey.DependencyProperty; + + private static void OnHoverChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { + if (d is GraphView graphView) { + FileItemBase hover = e.NewValue as FileItemBase; + graphView.HasHover = hover != null; + graphView.RaiseEvent(new GraphViewHoverEventArgs(HoverChangedEvent, hover)); + } + } + + public FileItemBase Hover { + get => (FileItemBase) GetValue(HoverProperty); + private set => SetValue(HoverPropertyKey, value); + } + + private static readonly DependencyPropertyKey HasHoverPropertyKey = + DependencyProperty.RegisterReadOnly("HasHover", typeof(bool), typeof(GraphView), + new FrameworkPropertyMetadata(false)); + + public static readonly DependencyProperty HasHoverProperty = + HasHoverPropertyKey.DependencyProperty; + + public bool HasHover { + get => (bool) GetValue(HasHoverProperty); + private set => SetValue(HasHoverPropertyKey, value); + } + + public static readonly RoutedEvent HoverChangedEvent = + EventManager.RegisterRoutedEvent("HoverChanged", RoutingStrategy.Bubble, + typeof(GraphViewHoverEventHandler), typeof(GraphView)); + + public event GraphViewHoverEventHandler HoverChanged { + add => AddHandler(HoverChangedEvent, value); + remove => RemoveHandler(HoverChangedEvent, value); + } + + private static readonly DependencyProperty RenderPriorityProperty = + DependencyProperty.Register("RenderPriority", typeof(ThreadPriority), typeof(GraphView), + new FrameworkPropertyMetadata(ThreadPriority.BelowNormal)); + + public ThreadPriority RenderPriority { + get => (ThreadPriority) GetValue(RenderPriorityProperty); + set => SetValue(RenderPriorityProperty, value); + } + + /*private static readonly DependencyProperty ForceDimmedProperty = DependencyProperty.Register("ForceDimmed", typeof(bool), typeof(GraphView), new FrameworkPropertyMetadata(false, OnForceDimmedChanged)); @@ -165,342 +151,328 @@ private static void OnForceDimmedChanged(DependencyObject d, DependencyPropertyC graphView.RenderAsync(); } } - }*/ - - private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is GraphView graphView) { - graphView.UpdateDimmed(); - if (!graphView.IsEnabled) { - graphView.AbortRender(); - graphView.disabledTreemap = graphView.treemap; - graphView.disabledHighlight = graphView.highlight; - graphView.imageTreemap.Source = graphView.disabledTreemap; - graphView.imageHighlight.Source = graphView.disabledHighlight; - } - else { - graphView.disabledTreemap = null; - graphView.disabledHighlight = null; - // GraphView will render if (!IsEnabled and Root != null) - graphView.RenderAsync(); - } - } - } - - private void UpdateDimmed() { - IsDimmed = IsRenderingTreemap || resizing || !IsEnabled; - } - - private static readonly DependencyPropertyKey IsDimmedPropertyKey = - DependencyProperty.RegisterReadOnly("IsDimmed", typeof(bool), typeof(GraphView), - new FrameworkPropertyMetadata(false, OnIsDimmedChanged)); - - private static void OnIsDimmedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - GraphView graphView = (GraphView) d; - - if (graphView.IsDimmed) - graphView.Hover = null; - else if (graphView.IsMouseOver) - graphView.UpdateHover(); - } - - public static readonly DependencyProperty IsDimmedProperty = - IsDimmedPropertyKey.DependencyProperty; - - public bool IsDimmed { - get => (bool) GetValue(IsDimmedProperty); - private set => SetValue(IsDimmedPropertyKey, value); - } - - private static void OnDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - GraphView graphView = (GraphView) d; - MainViewModel oldViewModel = e.OldValue as MainViewModel; - MainViewModel newViewModel = e.NewValue as MainViewModel; - - if (oldViewModel != null) - oldViewModel.Settings.PropertyChanged -= graphView.OnSettingsChanged; - if (graphView.IsLoaded && newViewModel != null) - newViewModel.Settings.PropertyChanged += graphView.OnSettingsChanged; - graphView.ViewModel = newViewModel; - } - - private void OnSettingsChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - case nameof(SettingsService.TreemapOptions): - case nameof(SettingsService.FilePalette): - RenderAsync(); - break; - case nameof(SettingsService.HighlightColor): - if (highlightMode != HighlightMode.None) - RenderHighlight(treemapSize); - break; - } - } - - private Point2I treemapSize; - private WriteableBitmap treemap; - private Point2I highlightSize; - private WriteableBitmap highlight; - private Bitmap highlightGdi; - private WriteableBitmap disabledTreemap; - private WriteableBitmap disabledHighlight; - private readonly DispatcherTimer resizeTimer; - private Thread renderThread; - private FileItemBase root; - private bool resizing; - /// Check if the running render thread has finished rendering the treemap. - private volatile bool treemapRendered; - private volatile bool fullRender; - //private TreemapOptions options; - - private readonly object renderLock = new object(); - private readonly object drawBitmapLock = new object(); - private FileItemBase[] selection; - private string extension; - private HighlightMode highlightMode; - - static GraphView() { - DataContextProperty.AddOwner(typeof(GraphView), - new FrameworkPropertyMetadata(OnDataContextChanged)); - IsEnabledProperty.AddOwner(typeof(GraphView), - new FrameworkPropertyMetadata(OnIsEnabledChanged)); - } - - public GraphView() { - if (!this.DesignerInitializeComponent("Controls")) - InitializeComponent(); - - resizeTimer = new DispatcherTimer( - TimeSpan.FromMilliseconds(50), - DispatcherPriority.Normal, - OnResizeTimerTick, - Dispatcher); - resizeTimer.Stop(); - treemapSize = Point2I.Zero; - highlightSize = Point2I.Zero; - highlightMode = HighlightMode.None; - treemapRendered = true; - } - - public void HighlightNone() { - highlightMode = HighlightMode.None; - extension = null; - selection = null; - imageHighlight.Source = null; - } - - public void HighlightExtension(string extension) { - if (this.extension == extension) - return; - - highlightMode = HighlightMode.Extension; - this.extension = extension; - selection = null; - if (IsRendering) { - RenderHighlightAsync(); - } - else if (!IsDimmed && Root != null) { - RenderHighlight(treemapSize); - if (imageHighlight.Source != highlight) - imageHighlight.Source = highlight; - } - //RenderHighlightAsync(ThreadPriority.Normal); - //Render(true); - } - - public void HighlightSelection(IEnumerable selection) { - if (this.selection != null && this.selection.Intersect(selection.Cast()).Count() == this.selection.Length) - return; - - highlightMode = HighlightMode.Selection; - this.selection = selection.Cast().ToArray(); - extension = null; - if (IsRendering) { - RenderHighlightAsync(); - } - else if (!IsDimmed && Root != null) { - RenderHighlight(treemapSize); - if (imageHighlight.Source != highlight) - imageHighlight.Source = highlight; - } - //RenderHighlightAsync(ThreadPriority.Normal); - //Render(true); - } - - private void OnLoaded(object sender, RoutedEventArgs e) { - resizeTimer.Start(); - } - - private void OnUnloaded(object sender, RoutedEventArgs e) { - resizeTimer.Stop(); - AbortRender(); - } - - private void OnSizeChanged(object sender, SizeChangedEventArgs e) { - resizing = true; - IsDimmed = true; - // Restart the timer by stopping it first - resizeTimer.Stop(); - resizeTimer.Start(); - } - - private void OnResizeTimerTick(object sender, EventArgs e) { - resizing = false; - UpdateDimmed(); - resizeTimer.Stop(); - RenderAsync(); - } - - - - /// Gets if anything is in the process of being rendered. - private bool IsRendering => renderThread?.IsAlive ?? false; - - /// Gets if the treemap is in the process of being rendered. - private bool IsRenderingTreemap => renderThread?.IsAlive ?? false && fullRender; - - /// A link to the view model that can be accessed outside of the UI thread. - private MainViewModel ViewModel { get; set; } - private SettingsService Settings => ViewModel.Settings; - private TreemapRenderer Treemap => ViewModel.Treemap; - - private TreemapOptions Options { - get => Settings.TreemapOptions; - } - private Rgba32Color HighlightColor { - get => Settings.HighlightColor; - } - - private void Clear() { - AbortRender(); - treemap = null; - highlight = null; - treemapSize = Point2I.Zero; - highlightSize = Point2I.Zero; - } - - public void AbortRender(bool waitForExit = true) { - if (renderThread != null) { - renderThread.Abort(); - renderThread = null; - UpdateDimmed(); - } - } - - public void RenderHighlightAsync(ThreadPriority? priority = null) { - fullRender = !treemapRendered; - RenderAsyncFinal(priority); - } - - public void RenderAsync(ThreadPriority? priority = null) { - fullRender = true; - RenderAsyncFinal(priority); - } - - private void RenderAsyncFinal(ThreadPriority? priority = null) { - if (IsEnabled && Root != null) { - AbortRender(); - treemapRendered = false; - //IsDimmed = true; - Point2I size = new Point2I((int) ActualWidth, (int) ActualHeight); - renderThread = new Thread(() => RenderThread(size)) { - Priority = priority ?? RenderPriority, - Name = "GraphView Render", - }; - renderThread.Start(); - UpdateDimmed(); - } - } - - private void RenderThread(Point2I size) { - try { - if (size.X != 0 && size.Y != 0) { - if (fullRender) { - RenderTreemap(size); - } - treemapRendered = true; - if (highlightMode != HighlightMode.None) { - RenderHighlight(size); - } - } - Dispatcher.Invoke(() => { - // Let the control know we're not rendering anymore - renderThread = null; - imageTreemap.Source = treemap; - if (highlightMode != HighlightMode.None) - imageHighlight.Source = highlight; - UpdateDimmed(); - }); - } - catch (ThreadAbortException) { } - catch (Exception ex) { - Stopwatch sw = Stopwatch.StartNew(); - Dispatcher.Invoke(() => { - Console.WriteLine(ex.ToString()); - renderThread = null; - UpdateDimmed(); - UpdateHover(); - }); - Console.WriteLine($"Took {sw.ElapsedMilliseconds}ms to invoke EXCEPTION Dispatcher"); - } - } - - private void RenderTreemap(Point2I size) { - Stopwatch sw = Stopwatch.StartNew(); - if (treemap == null || treemapSize.X != size.X || treemapSize.Y != size.Y) { - treemapSize = size; - Application.Current.Dispatcher.Invoke(() => { - treemap = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); - }); - } - Treemap.DrawTreemap(treemap, new Rectangle2I(size), root); - //Treemap.DrawTreemap(treemap, new Rectangle2I(size), fileRoot, options); - Console.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render treemap"); - } - private void RenderHighlight(Point2I size) { - Stopwatch sw = Stopwatch.StartNew(); - if (highlight == null || highlightSize.X != size.X || highlightSize.Y != size.Y) { - highlightSize = size; - Application.Current.Dispatcher.Invoke(() => { - highlight = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); - }); - highlightGdi?.Dispose(); - highlightGdi = new Bitmap(size.X, size.Y, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - Trace.WriteLine($"Took {sw.ElapsedMilliseconds}ms to setup highlight bitmap"); - } - sw.Restart(); - if (highlightMode == HighlightMode.Extension) { - Treemap.HighlightExtensions(highlight, new Rectangle2I(size), root, Settings.HighlightColor, extension); - } - else if (highlightMode == HighlightMode.Selection) { - Treemap.HighlightItems(highlight, new Rectangle2I(size), Settings.HighlightColor, selection); - } - Trace.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render highlight"); - Trace.WriteLine(""); - } - - private void OnMouseMove(object sender, MouseEventArgs e) { - UpdateHover((Point2I) e.GetPosition(this)); - } - - private void OnMouseLeave(object sender, MouseEventArgs e) { - Hover = null; - } - - private void UpdateHover() { - UpdateHover((Point2I) Mouse.GetPosition(this)); - } - - private void UpdateHover(Point2I point) { - if (root == null) { - Hover = null; - return; - } - if (Hover != null) { - Rectangle2I rc = ((ITreemapItem) Hover).Rectangle; - if (rc.Contains(point)) - return; // Hover is the same - } - Hover = (FileItemBase) TreemapRenderer.FindItemAtPoint(root, point); - } - } + }*/ + + private static async void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { + if (d is not GraphView graphView) + return; + + graphView.UpdateDimmed(); + if (graphView.IsEnabled) { + // GraphView will render if (!IsEnabled and Root != null) + await graphView.RenderAsync(); + } + } + + private void UpdateDimmed() => IsDimmed = IsRenderingTreemap || resizing || !IsEnabled; + + private static readonly DependencyPropertyKey IsDimmedPropertyKey = + DependencyProperty.RegisterReadOnly("IsDimmed", typeof(bool), typeof(GraphView), + new FrameworkPropertyMetadata(false, OnIsDimmedChanged)); + + private static void OnIsDimmedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { + GraphView graphView = (GraphView) d; + + if (graphView.IsDimmed) + graphView.Hover = null; + else if (graphView.IsMouseOver) + graphView.UpdateHover(); + } + + public static readonly DependencyProperty IsDimmedProperty = + IsDimmedPropertyKey.DependencyProperty; + + public bool IsDimmed { + get => (bool) GetValue(IsDimmedProperty); + private set => SetValue(IsDimmedPropertyKey, value); + } + + private static void OnDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { + GraphView graphView = (GraphView) d; + MainViewModel oldViewModel = e.OldValue as MainViewModel; + MainViewModel newViewModel = e.NewValue as MainViewModel; + + if (oldViewModel != null) + oldViewModel.Settings.PropertyChanged -= graphView.OnSettingsChanged; + if (graphView.IsLoaded && newViewModel != null) + newViewModel.Settings.PropertyChanged += graphView.OnSettingsChanged; + graphView.ViewModel = newViewModel; + } + + private async void OnSettingsChanged(object sender, PropertyChangedEventArgs e) { + switch (e.PropertyName) { + case nameof(SettingsService.TreemapOptions): + case nameof(SettingsService.FilePalette): + await RenderAsync(); + break; + case nameof(SettingsService.HighlightColor): + if (highlightMode != HighlightMode.None) + RenderHighlight(treemapSize); + break; + } + } + private Point2I treemapSize; + private WriteableBitmap treemap; + private Point2I highlightSize; + private WriteableBitmap highlight; + private readonly DispatcherTimer resizeTimer; + + private Task renderTask; + private AutoResetEvent renderGate; + + private FileItemBase root; + private bool resizing; + /// Check if the running render thread has finished rendering the treemap. + private volatile bool treemapRendered; + private volatile bool fullRender; + //private TreemapOptions options; + + private FileItemBase[] selection; + private string extension; + private HighlightMode highlightMode; + + static GraphView() { + DataContextProperty.AddOwner(typeof(GraphView), + new FrameworkPropertyMetadata(OnDataContextChanged)); + IsEnabledProperty.AddOwner(typeof(GraphView), + new FrameworkPropertyMetadata(OnIsEnabledChanged)); + } + + public GraphView() { + if (!this.DesignerInitializeComponent("Controls")) + InitializeComponent(); + + renderGate = new(true); + resizeTimer = new DispatcherTimer( + TimeSpan.FromMilliseconds(50), + DispatcherPriority.Normal, + OnResizeTimerTick, + Dispatcher); + resizeTimer.Stop(); + treemapSize = Point2I.Zero; + highlightSize = Point2I.Zero; + highlightMode = HighlightMode.None; + treemapRendered = true; + } + + public void HighlightNone() { + highlightMode = HighlightMode.None; + extension = null; + selection = null; + imageHighlight.Source = null; + } + + public async void HighlightExtension(string extension) { + if (this.extension == extension) + return; + + highlightMode = HighlightMode.Extension; + this.extension = extension; + selection = null; + if (IsRendering) { + await RenderHighlightAsync(); + } + else if (!IsDimmed && Root != null) { + RenderHighlight(treemapSize); + if (imageHighlight.Source != highlight) + imageHighlight.Source = highlight; + } + //RenderHighlightAsync(ThreadPriority.Normal); + //Render(true); + } + + public async void HighlightSelection(IEnumerable selection) { + if (this.selection != null && this.selection.Intersect(selection.Cast()).Count() == this.selection.Length) + return; + + highlightMode = HighlightMode.Selection; + this.selection = selection.Cast().ToArray(); + extension = null; + if (IsRendering) { + await RenderHighlightAsync(); + } + else if (!IsDimmed && Root != null) { + RenderHighlight(treemapSize); + if (imageHighlight.Source != highlight) + imageHighlight.Source = highlight; + } + //RenderHighlightAsync(ThreadPriority.Normal); + //Render(true); + } + + private void OnLoaded(object sender, RoutedEventArgs e) { + resizeTimer.Start(); + } + + private void OnUnloaded(object sender, RoutedEventArgs e) { + resizeTimer.Stop(); + //await AbortRenderAsync(); + } + + private void OnSizeChanged(object sender, SizeChangedEventArgs e) { + resizing = true; + IsDimmed = true; + // Restart the timer by stopping it first + resizeTimer.Stop(); + resizeTimer.Start(); + } + + private async void OnResizeTimerTick(object sender, EventArgs e) { + resizing = false; + resizeTimer.Stop(); + await RenderAsync(); + } + + + + /// Gets if anything is in the process of being rendered. + private bool IsRendering => !renderTask?.IsCompleted ?? false; + + /// Gets if the treemap is in the process of being rendered. + private bool IsRenderingTreemap => fullRender && IsRendering; + + /// A link to the view model that can be accessed outside of the UI thread. + private MainViewModel ViewModel { get; set; } + private SettingsService Settings => ViewModel.Settings; + private TreemapRenderer Treemap => ViewModel.Treemap; + + private TreemapOptions Options { + get => Settings.TreemapOptions; + } + private Rgba32Color HighlightColor { + get => Settings.HighlightColor; + } + + private void Clear() { + //await AbortRenderAsync(); + treemap = null; + highlight = null; + treemapSize = Point2I.Zero; + highlightSize = Point2I.Zero; + } + + //public async Task AbortRenderAsync(bool waitForExit = true) { + // //FIXME: waitForExit was never observed anyway + // if (waitForExit && IsRendering) { + // await renderTask; + // } + // UpdateDimmed(); + //} + + public Task RenderHighlightAsync(ThreadPriority? priority = null) { + fullRender = !treemapRendered; + return RenderCoreAsync(priority); + } + + public Task RenderAsync(ThreadPriority? priority = null) { + fullRender = true; + return RenderCoreAsync(priority); + } + + private async Task RenderCoreAsync(ThreadPriority? priority = null) { + if (!IsEnabled) + return; + + if (Root == null) + return; + + var acquired = renderGate.WaitOne(0); + if (!acquired) + return; + + //await AbortRenderAsync(); + treemapRendered = false; + + var size = new Point2I((int) ActualWidth, (int) ActualHeight); + + Debug.Assert(renderTask == null || renderTask.IsCompleted); + renderTask = Task.Run(() => RenderWorker(size)); + UpdateDimmed(); + await renderTask; + + Dispatcher.Invoke(RenderFinished); + } + + private void RenderWorker(Point2I size) { + if (size.X != 0 && size.Y != 0) { + if (fullRender) { + RenderTreemap(size); + } + treemapRendered = true; + + if (highlightMode != HighlightMode.None) { + RenderHighlight(size); + } + } + } + + private void RenderFinished() { + // Let the control know we're not rendering anymore + imageTreemap.Source = treemap; + if (highlightMode != HighlightMode.None) { + imageHighlight.Source = highlight; + } + UpdateDimmed(); + + renderGate.Set(); + } + + private void RenderTreemap(Point2I size) { + Stopwatch sw = Stopwatch.StartNew(); + if (treemap == null || treemapSize != size) { + treemapSize = size; + //treemap = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); + Dispatcher.Invoke(() => treemap = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null)); + } + Treemap.DrawTreemap(treemap, new Rectangle2I(size), root); + sw.Stop(); + + Debug.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render treemap"); + } + private void RenderHighlight(Point2I size) { + Stopwatch sw = Stopwatch.StartNew(); + if (highlight == null || highlightSize != size) { + highlightSize = size; + //highlight = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); + Dispatcher.Invoke(() => highlight = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null)); + } + sw.Stop(); + Debug.WriteLine($"Took {sw.ElapsedMilliseconds}ms to setup highlight bitmap"); + + sw.Restart(); + if (highlightMode == HighlightMode.Extension) { + Treemap.HighlightExtensions(highlight, new Rectangle2I(size), root, Settings.HighlightColor, extension); + } + else if (highlightMode == HighlightMode.Selection) { + Treemap.HighlightItems(highlight, new Rectangle2I(size), Settings.HighlightColor, selection); + } + sw.Stop(); + Debug.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render highlight"); + } + + private void OnMouseMove(object sender, MouseEventArgs e) { + UpdateHover((Point2I) e.GetPosition(this)); + } + + private void OnMouseLeave(object sender, MouseEventArgs e) { + Hover = null; + } + + private void UpdateHover() { + UpdateHover((Point2I) Mouse.GetPosition(this)); + } + + private void UpdateHover(Point2I point) { + if (root == null) { + Hover = null; + return; + } + if (Hover != null) { + Rectangle2I rc = ((ITreemapItem) Hover).Rectangle; + if (rc.Contains(point)) + return; // Hover is the same + } + Hover = (FileItemBase) TreemapRenderer.FindItemAtPoint(root, point); + } + } } diff --git a/WinDirStat.Net.Wpf.Single/Properties/AssemblyInfo.cs b/WinDirStat.Net.Wpf.Single/Properties/AssemblyInfo.cs deleted file mode 100644 index ca969d8..0000000 --- a/WinDirStat.Net.Wpf.Single/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Windows; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("WinDirStat.Net")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Trigger's Tools & Games")] -[assembly: AssemblyProduct("WinDirStat.Net")] -[assembly: AssemblyCopyright("Copyright © Robert Jordan {YEAR}")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -//In order to begin building localizable applications, set -//CultureYouAreCodingWith in your .csproj file -//inside a . For example, if you are using US english -//in your source files, set the to en-US. Then uncomment -//the NeutralResourceLanguage attribute below. Update the "en-US" in -//the line below to match the UICulture setting in the project file. - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] - - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.0.1.0")] -[assembly: AssemblyFileVersion("0.0.1.0")] -[assembly: NeutralResourcesLanguage("en-US")] - diff --git a/WinDirStat.Net.Wpf.Single/Services/DialogService.cs b/WinDirStat.Net.Wpf.Single/Services/DialogService.cs index cb5a3c1..f503ad0 100644 --- a/WinDirStat.Net.Wpf.Single/Services/DialogService.cs +++ b/WinDirStat.Net.Wpf.Single/Services/DialogService.cs @@ -1,17 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using Ookii.Dialogs.Wpf; using System.Media; -using System.Text; -using System.Threading.Tasks; using System.Windows; using WinDirStat.Net.Model.Drives; using WinDirStat.Net.Services; using WinDirStat.Net.Wpf.Windows; namespace WinDirStat.Net.Wpf.Services { - /// A service for launching dialogs and showing messages. - public class DialogService : IMyDialogService { + /// A service for launching dialogs and showing messages. + public class DialogService : IMyDialogService { /// Shows the dialog for selecting paths to scan. /// @@ -29,25 +25,22 @@ public DriveSelectResult ShowDriveSelect(Window owner) { /// The currently selected path. Use an empty string for nothing. /// The selected path on success, otherwise null. public string ShowFolderBrowser(Window owner, string description, bool showNewFolder, string selectedPath = "") { - FolderBrowserDialog dialog = new FolderBrowserDialog() { + var dialog = new VistaFolderBrowserDialog() { Description = description, ShowNewFolderButton = showNewFolder, SelectedPath = selectedPath, }; - bool? result = dialog.ShowDialog(owner); - if (result ?? false) { - return dialog.SelectedPath; - } - return null; - } - /// Shows a message with no icon. - /// - /// The owner window for this dialog message. - /// The text message. - /// The message window title. - /// The message buttons to display. - public MessageBoxResult ShowMessage(Window owner, string message, string title, MessageBoxButton button = MessageBoxButton.OK) { + return (dialog.ShowDialog() ?? false) ? dialog.SelectedPath : null; + } + + /// Shows a message with no icon. + /// + /// The owner window for this dialog message. + /// The text message. + /// The message window title. + /// The message buttons to display. + public MessageBoxResult ShowMessage(Window owner, string message, string title, MessageBoxButton button = MessageBoxButton.OK) { return MessageBox.Show(owner, message, title, button); } diff --git a/WinDirStat.Net.Wpf.Single/Services/RelayInfoCommandFactory.cs b/WinDirStat.Net.Wpf.Single/Services/RelayInfoCommandFactory.cs index 06375df..70df1ac 100644 --- a/WinDirStat.Net.Wpf.Single/Services/RelayInfoCommandFactory.cs +++ b/WinDirStat.Net.Wpf.Single/Services/RelayInfoCommandFactory.cs @@ -1,47 +1,35 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Microsoft.Toolkit.Mvvm.Input; +using System; using WinDirStat.Net.Services; -using WinDirStat.Net.ViewModel.Commands; -using WinDirStat.Net.Wpf.Commands; - -namespace WinDirStat.Net.Wpf.Services { - /// A service for creating relay commands to be loaded by the view model. - public class RelayInfoCommandFactory : RelayCommandFactory { - - #region Create Abstract - - /// - /// Creates a new with the specified info and functions. - /// - /// - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - public override IRelayCommand Create(Action execute, Func canExecute, - bool keepTargetAlive = false) - { - return new RelayInfoCommand(execute, canExecute, keepTargetAlive); - } - - /// - /// Creates a new with the specified info and functions. - /// - /// - /// The parameter type of the command. - /// The abstract information about the command. - /// The execution action. - /// The optional can execute function. - /// The constructed - public override IRelayCommand Create(Action execute, Func canExecute, - bool keepTargetAlive = false) - { - return new RelayInfoCommand(execute, canExecute, keepTargetAlive); - } - - #endregion - } +using WinDirStat.Net.Wpf.Commands; + +namespace WinDirStat.Net.Wpf.Services { + /// A service for creating relay commands to be loaded by the view model. + public class RelayInfoCommandFactory : RelayCommandFactory { + + #region Create Abstract + + /// + /// Creates a new with the specified info and functions. + /// + /// + /// The abstract information about the command. + /// The execution action. + /// The optional can execute function. + /// The constructed + public override IRelayCommand Create(Action execute, Func canExecute) => new RelayInfoCommand(execute, canExecute); + + /// + /// Creates a new with the specified info and functions. + /// + /// + /// The parameter type of the command. + /// The abstract information about the command. + /// The execution action. + /// The optional can execute function. + /// The constructed + public override IRelayCommand Create(Action execute, Predicate canExecute) => new RelayInfoCommand(execute, canExecute); + + #endregion + } } diff --git a/WinDirStat.Net.Wpf.Single/ViewModel/ViewModelLocator.cs b/WinDirStat.Net.Wpf.Single/ViewModel/ViewModelLocator.cs index ddeb45e..ed6ea99 100644 --- a/WinDirStat.Net.Wpf.Single/ViewModel/ViewModelLocator.cs +++ b/WinDirStat.Net.Wpf.Single/ViewModel/ViewModelLocator.cs @@ -12,20 +12,19 @@ See http://www.galasoft.ch/mvvm */ -using GalaSoft.MvvmLight; -using GalaSoft.MvvmLight.Ioc; -using CommonServiceLocator; -using WinDirStat.Net.ViewModel; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Toolkit.Mvvm.DependencyInjection; using WinDirStat.Net.Rendering; using WinDirStat.Net.Services; +using WinDirStat.Net.ViewModel; using WinDirStat.Net.Wpf.Services; - -namespace WinDirStat.Net.Wpf.ViewModel { - /// - /// This class contains static references to all the view models in the - /// application and provides an entry point for the bindings. - /// - public class ViewModelLocator { + +namespace WinDirStat.Net.Wpf.ViewModel { + /// + /// This class contains static references to all the view models in the + /// application and provides an entry point for the bindings. + /// + public class ViewModelLocator { //public SimpleIoc Ioc { get; private set; } @@ -62,50 +61,40 @@ static ViewModelLocator() { } /// Initializes a new instance of the ViewModelLocator class. - public ViewModelLocator() { - SimpleIoc.Default.Reset(); - - ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); - - ////if (ViewModelBase.IsInDesignModeStatic) - ////{ - //// // Create design time view services and models - //// SimpleIoc.Default.Register(); - ////} - ////else - ////{ - //// // Create run time view services and models - //// SimpleIoc.Default.Register(); - ////} - - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - } - - public MainViewModel Main => ServiceLocator.Current.GetInstance(); - public DriveSelectViewModel DriveSelect => ServiceLocator.Current.GetInstance(); - public ConfigureViewModel Configure => ServiceLocator.Current.GetInstance(); + public ViewModelLocator() { + RegisterServices(); + } + + private void RegisterServices() { + var collection = new ServiceCollection() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + + .AddSingleton() + .AddSingleton() + .AddSingleton() + + .BuildServiceProvider(); + + Ioc.Default.ConfigureServices(collection); + } + + public MainViewModel Main => Ioc.Default.GetService(); + public DriveSelectViewModel DriveSelect => Ioc.Default.GetService(); + public ConfigureViewModel Configure => Ioc.Default.GetService(); /*public TreemapRendererFactory TreemapFactory => ServiceLocator.Current.GetInstance(); public TreemapRenderer CreateTreemap() { return TreemapFactory.Create(); }*/ - - public static void Cleanup() { - ServiceLocator.Current.GetInstance().Dispose(); - } } } \ No newline at end of file diff --git a/WinDirStat.Net.Wpf.Single/WinDirStat.Net.Wpf.Single.csproj b/WinDirStat.Net.Wpf.Single/WinDirStat.Net.Wpf.Single.csproj index 352e7cf..3db1639 100644 --- a/WinDirStat.Net.Wpf.Single/WinDirStat.Net.Wpf.Single.csproj +++ b/WinDirStat.Net.Wpf.Single/WinDirStat.Net.Wpf.Single.csproj @@ -1,326 +1,58 @@ - - - - - Debug - AnyCPU - {DA620261-55E4-4382-8866-168D958A3BE7} - WinExe - WinDirStat.Net.Wpf - WinDirStat.Net - v4.6.2 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - true - true - - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - latest - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - latest - - - Resources\App.ico - - - Properties\App.manifest - - - - - - - - - - - 4.0 - - - - - - - - - MSBuild:Compile - Designer - - - - - - - - - - - - - - - - - - - - - - - - - GraphView.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DriveSelectDialog.xaml - - - ErrorMessageBox.xaml - - - - ConfigureDialog.xaml - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - MainWindow.xaml - Code - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - - - Code - - - - - - {7da5a107-b474-4ac0-b861-63a489db0c02} - FunctionalFun.UI.Behaviors - - - {ef57db12-06c2-4441-ba5e-56aeb8e0b907} - WinDirStat.Net.Wpf.Base - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.0.1 - - - 5.4.1.1 - - - 1.0.0 - - - 1.0.0 - - - 1.6.2 - - - + + + net5.0-windows + WinExe + WinDirStat.Net.Wpf + WinDirStat.Net + WinDirStat.Net + Trigger's Tools & Games + WinDirStat.Net + Copyright © Robert Jordan {YEAR} + 0.0.1.0 + en-US + true + true + latest + + + Resources\App.ico + + + Properties\App.manifest + + + + + + + + + + + + + + + + + + + + + + + 2.0.0 + + + 1.0.2 + + + all + + + + + + + \ No newline at end of file diff --git a/WinDirStat.Net.Wpf.Single/Windows/ErrorMessageBox.xaml.cs b/WinDirStat.Net.Wpf.Single/Windows/ErrorMessageBox.xaml.cs index 202f5f0..9ed4a9c 100644 --- a/WinDirStat.Net.Wpf.Single/Windows/ErrorMessageBox.xaml.cs +++ b/WinDirStat.Net.Wpf.Single/Windows/ErrorMessageBox.xaml.cs @@ -13,7 +13,6 @@ using System.Windows.Navigation; using System.Windows.Threading; using WinDirStat.Net.Utils; -using WinFormsApplication = System.Windows.Forms.Application; namespace WinDirStat.Net.Wpf.Windows { /// Shows an error that occured in the program. @@ -208,8 +207,6 @@ public static void GlobalHook(Application app) { OnAppDomainUnhandledException; TaskScheduler.UnobservedTaskException += OnTaskSchedulerUnobservedTaskException; - WinFormsApplication.ThreadException += - OnWinFormsThreadException; app.Exit += OnAppShutdown; } @@ -225,8 +222,6 @@ private static void OnAppShutdown(object sender, ExitEventArgs e) { OnAppDomainUnhandledException; TaskScheduler.UnobservedTaskException -= OnTaskSchedulerUnobservedTaskException; - WinFormsApplication.ThreadException -= - OnWinFormsThreadException; } /// Show an exception window for an exception that occurred in a @@ -255,15 +250,6 @@ private static void OnTaskSchedulerUnobservedTaskException(object sender, () => ShowErrorMessageBox(e.Exception)); } - /// Show an exception window for an exception that occurred in - /// winforms. - private static void OnWinFormsThreadException(object sender, - ThreadExceptionEventArgs e) - { - Application.Current.Dispatcher.Invoke( - () => ShowErrorMessageBox(e.Exception)); - } - /// The helper method for showing an error message. private static void ShowErrorMessageBox(object ex) { // Ignore these thrown by the debugger diff --git a/WinDirStat.Net.Wpf.Single/Windows/FolderBrowserDialog.cs b/WinDirStat.Net.Wpf.Single/Windows/FolderBrowserDialog.cs deleted file mode 100644 index 5387d09..0000000 --- a/WinDirStat.Net.Wpf.Single/Windows/FolderBrowserDialog.cs +++ /dev/null @@ -1,174 +0,0 @@ -using System; -using System.ComponentModel; -using System.Windows.Forms; -using System.Windows.Interop; -using System.Runtime.InteropServices; -using FormsFolderBrowserDialog = System.Windows.Forms.FolderBrowserDialog; -using Window = System.Windows.Window; - -namespace WinDirStat.Net.Wpf.Windows { - /// - /// A wrapper for the folder browser that makes sure it scrolls to the selected folder. - /// - /// - /// - /// - public class FolderBrowserDialog { - - /// - /// Gets or sets a value indicating whether the New Folder button appears in the folder browser - /// dialog box. - /// - [Browsable(true)] - [DefaultValue(true)] - [Localizable(false)] - public bool ShowNewFolderButton { get; set; } = true; - - /// Gets or sets the path selected by the user. - [Browsable(true)] - [DefaultValue("")] - public string SelectedPath { get; set; } = ""; - - /// Gets or sets the root folder where the browsing starts from. - [Browsable(true)] - [DefaultValue(Environment.SpecialFolder.Desktop)] - public Environment.SpecialFolder RootFolder { get; set; } = Environment.SpecialFolder.Desktop; - - /// - /// Gets or sets the descriptive text displayed above the tree view control in the dialog box. - /// - [Browsable(true)] - [DefaultValue("")] - public string Description { get; set; } = ""; - - /// Shows the folder browser dialog. - /// The result of the dialog. - public bool? ShowDialog() { - return ShowDialog(null); - } - - /// Shows the folder browser dialog. - /// The window that owns the dialog - /// The result of the dialog. - public bool? ShowDialog(Window owner) { - using (FormsFolderBrowserDialog dialog = new FormsFolderBrowserDialog()) { - dialog.ShowNewFolderButton = ShowNewFolderButton; - dialog.SelectedPath = SelectedPath; - dialog.RootFolder = RootFolder; - dialog.Description = Description; - - bool? result = ShowFolderBrowser(dialog, owner); - if (result ?? false) - SelectedPath = dialog.SelectedPath; - return result; - } - } - - /// - /// Using title text to look for the top level dialog window is fragile. - /// In particular, this will fail in non-English applications. - /// - private const string _topLevelSearchString = "Browse For Folder"; - - /// - /// These should be more robust. We find the correct child controls in the dialog - /// by using the GetDlgItem method, rather than the FindWindow(Ex) method, - /// because the dialog item IDs should be constant. - /// - private const int _dlgItemBrowseControl = 0; - private const int _dlgItemTreeView = 100; - - [DllImport("user32.dll", SetLastError = true)] - private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); - - [DllImport("user32.dll")] - private static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem); - - [DllImport("user32.dll", CharSet = CharSet.Auto)] - private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); - - /// - /// Some of the messages that the Tree View control will respond to - /// - private const int TV_FIRST = 0x1100; - private const int TVM_SELECTITEM = (TV_FIRST + 11); - private const int TVM_GETNEXTITEM = (TV_FIRST + 10); - private const int TVM_GETITEM = (TV_FIRST + 12); - private const int TVM_ENSUREVISIBLE = (TV_FIRST + 20); - - /// - /// Constants used to identity specific items in the Tree View control - /// - private const int TVGN_ROOT = 0x0; - private const int TVGN_NEXT = 0x1; - private const int TVGN_CHILD = 0x4; - private const int TVGN_FIRSTVISIBLE = 0x5; - private const int TVGN_NEXTVISIBLE = 0x6; - private const int TVGN_CARET = 0x9; - - /// - /// Calling this method is identical to calling the ShowDialog method of the provided - /// FolderBrowserDialog, except that an attempt will be made to scroll the Tree View - /// to make the currently selected folder visible in the dialog window. - /// - /// - /// - /// - private static bool? ShowFolderBrowser(FormsFolderBrowserDialog dlg, Window owner = null) { - DialogResult result = DialogResult.Cancel; - int retries = 40; - NativeWindow parent = null; - if (owner != null) { - parent = new NativeWindow(); - parent.AssignHandle(new WindowInteropHelper(owner).Handle); - } - - using (Timer t = new Timer()) { - t.Tick += (s, a) => { - if (retries > 0) { - --retries; - IntPtr hwndDlg = FindWindow((string) null, _topLevelSearchString); - if (hwndDlg != IntPtr.Zero) { - IntPtr hwndFolderCtrl = GetDlgItem(hwndDlg, _dlgItemBrowseControl); - if (hwndFolderCtrl != IntPtr.Zero) { - IntPtr hwndTV = GetDlgItem(hwndFolderCtrl, _dlgItemTreeView); - - if (hwndTV != IntPtr.Zero) { - IntPtr item = SendMessage(hwndTV, (uint) TVM_GETNEXTITEM, new IntPtr(TVGN_CARET), IntPtr.Zero); - if (item != IntPtr.Zero) { - // Let's send this 40 times until we drill it into the folder browser's thick skull. - // Otherwise it will just go back to the beginning. - SendMessage(hwndTV, TVM_ENSUREVISIBLE, IntPtr.Zero, item); - //retries = 0; - //t.Stop(); - } - } - } - } - } - - else { - // - // We failed to find the Tree View control. - // - // As a fall back (and this is an UberUgly hack), we will send - // some fake keystrokes to the application in an attempt to force - // the Tree View to scroll to the selected item. - // - t.Stop(); - //SendKeys.Send("{TAB}{TAB}{DOWN}{DOWN}{UP}{UP}"); - } - }; - - t.Interval = 10; - t.Start(); - - result = dlg.ShowDialog(parent); - // Very important, I've learned my lesson - parent.ReleaseHandle(); - } - - return (result == DialogResult.OK); - } - } -} diff --git a/WinDirStat.Net.Wpf/App.config b/WinDirStat.Net.Wpf/App.config deleted file mode 100644 index b50c74f..0000000 --- a/WinDirStat.Net.Wpf/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/WinDirStat.Net.Wpf/App.ico b/WinDirStat.Net.Wpf/App.ico deleted file mode 100644 index 4e4be1a..0000000 Binary files a/WinDirStat.Net.Wpf/App.ico and /dev/null differ diff --git a/WinDirStat.Net.Wpf/App.xaml b/WinDirStat.Net.Wpf/App.xaml deleted file mode 100644 index c6c7b91..0000000 --- a/WinDirStat.Net.Wpf/App.xaml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/WinDirStat.Net.Wpf/App.xaml.cs b/WinDirStat.Net.Wpf/App.xaml.cs deleted file mode 100644 index db4a889..0000000 --- a/WinDirStat.Net.Wpf/App.xaml.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; - -namespace WinDirStat.Net.Wpf { - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application { - } -} diff --git a/WinDirStat.Net.Wpf/Controls/CommandButton.cs b/WinDirStat.Net.Wpf/Controls/CommandButton.cs deleted file mode 100644 index 2da9ec1..0000000 --- a/WinDirStat.Net.Wpf/Controls/CommandButton.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using WinDirStat.Net.Model; -using WinDirStat.Net.Utils; -using WinDirStat.Net.ViewModel; -using WinDirStat.Net.Wpf.Services.Structures; -using WinDirStat.Net.Wpf.Utils; -using WinDirStat.Net.Wpf.ViewModel; - -namespace WinDirStat.Net.Wpf.Controls { - public class CommandButton : ImageButton { - private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - CommandButton button = (CommandButton) d; - - if (e.OldValue is IWpfRelayCommand oldUICommand) - oldUICommand.PropertyChanged -= button.OnCommandPropertyChanged; - if (e.NewValue is IWpfRelayCommand newUICommand) - newUICommand.PropertyChanged += button.OnCommandPropertyChanged; - - d.CoerceValue(SourceProperty); - //d.CoerceValue(ContentProperty); - d.CoerceValue(ToolTipProperty); - } - - private void OnCommandPropertyChanged(object sender, PropertyChangedEventArgs e) { - CoerceValue(SourceProperty); - //CoerceValue(ContentProperty); - CoerceValue(ToolTipProperty); - } - - // Set the header to the command text if no header has been explicitly specified - /*private static object CoerceContent(DependencyObject d, object value) { - CommandButton button = (CommandButton) d; - RelayUICommand uiCommand; - - // If no header has been set, use the command's text - if (button.IsValueUnsetAndNull(ContentProperty) && button.Command is RelayUICommand uiCommand) { - value = uiCommand.Text; - } - - return value; - }*/ - - - // Set the icon to the command text if no icon has been explicitly specified - private static object CoerceSource(DependencyObject d, object value) { - CommandButton button = (CommandButton) d; - - // If no icon has been set, use the command's icon - if (button.IsValueUnsetAndNull(SourceProperty, value) && button.Command is IWpfRelayCommand uiCommand) { - value = uiCommand.Icon; - } - return value; - } - - // Gets the input gesture text from the command text if it hasn't been explicitly specified - private static object CoerceToolTip(DependencyObject d, object value) { - CommandButton button = (CommandButton) d; - - if (button.IsValueUnsetAndNull(ToolTipProperty, value) && button.Command is IWpfRelayCommand uiCommand) { - - string tooltip = ""; - if (!string.IsNullOrEmpty(uiCommand.Text)) { - tooltip += uiCommand.Text; - // Remove ellipses - if (tooltip.EndsWith("...")) - tooltip = tooltip.Substring(0, tooltip.Length - 3); - } - if (uiCommand.InputGesture != null) { - if (!string.IsNullOrEmpty(tooltip)) - tooltip += " "; - tooltip += $"({uiCommand.InputGesture.GetDisplayStringForCulture(CultureInfo.CurrentCulture)})"; - } - return tooltip; - } - - return value; - } - - static CommandButton() { - CommandProperty.AddOwner(typeof(CommandButton), - new FrameworkPropertyMetadata(OnCommandChanged)); - //ContentProperty.AddOwner(typeof(CommandButton), - // new FrameworkPropertyMetadata(null, CoerceContent)); - SourceProperty.AddOwner(typeof(CommandButton), - new FrameworkPropertyMetadata(null, CoerceSource)); - ToolTipProperty.AddOwner(typeof(CommandButton), - new FrameworkPropertyMetadata(null, CoerceToolTip)); - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/CommandMenuItem.cs b/WinDirStat.Net.Wpf/Controls/CommandMenuItem.cs deleted file mode 100644 index 3fee95b..0000000 --- a/WinDirStat.Net.Wpf/Controls/CommandMenuItem.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; -using WinDirStat.Net.Model; -using WinDirStat.Net.Utils; -using WinDirStat.Net.ViewModel; -using WinDirStat.Net.Wpf.Services.Structures; -using WinDirStat.Net.Wpf.Utils; -using WinDirStat.Net.Wpf.ViewModel; - -namespace WinDirStat.Net.Wpf.Controls { - public class CommandMenuItem : ImageMenuItem { - private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - CommandMenuItem menuItem = (CommandMenuItem) d; - - if (e.OldValue is IWpfRelayCommand oldUICommand) - oldUICommand.PropertyChanged -= menuItem.OnCommandPropertyChanged; - if (e.NewValue is IWpfRelayCommand newUICommand) - newUICommand.PropertyChanged += menuItem.OnCommandPropertyChanged; - - d.CoerceValue(SourceProperty); - d.CoerceValue(HeaderProperty); - d.CoerceValue(InputGestureTextProperty); - } - - private void OnCommandPropertyChanged(object sender, PropertyChangedEventArgs e) { - CoerceValue(SourceProperty); - CoerceValue(HeaderProperty); - CoerceValue(InputGestureTextProperty); - } - - // Set the header to the command text if no header has been explicitly specified - private static object CoerceHeader(DependencyObject d, object value) { - CommandMenuItem menuItem = (CommandMenuItem) d; - IWpfRelayCommand uiCommand; - - // If no header has been set, use the command's text - bool unset = menuItem.IsValueUnsetAndNull(HeaderProperty, value); - if (menuItem.IsValueUnsetAndNull(HeaderProperty, value)) { - uiCommand = menuItem.Command as IWpfRelayCommand; - if (uiCommand != null) { - value = uiCommand.Text; - } - return value; - } - - // If the header had been set to a UICommand by the ItemsControl, replace it with the command's text - uiCommand = value as IWpfRelayCommand; - - if (uiCommand != null) { - // The header is equal to the command. - // If this MenuItem was generated for the command, then go ahead and overwrite the header - // since the generator automatically set the header. - ItemsControl parent = ItemsControl.ItemsControlFromItemContainer(menuItem); - if (parent != null) { - object originalItem = parent.ItemContainerGenerator.ItemFromContainer(menuItem); - if (originalItem == value) - return uiCommand.Text; - } - } - - return value; - } - - - // Set the icon to the command text if no icon has been explicitly specified - private static object CoerceSource(DependencyObject d, object value) { - CommandMenuItem menuItem = (CommandMenuItem) d; - - // If no icon has been set, use the command's text - if (menuItem.IsValueUnsetAndNull(SourceProperty, value) && - menuItem.Command is IWpfRelayCommand uiCommand) - { - value = uiCommand.Icon; - } - - return value; - } - - // Gets the input gesture text from the command text if it hasn't been explicitly specified - private static object CoerceInputGestureText(DependencyObject d, object value) { - MenuItem menuItem = (MenuItem) d; - - if (menuItem.IsValueUnsetAndNull(InputGestureTextProperty, value) && - menuItem.Command is IWpfRelayCommand uiCommand && uiCommand.InputGesture != null) - { - return uiCommand.InputGesture.GetDisplayStringForCulture(CultureInfo.CurrentCulture); - } - - return value; - } - - static CommandMenuItem() { - CommandProperty.AddOwner(typeof(CommandMenuItem), - new FrameworkPropertyMetadata(OnCommandChanged)); - HeaderProperty.AddOwner(typeof(CommandMenuItem), - new FrameworkPropertyMetadata(null, CoerceHeader)); - SourceProperty.AddOwner(typeof(CommandMenuItem), - new FrameworkPropertyMetadata(null, CoerceSource)); - InputGestureTextProperty.AddOwner(typeof(CommandMenuItem), - new FrameworkPropertyMetadata(null, CoerceInputGestureText)); - } - - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FileList/EditTextBox.cs b/WinDirStat.Net.Wpf/Controls/FileList/EditTextBox.cs deleted file mode 100644 index 4a174a4..0000000 --- a/WinDirStat.Net.Wpf/Controls/FileList/EditTextBox.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Controls; -using System.Windows.Input; -using System.Windows.Data; -using System.Windows; -using WinDirStat.Net.ViewModel.Files; - -namespace WinDirStat.Net.Wpf.Controls.FileList { - class EditTextBox : TextBox { - static EditTextBox() { - DefaultStyleKeyProperty.OverrideMetadata(typeof(EditTextBox), - new FrameworkPropertyMetadata(typeof(EditTextBox))); - } - - public EditTextBox() { - Loaded += delegate { Init(); }; - } - - public FileTreeViewItem Item { get; set; } - - public FileItemViewModel Node { - get { return Item.Node; } - } - - void Init() { - Text = Node.LoadEditText(); - Focus(); - SelectAll(); - } - - protected override void OnKeyDown(KeyEventArgs e) { - if (e.Key == Key.Enter) { - Commit(); - } - else if (e.Key == Key.Escape) { - Node.IsEditing = false; - } - } - - protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e) { - if (Node.IsEditing) { - Commit(); - } - } - - bool commiting; - - void Commit() { - if (!commiting) { - commiting = true; - - Node.IsEditing = false; - if (!Node.SaveEditText(Text)) { - Item.Focus(); - } - //Node.RaisePropertyChanged("Text"); - - //if (Node.SaveEditText(Text)) { - // Node.IsEditing = false; - // Node.RaisePropertyChanged("Text"); - //} - //else { - // Init(); - //} - - commiting = false; - } - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FileList/ExtensionMethods.cs b/WinDirStat.Net.Wpf/Controls/FileList/ExtensionMethods.cs deleted file mode 100644 index 3b98cbf..0000000 --- a/WinDirStat.Net.Wpf/Controls/FileList/ExtensionMethods.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Media; -using System.Windows; -using System.Collections; -using System.Windows.Input; - -namespace WinDirStat.Net.Wpf.Controls.FileList { - public static class ExtensionMethods { - public static T FindAncestor(this DependencyObject d) where T : class { - return AncestorsAndSelf(d).OfType().FirstOrDefault(); - } - - public static IEnumerable AncestorsAndSelf(this DependencyObject d) { - while (d != null) { - yield return d; - d = VisualTreeHelper.GetParent(d); - } - } - - public static void AddOnce(this IList list, object item) { - if (!list.Contains(item)) { - list.Add(item); - } - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FileList/FileGridView.cs b/WinDirStat.Net.Wpf/Controls/FileList/FileGridView.cs deleted file mode 100644 index 1f37727..0000000 --- a/WinDirStat.Net.Wpf/Controls/FileList/FileGridView.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Controls; -using System.Windows; -using WinDirStat.Net.Wpf.Controls.SortList; - -namespace WinDirStat.Net.Wpf.Controls.FileList { - public class FileGridView : SortView { - static FileGridView() { - ItemContainerStyleKey = - new ComponentResourceKey(typeof(FileTreeView), "GridViewItemContainerStyleKey"); - } - - public static ResourceKey ItemContainerStyleKey { get; private set; } - - protected override object ItemContainerDefaultStyleKey { - get { - return ItemContainerStyleKey; - } - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FileList/FileTreeNodeView.cs b/WinDirStat.Net.Wpf/Controls/FileList/FileTreeNodeView.cs deleted file mode 100644 index df54396..0000000 --- a/WinDirStat.Net.Wpf/Controls/FileList/FileTreeNodeView.cs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Windows.Controls; -using System.Windows; -using System.Windows.Controls.Primitives; -using System.Windows.Media; -using System.Windows.Input; -using System.ComponentModel; -using System.Collections.Specialized; -using WinDirStat.Net.ViewModel.Files; - -namespace WinDirStat.Net.Wpf.Controls.FileList { - public class FileTreeNodeView : Control { - static FileTreeNodeView() { - DefaultStyleKeyProperty.OverrideMetadata(typeof(FileTreeNodeView), - new FrameworkPropertyMetadata(typeof(FileTreeNodeView))); - } - - public static readonly DependencyProperty TextBackgroundProperty = - DependencyProperty.Register("TextBackground", typeof(Brush), typeof(FileTreeNodeView)); - - public Brush TextBackground { - get => (Brush) GetValue(TextBackgroundProperty); - set => SetValue(TextBackgroundProperty, value); - } - - public FileItemViewModel Node { - get { return DataContext as FileItemViewModel; } - } - - public FileTreeViewItem ParentItem { get; private set; } - - public static readonly DependencyProperty CellEditorProperty = - DependencyProperty.Register("CellEditor", typeof(Control), typeof(FileTreeNodeView), - new FrameworkPropertyMetadata()); - - public Control CellEditor { - get => (Control) GetValue(CellEditorProperty); - set => SetValue(CellEditorProperty, value); - } - - public FileTreeView ParentTreeView { - get { return ParentItem.ParentTreeView; } - } - - internal LinesRenderer LinesRenderer { get; private set; } - - public override void OnApplyTemplate() { - base.OnApplyTemplate(); - LinesRenderer = Template.FindName("linesRenderer", this) as LinesRenderer; - UpdateTemplate(); - } - - protected override void OnVisualParentChanged(DependencyObject oldParent) { - base.OnVisualParentChanged(oldParent); - ParentItem = this.FindAncestor(); - ParentItem.NodeView = this; - } - - protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { - base.OnPropertyChanged(e); - if (e.Property == DataContextProperty) { - UpdateDataContext(e.OldValue as FileItemViewModel, e.NewValue as FileItemViewModel); - } - } - - void UpdateDataContext(FileItemViewModel oldNode, FileItemViewModel newNode) { - if (newNode != null) { - newNode.PropertyChanged += Node_PropertyChanged; - if (Template != null) { - UpdateTemplate(); - } - } - if (oldNode != null) { - oldNode.PropertyChanged -= Node_PropertyChanged; - } - } - - void Node_PropertyChanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == nameof(FileItemViewModel.IsEditing)) { - OnIsEditingChanged(); - } - else if (e.PropertyName == nameof(FileItemViewModel.IsLast)) { - if (ParentTreeView.ShowLines) { - foreach (var child in Node.VisibleDescendantsAndSelf()) { - var container = ParentTreeView.ItemContainerGenerator.ContainerFromItem(child) as FileTreeViewItem; - if (container != null) { - container.NodeView.LinesRenderer.InvalidateVisual(); - } - } - } - } - else if (e.PropertyName == nameof(FileItemViewModel.IsExpanded)) { - if (Node.IsExpanded) - ParentTreeView.HandleExpanding(Node); - } - } - - void OnIsEditingChanged() { - var textEditorContainer = Template.FindName("textEditorContainer", this) as Border; - if (Node.IsEditing) { - if (CellEditor == null) - textEditorContainer.Child = new EditTextBox() { Item = ParentItem }; - else - textEditorContainer.Child = CellEditor; - } - else { - textEditorContainer.Child = null; - } - } - - void UpdateTemplate() { - var spacer = Template.FindName("spacer", this) as FrameworkElement; - spacer.Width = CalculateIndent(); - - var expander = Template.FindName("expander", this) as ToggleButton; - if (ParentTreeView.Root == Node && !ParentTreeView.ShowRootExpander) { - expander.Visibility = Visibility.Collapsed; - } - else { - expander.ClearValue(VisibilityProperty); - } - } - - internal double CalculateIndent() { - int result = 18 * Node.Level; - if (ParentTreeView.ShowRoot) { - if (!ParentTreeView.ShowRootExpander) { - if (ParentTreeView.Root != Node) { - result -= 15; - } - } - } - else { - result -= 19; - } - if (result < 0) { - Debug.WriteLine("Negative indent level detected for node " + Node); - result = 0; - } - return result; - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FileList/FileTreeView.cs b/WinDirStat.Net.Wpf/Controls/FileList/FileTreeView.cs deleted file mode 100644 index c1a7cab..0000000 --- a/WinDirStat.Net.Wpf/Controls/FileList/FileTreeView.cs +++ /dev/null @@ -1,711 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Threading; -using WinDirStat.Net.Wpf.Controls.SortList; -using WinDirStat.Net.Utils; -using WinDirStat.Net.ViewModel.Files; - -namespace WinDirStat.Net.Wpf.Controls.FileList { - public class FileTreeView : SortListView { - static FileTreeView() { - DefaultStyleKeyProperty.OverrideMetadata(typeof(FileTreeView), - new FrameworkPropertyMetadata(typeof(FileTreeView))); - - SelectionModeProperty.OverrideMetadata(typeof(FileTreeView), - new FrameworkPropertyMetadata(SelectionMode.Extended)); - - AlternationCountProperty.OverrideMetadata(typeof(FileTreeView), - new FrameworkPropertyMetadata(2)); - - DefaultItemContainerStyleKey = - new ComponentResourceKey(typeof(FileTreeView), "DefaultItemContainerStyleKey"); - - VirtualizingStackPanel.VirtualizationModeProperty.OverrideMetadata(typeof(FileTreeView), - new FrameworkPropertyMetadata(VirtualizationMode.Recycling)); - - RegisterCommands(); - } - - public static readonly RoutedEvent ActivateEvent = - EventManager.RegisterRoutedEvent("Activate", RoutingStrategy.Bubble, - typeof(RoutedEventHandler), typeof(FileTreeView)); - - public event RoutedEventHandler Activate { - add => AddHandler(ActivateEvent, value); - remove => RemoveHandler(ActivateEvent, value); - } - - public static ResourceKey DefaultItemContainerStyleKey { get; private set; } - - public FileTreeView() { - SetResourceReference(ItemContainerStyleProperty, DefaultItemContainerStyleKey); - } - - public static readonly DependencyProperty RootProperty = - DependencyProperty.Register("Root", typeof(FileItemViewModel), typeof(FileTreeView)); - - public FileItemViewModel Root { - get => (FileItemViewModel) GetValue(RootProperty); - set => SetValue(RootProperty, value); - } - - public static readonly DependencyProperty ShowRootProperty = - DependencyProperty.Register("ShowRoot", typeof(bool), typeof(FileTreeView), - new FrameworkPropertyMetadata(true)); - - public bool ShowRoot { - get => (bool) GetValue(ShowRootProperty); - set => SetValue(ShowRootProperty, value); - } - - public static readonly DependencyProperty ShowRootExpanderProperty = - DependencyProperty.Register("ShowRootExpander", typeof(bool), typeof(FileTreeView), - new FrameworkPropertyMetadata(false)); - - public bool ShowRootExpander { - get => (bool) GetValue(ShowRootExpanderProperty); - set => SetValue(ShowRootExpanderProperty, value); - } - - public static readonly DependencyProperty AllowDropOrderProperty = - DependencyProperty.Register("AllowDropOrder", typeof(bool), typeof(FileTreeView)); - - public bool AllowDropOrder { - get => (bool) GetValue(AllowDropOrderProperty); - set => SetValue(AllowDropOrderProperty, value); - } - - public static readonly DependencyProperty ShowLinesProperty = - DependencyProperty.Register("ShowLines", typeof(bool), typeof(FileTreeView), - new FrameworkPropertyMetadata(true)); - - public bool ShowLines { - get => (bool) GetValue(ShowLinesProperty); - set => SetValue(ShowLinesProperty, value); - } - - public static bool GetShowAlternation(DependencyObject obj) { - return (bool) obj.GetValue(ShowAlternationProperty); - } - - public static void SetShowAlternation(DependencyObject obj, bool value) { - obj.SetValue(ShowAlternationProperty, value); - } - - public static readonly DependencyProperty ShowAlternationProperty = - DependencyProperty.RegisterAttached("ShowAlternation", typeof(bool), typeof(FileTreeView), - new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits)); - - protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { - base.OnPropertyChanged(e); - if (e.Property == RootProperty || - e.Property == ShowRootProperty || - e.Property == ShowRootExpanderProperty) { - Reload(); - } - } - - FileTreeFlattener flattener; - - void Reload() { - if (flattener != null) { - flattener.Stop(); - flattener = null; - } - if (Root != null) { - if (!(ShowRoot && ShowRootExpander)) { - Root.IsExpanded = true; - } - flattener = new FileTreeFlattener(Root, ShowRoot); - flattener.CollectionChanged += Flattener_CollectionChanged; - this.ItemsSource = flattener; - } - else { - this.ItemsSource = null; - } - } - - void Flattener_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - // Deselect nodes that are being hidden, if any remain in the tree - if (e.Action == NotifyCollectionChangedAction.Remove && Items.Count > 0) { - List selectedOldItems = null; - foreach (FileItemViewModel node in e.OldItems) { - if (node.IsSelected) { - if (selectedOldItems == null) - selectedOldItems = new List(); - selectedOldItems.Add(node); - } - } - if (selectedOldItems != null) { - var list = SelectedItems.Cast().Except(selectedOldItems).ToList(); - SetSelectedItems(list); - if (SelectedItem == null && this.IsKeyboardFocusWithin) { - // if we removed all selected nodes, then move the focus to the node - // preceding the first of the old selected nodes - SelectedIndex = Math.Max(0, e.OldStartingIndex - 1); - if (SelectedIndex >= 0) - FocusNode((FileItemViewModel) SelectedItem); - } - } - } - } - - protected override DependencyObject GetContainerForItemOverride() { - return new FileTreeViewItem(); - } - - protected override bool IsItemItsOwnContainerOverride(object item) { - return item is FileTreeViewItem; - } - - protected override void PrepareContainerForItemOverride(DependencyObject element, object item) { - base.PrepareContainerForItemOverride(element, item); - FileTreeViewItem container = element as FileTreeViewItem; - container.ParentTreeView = this; - // Make sure that the line renderer takes into account the new bound data - if (container.NodeView != null) { - container.NodeView.LinesRenderer.InvalidateVisual(); - } - } - - bool doNotScrollOnExpanding; - - /// - /// Handles the node expanding event in the tree view. - /// This method gets called only if the node is in the visible region (a SharpTreeNodeView exists). - /// - internal void HandleExpanding(FileItemViewModel node) { - if (doNotScrollOnExpanding) - return; - /*FileNode lastVisibleChild = node; - while (true) { - FileNode tmp = lastVisibleChild.Children.LastOrDefault(c => c.IsVisible); - if (tmp != null) { - lastVisibleChild = tmp; - } - else { - break; - } - } - if (lastVisibleChild != node) { - // Make the the expanded children are visible; but don't scroll down - // to much (keep node itself visible) - base.ScrollIntoView(lastVisibleChild); - // For some reason, this only works properly when delaying it... - Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action( - delegate { - base.ScrollIntoView(node); - })); - }*/ - } - - protected override void OnKeyDown(KeyEventArgs e) { - FileTreeViewItem container = e.OriginalSource as FileTreeViewItem; - switch (e.Key) { - case Key.Left: - if (container != null && ItemsControl.ItemsControlFromItemContainer(container) == this) { - if (container.Node.IsExpanded) { - container.Node.IsExpanded = false; - } - else if (container.Node.Parent != null) { - this.FocusNode(container.Node.Parent); - } - e.Handled = true; - } - break; - case Key.Right: - if (container != null && ItemsControl.ItemsControlFromItemContainer(container) == this) { - if (!container.Node.IsExpanded && container.Node.ShowExpander) { - container.Node.IsExpanded = true; - } - else if (container.Node.Children.Count > 0) { - // jump to first child: - container.MoveFocus(new TraversalRequest(FocusNavigationDirection.Down)); - } - e.Handled = true; - } - break; - case Key.Return: - if (container != null && Keyboard.Modifiers == ModifierKeys.None && this.SelectedItems.Count == 1 && this.SelectedItem == container.Node) { - e.Handled = true; - container.Node.ActivateItem(); - } - break; - case Key.Space: - if (container != null && Keyboard.Modifiers == ModifierKeys.None && this.SelectedItems.Count == 1 && this.SelectedItem == container.Node) { - e.Handled = true; - /*if (container.Node.IsCheckable) { - if (container.Node.IsChecked == null) // If partially selected, we want to select everything - container.Node.IsChecked = true; - else - container.Node.IsChecked = !container.Node.IsChecked; - } - else {*/ - container.Node.ActivateItem(); - //} - } - break; - case Key.Add: - if (container != null && ItemsControl.ItemsControlFromItemContainer(container) == this) { - if (container.Node.ShowExpander) - container.Node.IsExpanded = true; - e.Handled = true; - } - break; - case Key.Subtract: - if (container != null && ItemsControl.ItemsControlFromItemContainer(container) == this) { - container.Node.IsExpanded = false; - e.Handled = true; - } - break; - case Key.Multiply: - if (container != null && ItemsControl.ItemsControlFromItemContainer(container) == this) { - if (container.Node.ShowExpander) { - container.Node.IsExpanded = true; - ExpandRecursively(container.Node); - } - e.Handled = true; - } - break; - case Key.Divide: - if (container != null && ItemsControl.ItemsControlFromItemContainer(container) == this) { - if (container.Node.Parent != null) { - FocusNode(container.Node.Parent); - } - e.Handled = true; - } - break; - } - if (!e.Handled) - base.OnKeyDown(e); - } - - void ExpandRecursively(FileItemViewModel node) { - if (node.CanExpandRecursively) { - node.IsExpanded = true; - foreach (FileItemViewModel child in node.Children) { - ExpandRecursively(child); - } - } - } - - /// - /// Scrolls the specified node in view and sets keyboard focus on it. - /// - public void FocusNode(FileItemViewModel node) { - if (node == null) - throw new ArgumentNullException("node"); - ScrollIntoView(node); - // WPF's ScrollIntoView() uses the same if/dispatcher construct, so we call OnFocusItem() after the item was brought into view. - if (this.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) { - OnFocusItem(node); - } - else { - this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new DispatcherOperationCallback(this.OnFocusItem), node); - } - } - - public void ScrollIntoView(FileItemViewModel node) { - if (node == null) - throw new ArgumentNullException("node"); - doNotScrollOnExpanding = true; - foreach (FileItemViewModel ancestor in node.Ancestors()) - ancestor.IsExpanded = true; - doNotScrollOnExpanding = false; - base.ScrollIntoView(node); - } - - object OnFocusItem(object item) { - if (ItemContainerGenerator.ContainerFromItem(item) is FrameworkElement element) { - element.Focus(); - Keyboard.Focus(element); - } - return null; - } - - #region Track selection - - protected override void OnSelectionChanged(SelectionChangedEventArgs e) { - foreach (FileItemViewModel node in e.RemovedItems) { - node.IsSelected = false; - } - foreach (FileItemViewModel node in e.AddedItems) { - node.IsSelected = true; - } - base.OnSelectionChanged(e); - } - - #endregion - - #region Drag and Drop (Disabled) - /*protected override void OnDragEnter(DragEventArgs e) { - OnDragOver(e); - } - - protected override void OnDragOver(DragEventArgs e) { - e.Effects = DragDropEffects.None; - - if (Root != null && !ShowRoot) { - e.Handled = true; - e.Effects = Root.GetDropEffect(e, Root.Children.Count); - } - } - - protected override void OnDrop(DragEventArgs e) { - e.Effects = DragDropEffects.None; - - if (Root != null && !ShowRoot) { - e.Handled = true; - e.Effects = Root.GetDropEffect(e, Root.Children.Count); - if (e.Effects != DragDropEffects.None) - Root.InternalDrop(e, Root.Children.Count); - } - } - - internal void HandleDragEnter(WinDirTreeViewItem item, DragEventArgs e) { - HandleDragOver(item, e); - } - - internal void HandleDragOver(WinDirTreeViewItem item, DragEventArgs e) { - HidePreview(); - e.Effects = DragDropEffects.None; - - var target = GetDropTarget(item, e); - if (target != null) { - e.Handled = true; - e.Effects = target.Effect; - ShowPreview(target.Item, target.Place); - } - } - - internal void HandleDrop(WinDirTreeViewItem item, DragEventArgs e) { - try { - HidePreview(); - - var target = GetDropTarget(item, e); - if (target != null) { - e.Handled = true; - e.Effects = target.Effect; - target.Node.InternalDrop(e, target.Index); - } - } - catch (Exception ex) { - Debug.WriteLine(ex.ToString()); - throw; - } - } - - internal void HandleDragLeave(WinDirTreeViewItem item, DragEventArgs e) { - HidePreview(); - e.Handled = true; - } - - class DropTarget { - public WinDirTreeViewItem Item; - public DropPlace Place; - public double Y; - public WinDirNode Node; - public int Index; - public DragDropEffects Effect; - } - - DropTarget GetDropTarget(WinDirTreeViewItem item, DragEventArgs e) { - var dropTargets = BuildDropTargets(item, e); - var y = e.GetPosition(item).Y; - foreach (var target in dropTargets) { - if (target.Y >= y) { - return target; - } - } - return null; - } - - List BuildDropTargets(WinDirTreeViewItem item, DragEventArgs e) { - var result = new List(); - var node = item.Node; - - if (AllowDropOrder) { - TryAddDropTarget(result, item, DropPlace.Before, e); - } - - TryAddDropTarget(result, item, DropPlace.Inside, e); - - if (AllowDropOrder) { - if (node.IsExpanded && node.Children.Count > 0) { - var firstChildItem = ItemContainerGenerator.ContainerFromItem(node.Children[0]) as WinDirTreeViewItem; - TryAddDropTarget(result, firstChildItem, DropPlace.Before, e); - } - else { - TryAddDropTarget(result, item, DropPlace.After, e); - } - } - - var h = item.ActualHeight; - var y1 = 0.2 * h; - var y2 = h / 2; - var y3 = h - y1; - - if (result.Count == 2) { - if (result[0].Place == DropPlace.Inside && - result[1].Place != DropPlace.Inside) { - result[0].Y = y3; - } - else if (result[0].Place != DropPlace.Inside && - result[1].Place == DropPlace.Inside) { - result[0].Y = y1; - } - else { - result[0].Y = y2; - } - } - else if (result.Count == 3) { - result[0].Y = y1; - result[1].Y = y3; - } - if (result.Count > 0) { - result[result.Count - 1].Y = h; - } - return result; - } - - void TryAddDropTarget(List targets, WinDirTreeViewItem item, DropPlace place, DragEventArgs e) { - WinDirNode node; - int index; - - GetNodeAndIndex(item, place, out node, out index); - - if (node != null) { - var effect = node.GetDropEffect(e, index); - if (effect != DragDropEffects.None) { - DropTarget target = new DropTarget() { - Item = item, - Place = place, - Node = node, - Index = index, - Effect = effect - }; - targets.Add(target); - } - } - } - - void GetNodeAndIndex(WinDirTreeViewItem item, DropPlace place, out WinDirNode node, out int index) { - node = null; - index = 0; - - if (place == DropPlace.Inside) { - node = item.Node; - index = node.Children.Count; - } - else if (place == DropPlace.Before) { - if (item.Node.Parent != null) { - node = item.Node.Parent; - index = node.Children.IndexOf(item.Node); - } - } - else { - if (item.Node.Parent != null) { - node = item.Node.Parent; - index = node.Children.IndexOf(item.Node) + 1; - } - } - } - - WinDirNodeView previewNodeView; - InsertMarker insertMarker; - DropPlace previewPlace; - - enum DropPlace { - Before, Inside, After - } - - void ShowPreview(WinDirTreeViewItem item, DropPlace place) { - previewNodeView = item.NodeView; - previewPlace = place; - - if (place == DropPlace.Inside) { - previewNodeView.TextBackground = SystemColors.HighlightBrush; - previewNodeView.Foreground = SystemColors.HighlightTextBrush; - } - else { - if (insertMarker == null) { - var adornerLayer = AdornerLayer.GetAdornerLayer(this); - var adorner = new GeneralAdorner(this); - insertMarker = new InsertMarker(); - adorner.Child = insertMarker; - adornerLayer.Add(adorner); - } - - insertMarker.Visibility = Visibility.Visible; - - var p1 = previewNodeView.TransformToVisual(this).Transform(new Point()); - var p = new Point(p1.X + previewNodeView.CalculateIndent() + 4.5, p1.Y - 3); - - if (place == DropPlace.After) { - p.Y += previewNodeView.ActualHeight; - } - - insertMarker.Margin = new Thickness(p.X, p.Y, 0, 0); - - WinDirNodeView secondNodeView = null; - var index = flattener.IndexOf(item.Node); - - if (place == DropPlace.Before) { - if (index > 0) { - secondNodeView = (ItemContainerGenerator.ContainerFromIndex(index - 1) as WinDirTreeViewItem).NodeView; - } - } - else if (index + 1 < flattener.Count) { - secondNodeView = (ItemContainerGenerator.ContainerFromIndex(index + 1) as WinDirTreeViewItem).NodeView; - } - - var w = p1.X + previewNodeView.ActualWidth - p.X; - - if (secondNodeView != null) { - var p2 = secondNodeView.TransformToVisual(this).Transform(new Point()); - w = Math.Max(w, p2.X + secondNodeView.ActualWidth - p.X); - } - - insertMarker.Width = w + 10; - } - } - - void HidePreview() { - if (previewNodeView != null) { - previewNodeView.ClearValue(WinDirNodeView.TextBackgroundProperty); - previewNodeView.ClearValue(WinDirNodeView.ForegroundProperty); - if (insertMarker != null) { - insertMarker.Visibility = Visibility.Collapsed; - } - previewNodeView = null; - } - }*/ - #endregion - - #region Cut / Copy / Paste / Delete Commands (Disabled) - - static void RegisterCommands() { - /*CommandManager.RegisterClassCommandBinding(typeof(WinDirTreeView), - new CommandBinding(ApplicationCommands.Cut, HandleExecuted_Cut, HandleCanExecute_Cut)); - - CommandManager.RegisterClassCommandBinding(typeof(WinDirTreeView), - new CommandBinding(ApplicationCommands.Copy, HandleExecuted_Copy, HandleCanExecute_Copy)); - - CommandManager.RegisterClassCommandBinding(typeof(WinDirTreeView), - new CommandBinding(ApplicationCommands.Paste, HandleExecuted_Paste, HandleCanExecute_Paste)); - - CommandManager.RegisterClassCommandBinding(typeof(WinDirTreeView), - new CommandBinding(ApplicationCommands.Delete, HandleExecuted_Delete, HandleCanExecute_Delete));*/ - } - - /*static void HandleExecuted_Cut(object sender, ExecutedRoutedEventArgs e) { - e.Handled = true; - WinDirTreeView treeView = (WinDirTreeView) sender; - var nodes = treeView.GetTopLevelSelection().ToArray(); - if (nodes.Length > 0) - nodes[0].Cut(nodes); - } - - static void HandleCanExecute_Cut(object sender, CanExecuteRoutedEventArgs e) { - WinDirTreeView treeView = (WinDirTreeView) sender; - var nodes = treeView.GetTopLevelSelection().ToArray(); - e.CanExecute = nodes.Length > 0 && nodes[0].CanCut(nodes); - e.Handled = true; - } - - static void HandleExecuted_Copy(object sender, ExecutedRoutedEventArgs e) { - e.Handled = true; - WinDirTreeView treeView = (WinDirTreeView) sender; - var nodes = treeView.GetTopLevelSelection().ToArray(); - if (nodes.Length > 0) - nodes[0].Copy(nodes); - } - - static void HandleCanExecute_Copy(object sender, CanExecuteRoutedEventArgs e) { - WinDirTreeView treeView = (WinDirTreeView) sender; - var nodes = treeView.GetTopLevelSelection().ToArray(); - e.CanExecute = nodes.Length > 0 && nodes[0].CanCopy(nodes); - e.Handled = true; - } - - static void HandleExecuted_Paste(object sender, ExecutedRoutedEventArgs e) { - WinDirTreeView treeView = (WinDirTreeView) sender; - var data = Clipboard.GetDataObject(); - if (data != null) { - var selectedNode = (treeView.SelectedItem as WinDirNode) ?? treeView.Root; - if (selectedNode != null) - selectedNode.Paste(data); - } - e.Handled = true; - } - - static void HandleCanExecute_Paste(object sender, CanExecuteRoutedEventArgs e) { - WinDirTreeView treeView = (WinDirTreeView) sender; - var data = Clipboard.GetDataObject(); - if (data == null) { - e.CanExecute = false; - } - else { - var selectedNode = (treeView.SelectedItem as WinDirNode) ?? treeView.Root; - e.CanExecute = selectedNode != null && selectedNode.CanPaste(data); - } - e.Handled = true; - } - - static void HandleExecuted_Delete(object sender, ExecutedRoutedEventArgs e) { - e.Handled = true; - WinDirTreeView treeView = (WinDirTreeView) sender; - var nodes = treeView.GetTopLevelSelection().ToArray(); - if (nodes.Length > 0) - nodes[0].Delete(nodes); - } - - static void HandleCanExecute_Delete(object sender, CanExecuteRoutedEventArgs e) { - WinDirTreeView treeView = (WinDirTreeView) sender; - var nodes = treeView.GetTopLevelSelection().ToArray(); - e.CanExecute = nodes.Length > 0 && nodes[0].CanDelete(nodes); - e.Handled = true; - }*/ - - /// - /// Gets the selected items which do not have any of their ancestors selected. - /// - public IEnumerable GetTopLevelSelection() { - var selection = this.SelectedItems.OfType(); - var selectionHash = new HashSet(selection); - return selection.Where(item => item.Ancestors().All(a => !selectionHash.Contains(a))); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FileList/FileTreeViewItem.cs b/WinDirStat.Net.Wpf/Controls/FileList/FileTreeViewItem.cs deleted file mode 100644 index 3ceaa65..0000000 --- a/WinDirStat.Net.Wpf/Controls/FileList/FileTreeViewItem.cs +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Controls; -using System.Windows; -using System.Windows.Media; -using System.Windows.Input; -using System.Diagnostics; -using WinDirStat.Net.ViewModel.Files; - -namespace WinDirStat.Net.Wpf.Controls.FileList { - public class FileTreeViewItem : ListViewItem { - static FileTreeViewItem() { - DefaultStyleKeyProperty.OverrideMetadata(typeof(FileTreeViewItem), - new FrameworkPropertyMetadata(typeof(FileTreeViewItem))); - } - - public FileItemViewModel Node { - get { return DataContext as FileItemViewModel; } - } - - public FileTreeNodeView NodeView { get; internal set; } - public FileTreeView ParentTreeView { get; internal set; } - - protected override void OnKeyDown(KeyEventArgs e) { - switch (e.Key) { - case Key.F2: - if (Node.IsEditable && ParentTreeView != null && ParentTreeView.SelectedItems.Count == 1 && ParentTreeView.SelectedItems[0] == Node) { - Node.IsEditing = true; - e.Handled = true; - } - break; - case Key.Escape: - if (Node.IsEditing) { - Node.IsEditing = false; - e.Handled = true; - } - break; - } - } - - #region Mouse - - Point startPoint; - bool wasSelected; - bool wasDoubleClick; - - protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { - wasSelected = IsSelected; - if (!IsSelected) { - base.OnMouseLeftButtonDown(e); - } - - if (Mouse.LeftButton == MouseButtonState.Pressed) { - startPoint = e.GetPosition(null); - CaptureMouse(); - - if (e.ClickCount == 2) { - wasDoubleClick = true; - } - } - } - - /*protected override void OnMouseMove(MouseEventArgs e) { - if (IsMouseCaptured) { - var currentPoint = e.GetPosition(null); - if (Math.Abs(currentPoint.X - startPoint.X) >= SystemParameters.MinimumHorizontalDragDistance || - Math.Abs(currentPoint.Y - startPoint.Y) >= SystemParameters.MinimumVerticalDragDistance) { - - var selection = ParentTreeView.GetTopLevelSelection().ToArray(); - Node.StartDrag(this, selection); - } - } - }*/ - - protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { - if (wasDoubleClick) { - wasDoubleClick = false; - Node.ActivateItem(); - if (!e.Handled) { - if (!Node.IsRoot || ParentTreeView.ShowRootExpander) { - Node.IsExpanded = !Node.IsExpanded; - } - } - } - - ReleaseMouseCapture(); - if (wasSelected) { - base.OnMouseLeftButtonDown(e); - } - } - - protected override void OnContextMenuOpening(ContextMenuEventArgs e) { - if (Node != null) - Node.ShowContextMenu(e); - } - - #endregion - - #region Drag and Drop - - /*protected override void OnDragEnter(DragEventArgs e) { - ParentTreeView.HandleDragEnter(this, e); - } - - protected override void OnDragOver(DragEventArgs e) { - ParentTreeView.HandleDragOver(this, e); - } - - protected override void OnDrop(DragEventArgs e) { - ParentTreeView.HandleDrop(this, e); - } - - protected override void OnDragLeave(DragEventArgs e) { - ParentTreeView.HandleDragLeave(this, e); - }*/ - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FileList/GeneralAdorner.cs b/WinDirStat.Net.Wpf/Controls/FileList/GeneralAdorner.cs deleted file mode 100644 index 9a9e702..0000000 --- a/WinDirStat.Net.Wpf/Controls/FileList/GeneralAdorner.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Documents; -using System.Windows; -using System.Windows.Media; - -namespace WinDirStat.Net.Wpf.Controls.FileList { - public class GeneralAdorner : Adorner { - public GeneralAdorner(UIElement target) - : base(target) { - } - - FrameworkElement child; - - public FrameworkElement Child { - get => child; - set { - if (child != value) { - RemoveVisualChild(child); - RemoveLogicalChild(child); - child = value; - AddLogicalChild(value); - AddVisualChild(value); - InvalidateMeasure(); - } - } - } - - protected override int VisualChildrenCount { - get { return child == null ? 0 : 1; } - } - - protected override Visual GetVisualChild(int index) { - return child; - } - - protected override Size MeasureOverride(Size constraint) { - if (child != null) { - child.Measure(constraint); - return child.DesiredSize; - } - return new Size(); - } - - protected override Size ArrangeOverride(Size finalSize) { - if (child != null) { - child.Arrange(new Rect(finalSize)); - return finalSize; - } - return new Size(); - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FileList/InsertMarker.cs b/WinDirStat.Net.Wpf/Controls/FileList/InsertMarker.cs deleted file mode 100644 index 4eeb55d..0000000 --- a/WinDirStat.Net.Wpf/Controls/FileList/InsertMarker.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Controls; -using System.Windows; - -namespace WinDirStat.Net.Wpf.Controls.FileList { - public class InsertMarker : Control { - static InsertMarker() { - DefaultStyleKeyProperty.OverrideMetadata(typeof(InsertMarker), - new FrameworkPropertyMetadata(typeof(InsertMarker))); - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FileList/LinesRenderer.cs b/WinDirStat.Net.Wpf/Controls/FileList/LinesRenderer.cs deleted file mode 100644 index 2ad6b40..0000000 --- a/WinDirStat.Net.Wpf/Controls/FileList/LinesRenderer.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Media; - -namespace WinDirStat.Net.Wpf.Controls.FileList { - class LinesRenderer : FrameworkElement { - static LinesRenderer() { - pen = new Pen(Brushes.LightGray, 1); - pen.Freeze(); - } - - static Pen pen; - - FileTreeNodeView NodeView { - get { return TemplatedParent as FileTreeNodeView; } - } - - protected override void OnRender(DrawingContext dc) { - double indent = NodeView.CalculateIndent(); - Point p = new Point(indent + 4.5, 0); - double endY = Math.Floor(ActualHeight / 2) + 0.5; - - if (!NodeView.Node.IsRoot || NodeView.ParentTreeView.ShowRootExpander) { - dc.DrawLine(pen, new Point(p.X, endY), new Point(p.X + 10.5, endY)); - } - - if (NodeView.Node.IsRoot) return; - - if (NodeView.Node.IsLast) { - dc.DrawLine(pen, p, new Point(p.X, endY)); - } - else { - dc.DrawLine(pen, p, new Point(p.X, ActualHeight)); - } - - var current = NodeView.Node; - while (true) { - p.X -= 18; - current = current.Parent; - if (p.X < 0) break; - if (!current.IsLast) { - dc.DrawLine(pen, p, new Point(p.X, ActualHeight)); - } - } - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FlashyProgressBar.cs b/WinDirStat.Net.Wpf/Controls/FlashyProgressBar.cs deleted file mode 100644 index f5f3921..0000000 --- a/WinDirStat.Net.Wpf/Controls/FlashyProgressBar.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Controls; - -namespace WinDirStat.Net.Wpf.Controls { - public class FlashyProgressBar : ProgressBar { - - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FocusBehavior.cs b/WinDirStat.Net.Wpf/Controls/FocusBehavior.cs deleted file mode 100644 index 7cdacdf..0000000 --- a/WinDirStat.Net.Wpf/Controls/FocusBehavior.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Diagnostics; -using System.Windows; -using System.Windows.Input; -using System.Windows.Interactivity; - -namespace WinDirStat.Net.Wpf.Controls { - /// A behavior for binding to readonly focus of the element. - public class FocusBehavior : Behavior { - - #region Dependency Properties - - /// Gets the property for standard control focus. - public static readonly DependencyProperty IsFocusedProperty = - DependencyProperty.Register( - "IsFocused", typeof(bool), typeof(FocusBehavior), - new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); - - /// Gets the property for keyboard control focus. - public static readonly DependencyProperty IsKeyboardFocusedProperty = - DependencyProperty.Register( - "IsKeyboardFocused", typeof(bool), typeof(FocusBehavior), - new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); - - /// Gets if the control has standard focus. - public bool IsFocused { - get => (bool) GetValue(IsFocusedProperty); - set => SetValue(IsFocusedProperty, value); - } - - /// Gets if the control has keyboard focus. - public bool IsKeyboardFocused { - get => (bool) GetValue(IsKeyboardFocusedProperty); - set => SetValue(IsKeyboardFocusedProperty, value); - } - - #endregion - - #region Override Methods - - /// Attaches the focus events. - protected override void OnAttached() { - base.OnAttached(); - AssociatedObject.GotFocus += OnGotFocus; - AssociatedObject.LostFocus += OnLostFocus; - AssociatedObject.GotKeyboardFocus += OnGotKeyboardFocus; - AssociatedObject.LostKeyboardFocus += OnLostKeyboardFocus; - } - - /// Detaches the focus events. - protected override void OnDetaching() { - base.OnDetaching(); - if (AssociatedObject != null) { - AssociatedObject.GotFocus -= OnGotFocus; - AssociatedObject.LostFocus -= OnLostFocus; - AssociatedObject.GotKeyboardFocus -= OnGotKeyboardFocus; - AssociatedObject.LostKeyboardFocus -= OnLostKeyboardFocus; - } - } - - #endregion - - #region Event Handlers - - /// Called when the control receives standard focus. - private void OnGotFocus(object sender, RoutedEventArgs e) { - Debug.WriteLine("GotFocus"); - IsFocused = true; - } - /// Called when the control loses standard focus. - private void OnLostFocus(object sender, RoutedEventArgs e) { - Debug.WriteLine("LostFocus"); - IsFocused = false; - } - - /// Called when the control receives keyboard focus. - private void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { - Debug.WriteLine("GotKeyboardFocus"); - IsKeyboardFocused = true; - } - /// Called when the control loses keyboard focus. - private void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { - Debug.WriteLine("LostKeyboardFocus"); - IsKeyboardFocused = false; - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FocusExtension - Copy.cs b/WinDirStat.Net.Wpf/Controls/FocusExtension - Copy.cs deleted file mode 100644 index 9fcdf71..0000000 --- a/WinDirStat.Net.Wpf/Controls/FocusExtension - Copy.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Input; - -namespace WinDirStat.Net.Wpf.Controls { - public static class FocusExtension { - public static bool? GetIsFocused(DependencyObject obj) { - return (bool?) obj.GetValue(IsFocusedProperty); - } - - public static void SetIsFocused(DependencyObject obj, bool? value) { - obj.SetValue(IsFocusedProperty, value); - } - - public static readonly DependencyProperty IsFocusedProperty = - DependencyProperty.RegisterAttached( - "IsFocused", typeof(bool?), typeof(FocusExtension), - new FrameworkPropertyMetadata(null, OnIsFocusedPropertyChanged)); - - private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - FrameworkElement element = (FrameworkElement) d; - if (e.OldValue == null) { - element.GotFocus += OnGotFocus; - element.LostFocus += OnLostFocus; - element.GotKeyboardFocus += OnGotKeyboardFocus; - element.LostKeyboardFocus += OnLostKeyboardFocus; - } - else if (e.NewValue == null) { - element.GotFocus -= OnGotFocus; - element.LostFocus -= OnLostFocus; - element.GotKeyboardFocus -= OnGotKeyboardFocus; - element.LostKeyboardFocus -= OnLostKeyboardFocus; - } - - if (((bool?) e.NewValue) ?? false) { - element.Focus(); // Don't care about false values. - //Keyboard.Focus(element); - } - } - - private static void OnGotFocus(object sender, RoutedEventArgs e) { - FrameworkElement element = (FrameworkElement) sender; - Console.WriteLine("GotFocus"); - SetIsFocused(element, true); - } - private static void OnLostFocus(object sender, RoutedEventArgs e) { - FrameworkElement element = (FrameworkElement) sender; - Console.WriteLine("LostFocus"); - SetIsFocused(element, false); - } - - private static void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { - FrameworkElement element = (FrameworkElement) sender; - //SetIsFocused(element, true); - Console.WriteLine("LostKeyboardFocus"); - } - - private static void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { - FrameworkElement element = (FrameworkElement) sender; - //SetIsFocused(element, false); - Console.WriteLine("GotKeyboardFocus"); - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/FocusExtension.cs b/WinDirStat.Net.Wpf/Controls/FocusExtension.cs deleted file mode 100644 index 6dd4d42..0000000 --- a/WinDirStat.Net.Wpf/Controls/FocusExtension.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Input; - -namespace WinDirStat.Net.Wpf.Controls { - public static class FocusExtension { - - - private static readonly DependencyPropertyKey IsFocusedPropertyKey = - DependencyProperty.RegisterAttachedReadOnly( - "IsFocused", typeof(bool?), typeof(FocusExtension), - new FrameworkPropertyMetadata(null, OnIsFocusedPropertyChanged)); - - public static readonly DependencyProperty IsFocusedProperty = - IsFocusedPropertyKey.DependencyProperty; - - /// Gets if the control has focus. - public static bool? GetIsFocused(DependencyObject obj) { - return (bool?) obj.GetValue(IsFocusedProperty); - } - - private static void SetIsFocused(DependencyObject obj, bool? value) { - obj.SetValue(IsFocusedPropertyKey, value); - } - - - private static readonly DependencyPropertyKey IsKeyboardFocusedPropertyKey = - DependencyProperty.RegisterAttachedReadOnly( - "IsKeyboardFocused", typeof(bool?), typeof(FocusExtension), - new FrameworkPropertyMetadata(null, OnIsKeyboardFocusedPropertyChanged)); - - public static readonly DependencyProperty IsKeyboardFocusedProperty = - IsKeyboardFocusedPropertyKey.DependencyProperty; - - public static bool? GetIsKeyboardFocused(DependencyObject obj) { - return (bool?) obj.GetValue(IsKeyboardFocusedProperty); - } - - private static void SetIsKeyboardFocused(DependencyObject obj, bool? value) { - obj.SetValue(IsKeyboardFocusedPropertyKey, value); - } - - private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - FrameworkElement element = (FrameworkElement) d; - if (e.OldValue == null) { - element.GotFocus += OnGotFocus; - element.LostFocus += OnLostFocus; - element.GotKeyboardFocus += OnGotKeyboardFocus; - element.LostKeyboardFocus += OnLostKeyboardFocus; - } - else if (e.NewValue == null) { - element.GotFocus -= OnGotFocus; - element.LostFocus -= OnLostFocus; - element.GotKeyboardFocus -= OnGotKeyboardFocus; - element.LostKeyboardFocus -= OnLostKeyboardFocus; - } - - /*if (((bool?) e.NewValue) ?? false) { - element.Focus(); // Don't care about false values. - //Keyboard.Focus(element); - }*/ - } - - private static void OnIsKeyboardFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - FrameworkElement element = (FrameworkElement) d; - if (e.OldValue == null) { - element.GotFocus += OnGotFocus; - element.LostFocus += OnLostFocus; - element.GotKeyboardFocus += OnGotKeyboardFocus; - element.LostKeyboardFocus += OnLostKeyboardFocus; - } - else if (e.NewValue == null) { - element.GotFocus -= OnGotFocus; - element.LostFocus -= OnLostFocus; - element.GotKeyboardFocus -= OnGotKeyboardFocus; - element.LostKeyboardFocus -= OnLostKeyboardFocus; - } - - /*if (((bool?) e.NewValue) ?? false) { - element.Focus(); // Don't care about false values. - //Keyboard.Focus(element); - }*/ - } - - private static void OnGotFocus(object sender, RoutedEventArgs e) { - FrameworkElement element = (FrameworkElement) sender; - Console.WriteLine("GotFocus"); - SetIsFocused(element, true); - } - private static void OnLostFocus(object sender, RoutedEventArgs e) { - FrameworkElement element = (FrameworkElement) sender; - Console.WriteLine("LostFocus"); - SetIsFocused(element, false); - } - - private static void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { - FrameworkElement element = (FrameworkElement) sender; - //SetIsFocused(element, true); - Console.WriteLine("LostKeyboardFocus"); - } - - private static void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { - FrameworkElement element = (FrameworkElement) sender; - //SetIsFocused(element, false); - Console.WriteLine("GotKeyboardFocus"); - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/GraphView.xaml b/WinDirStat.Net.Wpf/Controls/GraphView.xaml deleted file mode 100644 index 0cc39a5..0000000 --- a/WinDirStat.Net.Wpf/Controls/GraphView.xaml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - diff --git a/WinDirStat.Net.Wpf/Controls/GraphView.xaml.cs b/WinDirStat.Net.Wpf/Controls/GraphView.xaml.cs deleted file mode 100644 index 739a531..0000000 --- a/WinDirStat.Net.Wpf/Controls/GraphView.xaml.cs +++ /dev/null @@ -1,506 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Imaging; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; -using System.Windows.Threading; -using WinDirStat.Net.Utils; -//using Bitmap = System.Drawing.Bitmap; -//using Graphics = System.Drawing.Graphics; -using Brush = System.Drawing.Brush; -using Pen = System.Drawing.Pen; -using Color = System.Drawing.Color; -using Rectangle = System.Drawing.Rectangle; -using WinDirStat.Net.Model.Files; -using WinDirStat.Net.Structures; -using WinDirStat.Net.Rendering; -using WinDirStat.Net.Services; -using WinDirStat.Net.Wpf.ViewModel; -using WinDirStat.Net.ViewModel; -using WinDirStat.Net.Wpf.Utils; - -namespace WinDirStat.Net.Wpf.Controls { - public class GraphViewHoverEventArgs : RoutedEventArgs { - - public FileItemBase Hover; - - public GraphViewHoverEventArgs(RoutedEvent routedEvent, FileItemBase hover) - : base(routedEvent) - { - Hover = hover; - } - } - - public delegate void GraphViewHoverEventHandler(object sender, GraphViewHoverEventArgs e); - - - /// - /// Interaction logic for WpfGraphView.xaml - /// - public partial class GraphView : UserControl { - - public enum HighlightMode { - None, - Extension, - Selection, - } - - public static readonly DependencyProperty RootProperty = - DependencyProperty.Register("Root", typeof(FileItemBase), typeof(GraphView), - new FrameworkPropertyMetadata(null, OnRootChanged)); - - private static void OnRootChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is GraphView graphView) { - FileItemBase root = graphView.Root; - if (root == null) { - graphView.AbortRender(); - } - - graphView.root = root; - graphView.HighlightNone(); - graphView.Hover = null; - if (root != null) { - //lock (graphView.drawBitmapLock) - graphView.RenderAsync(); - } - else { - graphView.Clear(); - } - - } - } - - public FileItemBase Root { - get => (FileItemBase) GetValue(RootProperty); - set => SetValue(RootProperty, value); - } - - private static readonly DependencyPropertyKey HoverPropertyKey = - DependencyProperty.RegisterReadOnly("Hover", typeof(FileItemBase), typeof(GraphView), - new FrameworkPropertyMetadata(null, OnHoverChanged)); - - public static readonly DependencyProperty HoverProperty = - HoverPropertyKey.DependencyProperty; - - private static void OnHoverChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is GraphView graphView) { - FileItemBase hover = e.NewValue as FileItemBase; - graphView.HasHover = hover != null; - graphView.RaiseEvent(new GraphViewHoverEventArgs(HoverChangedEvent, hover)); - } - } - - public FileItemBase Hover { - get => (FileItemBase) GetValue(HoverProperty); - private set => SetValue(HoverPropertyKey, value); - } - - private static readonly DependencyPropertyKey HasHoverPropertyKey = - DependencyProperty.RegisterReadOnly("HasHover", typeof(bool), typeof(GraphView), - new FrameworkPropertyMetadata(false)); - - public static readonly DependencyProperty HasHoverProperty = - HasHoverPropertyKey.DependencyProperty; - - public bool HasHover { - get => (bool) GetValue(HasHoverProperty); - private set => SetValue(HasHoverPropertyKey, value); - } - - public static readonly RoutedEvent HoverChangedEvent = - EventManager.RegisterRoutedEvent("HoverChanged", RoutingStrategy.Bubble, - typeof(GraphViewHoverEventHandler), typeof(GraphView)); - - public event GraphViewHoverEventHandler HoverChanged { - add => AddHandler(HoverChangedEvent, value); - remove => RemoveHandler(HoverChangedEvent, value); - } - - private static readonly DependencyProperty RenderPriorityProperty = - DependencyProperty.Register("RenderPriority", typeof(ThreadPriority), typeof(GraphView), - new FrameworkPropertyMetadata(ThreadPriority.BelowNormal)); - - public ThreadPriority RenderPriority { - get => (ThreadPriority) GetValue(RenderPriorityProperty); - set => SetValue(RenderPriorityProperty, value); - } - - /*private static readonly DependencyProperty ForceDimmedProperty = - DependencyProperty.Register("ForceDimmed", typeof(bool), typeof(GraphView), - new FrameworkPropertyMetadata(false, OnForceDimmedChanged)); - - public bool ForceDimmed { - get => (bool) GetValue(ForceDimmedProperty); - set => SetValue(ForceDimmedProperty, value); - } - - private static void OnForceDimmedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is GraphView graphView) { - graphView.UpdateDimmed(); - if (graphView.ForceDimmed) { - graphView.AbortRender(); - graphView.disabledTreemap = graphView.treemap; - graphView.disabledHighlight = graphView.highlight; - graphView.imageTreemap.Source = graphView.disabledTreemap; - graphView.imageHighlight.Source = graphView.disabledHighlight; - } - else { - graphView.disabledTreemap = null; - // GraphView will render if (!ForceDimmed and Root != null) - graphView.RenderAsync(); - } - } - }*/ - - private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is GraphView graphView) { - graphView.UpdateDimmed(); - if (!graphView.IsEnabled) { - graphView.AbortRender(); - graphView.disabledTreemap = graphView.treemap; - graphView.disabledHighlight = graphView.highlight; - graphView.imageTreemap.Source = graphView.disabledTreemap; - graphView.imageHighlight.Source = graphView.disabledHighlight; - } - else { - graphView.disabledTreemap = null; - graphView.disabledHighlight = null; - // GraphView will render if (!IsEnabled and Root != null) - graphView.RenderAsync(); - } - } - } - - private void UpdateDimmed() { - IsDimmed = IsRenderingTreemap || resizing || !IsEnabled; - } - - private static readonly DependencyPropertyKey IsDimmedPropertyKey = - DependencyProperty.RegisterReadOnly("IsDimmed", typeof(bool), typeof(GraphView), - new FrameworkPropertyMetadata(false, OnIsDimmedChanged)); - - private static void OnIsDimmedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - GraphView graphView = (GraphView) d; - - if (graphView.IsDimmed) - graphView.Hover = null; - else if (graphView.IsMouseOver) - graphView.UpdateHover(); - } - - public static readonly DependencyProperty IsDimmedProperty = - IsDimmedPropertyKey.DependencyProperty; - - public bool IsDimmed { - get => (bool) GetValue(IsDimmedProperty); - private set => SetValue(IsDimmedPropertyKey, value); - } - - private static void OnDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - GraphView graphView = (GraphView) d; - MainViewModel oldViewModel = e.OldValue as MainViewModel; - MainViewModel newViewModel = e.NewValue as MainViewModel; - - if (oldViewModel != null) - oldViewModel.Settings.PropertyChanged -= graphView.OnSettingsChanged; - if (graphView.IsLoaded && newViewModel != null) - newViewModel.Settings.PropertyChanged += graphView.OnSettingsChanged; - graphView.ViewModel = newViewModel; - } - - private void OnSettingsChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - case nameof(SettingsService.TreemapOptions): - case nameof(SettingsService.FilePalette): - RenderAsync(); - break; - case nameof(SettingsService.HighlightColor): - if (highlightMode != HighlightMode.None) - RenderHighlight(treemapSize); - break; - } - } - - private Point2I treemapSize; - private WriteableBitmap treemap; - private Point2I highlightSize; - private WriteableBitmap highlight; - private Bitmap highlightGdi; - private WriteableBitmap disabledTreemap; - private WriteableBitmap disabledHighlight; - private readonly DispatcherTimer resizeTimer; - private Thread renderThread; - private FileItemBase root; - private bool resizing; - /// Check if the running render thread has finished rendering the treemap. - private volatile bool treemapRendered; - private volatile bool fullRender; - //private TreemapOptions options; - - private readonly object renderLock = new object(); - private readonly object drawBitmapLock = new object(); - private FileItemBase[] selection; - private string extension; - private HighlightMode highlightMode; - - static GraphView() { - DataContextProperty.AddOwner(typeof(GraphView), - new FrameworkPropertyMetadata(OnDataContextChanged)); - IsEnabledProperty.AddOwner(typeof(GraphView), - new FrameworkPropertyMetadata(OnIsEnabledChanged)); - } - - public GraphView() { - if (!this.DesignerInitializeComponent("Controls")) - InitializeComponent(); - - resizeTimer = new DispatcherTimer( - TimeSpan.FromMilliseconds(50), - DispatcherPriority.Normal, - OnResizeTimerTick, - Dispatcher); - resizeTimer.Stop(); - treemapSize = Point2I.Zero; - highlightSize = Point2I.Zero; - highlightMode = HighlightMode.None; - treemapRendered = true; - } - - public void HighlightNone() { - highlightMode = HighlightMode.None; - extension = null; - selection = null; - imageHighlight.Source = null; - } - - public void HighlightExtension(string extension) { - if (this.extension == extension) - return; - - highlightMode = HighlightMode.Extension; - this.extension = extension; - selection = null; - if (IsRendering) { - RenderHighlightAsync(); - } - else if (!IsDimmed && Root != null) { - RenderHighlight(treemapSize); - if (imageHighlight.Source != highlight) - imageHighlight.Source = highlight; - } - //RenderHighlightAsync(ThreadPriority.Normal); - //Render(true); - } - - public void HighlightSelection(IEnumerable selection) { - if (this.selection != null && this.selection.Intersect(selection.Cast()).Count() == this.selection.Length) - return; - - highlightMode = HighlightMode.Selection; - this.selection = selection.Cast().ToArray(); - extension = null; - if (IsRendering) { - RenderHighlightAsync(); - } - else if (!IsDimmed && Root != null) { - RenderHighlight(treemapSize); - if (imageHighlight.Source != highlight) - imageHighlight.Source = highlight; - } - //RenderHighlightAsync(ThreadPriority.Normal); - //Render(true); - } - - private void OnLoaded(object sender, RoutedEventArgs e) { - resizeTimer.Start(); - } - - private void OnUnloaded(object sender, RoutedEventArgs e) { - resizeTimer.Stop(); - AbortRender(); - } - - private void OnSizeChanged(object sender, SizeChangedEventArgs e) { - resizing = true; - IsDimmed = true; - // Restart the timer by stopping it first - resizeTimer.Stop(); - resizeTimer.Start(); - } - - private void OnResizeTimerTick(object sender, EventArgs e) { - resizing = false; - UpdateDimmed(); - resizeTimer.Stop(); - RenderAsync(); - } - - - - /// Gets if anything is in the process of being rendered. - private bool IsRendering => renderThread?.IsAlive ?? false; - - /// Gets if the treemap is in the process of being rendered. - private bool IsRenderingTreemap => renderThread?.IsAlive ?? false && fullRender; - - /// A link to the view model that can be accessed outside of the UI thread. - private MainViewModel ViewModel { get; set; } - private SettingsService Settings => ViewModel.Settings; - private TreemapRenderer Treemap => ViewModel.Treemap; - - private TreemapOptions Options { - get => Settings.TreemapOptions; - } - private Rgba32Color HighlightColor { - get => Settings.HighlightColor; - } - - private void Clear() { - AbortRender(); - treemap = null; - highlight = null; - treemapSize = Point2I.Zero; - highlightSize = Point2I.Zero; - } - - public void AbortRender(bool waitForExit = true) { - if (renderThread != null) { - renderThread.Abort(); - renderThread = null; - UpdateDimmed(); - } - } - - public void RenderHighlightAsync(ThreadPriority? priority = null) { - fullRender = !treemapRendered; - RenderAsyncFinal(priority); - } - - public void RenderAsync(ThreadPriority? priority = null) { - fullRender = true; - RenderAsyncFinal(priority); - } - - private void RenderAsyncFinal(ThreadPriority? priority = null) { - if (IsEnabled && Root != null) { - AbortRender(); - treemapRendered = false; - //IsDimmed = true; - Point2I size = new Point2I((int) ActualWidth, (int) ActualHeight); - renderThread = new Thread(() => RenderThread(size)) { - Priority = priority ?? RenderPriority, - Name = "GraphView Render", - }; - renderThread.Start(); - UpdateDimmed(); - } - } - - private void RenderThread(Point2I size) { - try { - if (size.X != 0 && size.Y != 0) { - if (fullRender) { - RenderTreemap(size); - } - treemapRendered = true; - if (highlightMode != HighlightMode.None) { - RenderHighlight(size); - } - } - Dispatcher.Invoke(() => { - // Let the control know we're not rendering anymore - renderThread = null; - imageTreemap.Source = treemap; - if (highlightMode != HighlightMode.None) - imageHighlight.Source = highlight; - UpdateDimmed(); - }); - } - catch (ThreadAbortException) { } - catch (Exception ex) { - Stopwatch sw = Stopwatch.StartNew(); - Dispatcher.Invoke(() => { - Console.WriteLine(ex.ToString()); - renderThread = null; - UpdateDimmed(); - UpdateHover(); - }); - Console.WriteLine($"Took {sw.ElapsedMilliseconds}ms to invoke EXCEPTION Dispatcher"); - } - } - - private void RenderTreemap(Point2I size) { - Stopwatch sw = Stopwatch.StartNew(); - if (treemap == null || treemapSize.X != size.X || treemapSize.Y != size.Y) { - treemapSize = size; - Application.Current.Dispatcher.Invoke(() => { - treemap = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); - }); - } - Treemap.DrawTreemap(treemap, new Rectangle2I(size), root); - //Treemap.DrawTreemap(treemap, new Rectangle2I(size), fileRoot, options); - Console.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render treemap"); - } - private void RenderHighlight(Point2I size) { - Stopwatch sw = Stopwatch.StartNew(); - if (highlight == null || highlightSize.X != size.X || highlightSize.Y != size.Y) { - highlightSize = size; - Application.Current.Dispatcher.Invoke(() => { - highlight = new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null); - }); - highlightGdi?.Dispose(); - highlightGdi = new Bitmap(size.X, size.Y, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - Trace.WriteLine($"Took {sw.ElapsedMilliseconds}ms to setup highlight bitmap"); - } - sw.Restart(); - if (highlightMode == HighlightMode.Extension) { - Treemap.HighlightExtensions(highlight, new Rectangle2I(size), root, Settings.HighlightColor, extension); - } - else if (highlightMode == HighlightMode.Selection) { - Treemap.HighlightItems(highlight, new Rectangle2I(size), Settings.HighlightColor, selection); - } - Trace.WriteLine($"Took {sw.ElapsedMilliseconds}ms to render highlight"); - Trace.WriteLine(""); - } - - private void OnMouseMove(object sender, MouseEventArgs e) { - UpdateHover(e.GetPosition(this).ToPoint2I()); - } - - private void OnMouseLeave(object sender, MouseEventArgs e) { - Hover = null; - } - - private void UpdateHover() { - UpdateHover(Mouse.GetPosition(this).ToPoint2I()); - } - - private void UpdateHover(Point2I point) { - if (root == null) { - Hover = null; - return; - } - if (Hover != null) { - Rectangle2I rc = ((ITreemapItem) Hover).Rectangle; - if (rc.Contains(point)) - return; // Hover is the same - } - Hover = (FileItemBase) TreemapRenderer.FindItemAtPoint(root, point); - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/ImageButton.cs b/WinDirStat.Net.Wpf/Controls/ImageButton.cs deleted file mode 100644 index dca7c21..0000000 --- a/WinDirStat.Net.Wpf/Controls/ImageButton.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using WinDirStat.Net.Utils; -using WinDirStat.Net.Wpf.Utils; - -namespace WinDirStat.Net.Wpf.Controls { - public class ImageButton : Button { - - /// The dependency property for the button's image. - public static readonly DependencyProperty SourceProperty = - DependencyProperty.RegisterAttached("Source", typeof(ImageSource), typeof(ImageButton), - new FrameworkPropertyMetadata(OnSourceChanged)); - - /// Gets or sets the source of the button's image. - [Category("Common")] - public ImageSource Source { - get => (ImageSource) GetValue(SourceProperty); - set => SetValue(SourceProperty, value); - } - - /// Called when the source property for the button is changed. - private static void OnSourceChanged(object sender, DependencyPropertyChangedEventArgs e) { - ImageButton button = (ImageButton) sender; - button.image.Source = button.Source; - - button.CoerceValue(ContentProperty); - } - - private static object CoerceContent(DependencyObject d, object value) { - ImageButton button = (ImageButton) d; - - if (button.IsValueUnsetAndNull(ContentProperty, value)) { - return button.image; - } - return value; - } - - /// The image that contains the buttons's icon. - private Image image; - - /// Initializes the image buttons default style. - static ImageButton() { - //DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageButton), - // new FrameworkPropertyMetadata(typeof(ImageButton))); - ContentProperty.OverrideMetadata(typeof(ImageButton), - new FrameworkPropertyMetadata(null, CoerceContent)); - } - - /// Constructs an empty buttons. - public ImageButton() { - image = new Image() { - Stretch = Stretch.None, - }; - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/ImageMenuItem.cs b/WinDirStat.Net.Wpf/Controls/ImageMenuItem.cs deleted file mode 100644 index 0bd83d0..0000000 --- a/WinDirStat.Net.Wpf/Controls/ImageMenuItem.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using WinDirStat.Net.Utils; -using WinDirStat.Net.Wpf.Utils; - -namespace WinDirStat.Net.Wpf.Controls { - /// A menu item with easy access for setting its icon. - public class ImageMenuItem : MenuItem { - - /// The dependency property for the menu item's image. - public static readonly DependencyProperty SourceProperty = - DependencyProperty.RegisterAttached("Source", typeof(ImageSource), typeof(ImageMenuItem), - new FrameworkPropertyMetadata(OnSourceChanged)); - - /// Gets or sets the source of the menu item's image. - [Category("Common")] - public ImageSource Source { - get => (ImageSource) GetValue(SourceProperty); - set => SetValue(SourceProperty, value); - } - - /// Called when the source property for the menu item is changed. - private static void OnSourceChanged(object sender, DependencyPropertyChangedEventArgs e) { - ImageMenuItem menuItem = (ImageMenuItem) sender; - menuItem.image.Source = menuItem.Source; - } - - private static object CoerceIcon(DependencyObject d, object value) { - ImageMenuItem menuItem = (ImageMenuItem) d; - - if (menuItem.IsValueUnsetAndNull(IconProperty, value)) { - return menuItem.image; - } - return value; - } - - /// The image that contains the menu item's icon. - private Image image; - - /// Initializes the image menu item default style. - static ImageMenuItem() { - //DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageMenuItem), - // new FrameworkPropertyMetadata(typeof(ImageMenuItem))); - IconProperty.OverrideMetadata(typeof(ImageMenuItem), - new FrameworkPropertyMetadata(null, CoerceIcon)); - } - - /// Constructs an empty menu item. - public ImageMenuItem() { - image = new Image() { - Stretch = Stretch.None, - }; - Icon = image; - } - - /// Constructs an menu item with an image and name. - public ImageMenuItem(ImageSource source, string header) { - image = new Image() { - Stretch = Stretch.None, - Source = source, - }; - Icon = image; - Header = header; - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/ListSettings.cs b/WinDirStat.Net.Wpf/Controls/ListSettings.cs deleted file mode 100644 index cc089cd..0000000 --- a/WinDirStat.Net.Wpf/Controls/ListSettings.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace WinDirStat.Net.Wpf.Controls { - public static class ListSettings { - - public static readonly DependencyProperty InactiveSelectionProperty = - DependencyProperty.RegisterAttached("InactiveSelection", typeof(bool), typeof(ListSettings), - new FrameworkPropertyMetadata(true)); - - public static bool GetInactiveSelection(DependencyObject d) { - return (bool) d.GetValue(InactiveSelectionProperty); - } - - public static void SetInactiveSelection(DependencyObject d, bool value) { - d.SetValue(InactiveSelectionProperty, value); - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/PercentageBar.cs b/WinDirStat.Net.Wpf/Controls/PercentageBar.cs deleted file mode 100644 index ed4d326..0000000 --- a/WinDirStat.Net.Wpf/Controls/PercentageBar.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Shapes; - -namespace WinDirStat.Net.Wpf.Controls { - public class PercentageBar : Control { - - public static readonly DependencyProperty FillProperty = - Rectangle.FillProperty.AddOwner(typeof(PercentageBar), - new FrameworkPropertyMetadata(Brushes.LimeGreen)); - - public static readonly DependencyProperty PercentageProperty = - DependencyProperty.Register("Percentage", typeof(double), typeof(PercentageBar), - new FrameworkPropertyMetadata(0d, OnPercentageChanged, CoercePercentage)); - - private static void OnPercentageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is PercentageBar percentageBar) { - percentageBar.UpdatePercentage(); - } - } - - private static object CoercePercentage(DependencyObject d, object baseValue) { - return Math.Max(0d, Math.Min(1d, (double) baseValue)); - } - - public Brush Fill { - get => (Brush) GetValue(FillProperty); - set => SetValue(FillProperty, value); - } - - public double Percentage { - get => (double) GetValue(PercentageProperty); - set => SetValue(PercentageProperty, value); - } - - static PercentageBar() { - DefaultStyleKeyProperty.OverrideMetadata(typeof(PercentageBar), - new FrameworkPropertyMetadata(typeof(PercentageBar))); - SnapsToDevicePixelsProperty.OverrideMetadata(typeof(PercentageBar), - new FrameworkPropertyMetadata(true)); - } - - private ColumnDefinition PART_FillColoumn; - private ColumnDefinition PART_EmptyColoumn; - - public override void OnApplyTemplate() { - base.OnApplyTemplate(); - PART_FillColoumn = GetTemplateChild("PART_FillColoumn") as ColumnDefinition; - PART_EmptyColoumn = GetTemplateChild("PART_EmptyColoumn") as ColumnDefinition; - UpdatePercentage(); - } - - private void UpdatePercentage() { - if (Template != null) { - PART_FillColoumn.Width = new GridLength(Percentage, GridUnitType.Star); - PART_EmptyColoumn.Width = new GridLength(1d - Percentage, GridUnitType.Star); - } - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/RelayUIBinding.cs b/WinDirStat.Net.Wpf/Controls/RelayUIBinding.cs deleted file mode 100644 index 1bdbdd6..0000000 --- a/WinDirStat.Net.Wpf/Controls/RelayUIBinding.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Input; -using WinDirStat.Net.ViewModel; -using WinDirStat.Net.Wpf.Services.Structures; - -namespace WinDirStat.Net.Wpf.Controls { - public class RelayUIBinding : KeyBinding { - - private static void OnCommandChanged(object sender, DependencyPropertyChangedEventArgs e) { - ((RelayUIBinding) sender).OnCommandChanged(e); - } - - private void OnCommandChanged(DependencyPropertyChangedEventArgs e) { - base.Gesture = RelayUICommand?.InputGesture; - } - - static RelayUIBinding() { - CommandProperty.AddOwner(typeof(RelayUIBinding), - new UIPropertyMetadata(OnCommandChanged)); - } - - public IWpfRelayCommand RelayUICommand { - get => Command as IWpfRelayCommand; - } - - public override InputGesture Gesture { - get => base.Gesture; - set => throw new NotSupportedException(); - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/SortList/SortListView.cs b/WinDirStat.Net.Wpf/Controls/SortList/SortListView.cs deleted file mode 100644 index f419048..0000000 --- a/WinDirStat.Net.Wpf/Controls/SortList/SortListView.cs +++ /dev/null @@ -1,352 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; - -namespace WinDirStat.Net.Wpf.Controls.SortList { - public class SortViewEventArgs : RoutedEventArgs { - - public object Mode { get; } - public ListSortDirection Direction { get; } - public bool IsDescending { - get => Direction == ListSortDirection.Descending; - } - - public TEnum ParseMode() { - return (TEnum) Enum.Parse(typeof(TEnum), Mode as string); - } - - public SortViewEventArgs(RoutedEvent routedEvent, object mode, ListSortDirection direction) - : base(routedEvent) - { - Mode = mode; - Direction = direction; - } - } - - public delegate void SortViewEventHandler(object sender, SortViewEventArgs e); - - public class SortListView : ListView { - private struct ColumnPair { - public SortViewColumn Column { get; } - public GridViewColumnHeader Header { get; } - - public ColumnPair(SortViewColumn column, GridViewColumnHeader header) { - Column = column; - Header = header; - } - } - - - //public static ResourceKey CellTemplateKey { get; } = - // new ComponentResourceKey(typeof(SortListView), "CellTemplateKey"); - //public static ResourceKey ColumnHeaderContainerStyleKey { get; } = - // new ComponentResourceKey(typeof(SortListView), "ColumnHeaderContainerStyleKey"); - /*internal static readonly DependencyPropertyKey HeaderSortDirectionPropertyKey = - DependencyProperty.RegisterAttachedReadOnly("HeaderSortDirection", typeof(ListSortDirection?), typeof(SortListView), - new FrameworkPropertyMetadata(null));*/ - - public static readonly DependencyProperty CellTemplateProperty = - GridViewColumn.CellTemplateProperty.AddOwner(typeof(SortListView)); - - public DataTemplate CellTemplate { - get => (DataTemplate) GetValue(CellTemplateProperty); - set => SetValue(CellTemplateProperty, value); - } - - public static readonly DependencyProperty HeaderContainerStyleProperty = - GridViewColumn.HeaderContainerStyleProperty.AddOwner(typeof(SortListView)); - - public Style HeaderContainerStyle { - get => (Style) GetValue(HeaderContainerStyleProperty); - set => SetValue(HeaderContainerStyleProperty, value); - } - - public static readonly RoutedEvent SortEvent = - EventManager.RegisterRoutedEvent("Sort", RoutingStrategy.Bubble, typeof(SortViewEventHandler), typeof(SortListView)); - - public event SortViewEventHandler Sort { - add => AddHandler(SortEvent, value); - remove => RemoveHandler(SortEvent, value); - } - - - internal static readonly DependencyPropertyKey ColumnSortDirectionPropertyKey = - DependencyProperty.RegisterAttachedReadOnly("ColumnSortDirection", typeof(ListSortDirection?), typeof(SortListView), - new FrameworkPropertyMetadata(null)); - - public static readonly DependencyProperty ColumnSortDirectionProperty = - ColumnSortDirectionPropertyKey.DependencyProperty; - - public static ListSortDirection? GetColumnSortDirection(DependencyObject d) { - return (ListSortDirection?) d.GetValue(ColumnSortDirectionProperty); - } - - internal static void SetColumnSortDirection(DependencyObject d, ListSortDirection? value) { - d.SetValue(ColumnSortDirectionPropertyKey, value); - } - - internal static readonly DependencyPropertyKey ColumnHeaderTextAlignmentPropertyKey = - DependencyProperty.RegisterAttachedReadOnly("ColumnHeaderTextAlignment", typeof(TextAlignment), typeof(SortListView), - new FrameworkPropertyMetadata(TextAlignment.Left)); - - public static readonly DependencyProperty ColumnHeaderTextAlignmentProperty = - ColumnHeaderTextAlignmentPropertyKey.DependencyProperty; - - public static TextAlignment GetColumnHeaderTextAlignment(DependencyObject d) { - return (TextAlignment) d.GetValue(ColumnHeaderTextAlignmentProperty); - } - - internal static void SetColumnHeaderTextAlignment(DependencyObject d, TextAlignment value) { - d.SetValue(ColumnHeaderTextAlignmentPropertyKey, value); - } - - public static readonly DependencyProperty SortDirectionProperty = - DependencyProperty.Register("SortDirection", typeof(ListSortDirection), typeof(SortListView), - new FrameworkPropertyMetadata(ListSortDirection.Ascending, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSortChanged)); - - public ListSortDirection SortDirection { - get => (ListSortDirection) GetValue(SortDirectionProperty); - set => SetValue(SortDirectionProperty, value); - } - - public static readonly DependencyProperty SortModeProperty = - DependencyProperty.Register("SortMode", typeof(string), typeof(SortListView), - new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); - - public string SortMode { - get => (string) GetValue(SortModeProperty); - set => SetValue(SortModeProperty, value); - } - - private static void OnSortChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is SortListView listView && !listView.supressSortEvent) { - listView.UpdateColumns(); - listView.OnSort(); - } - } - - private static void OnViewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is SortListView listView) { - if (e.OldValue is SortView oldSortView) { - oldSortView.Columns.CollectionChanged -= listView.OnColumnsChanged; - } - if (e.NewValue is SortView newSortView) { - newSortView.Columns.CollectionChanged += listView.OnColumnsChanged; - //listView.Style = (Style) listView.FindResource(typeof(SortListView)); - } - else if (e.NewValue != null) { - throw new InvalidOperationException($"View is not a {nameof(SortView)}!"); - } - listView.UpdateColumns(); - } - } - - public override void OnApplyTemplate() { - base.OnApplyTemplate(); - UpdateColumns(); - } - - private void UpdateColumns() { - if (!IsLoaded) - return; - object mode = SortMode; - ListSortDirection sortDirection = SortDirection; - foreach (ColumnPair pair in ColumnsPairs) { - if (mode == null || !object.Equals(mode, pair.Column.SortMode)) { - SetColumnSortDirection(pair.Column, null); - SetColumnSortDirection(pair.Header, null); - } - else { - SetColumnSortDirection(pair.Column, sortDirection); - SetColumnSortDirection(pair.Header, sortDirection); - } - } - } - - private void OnColumnsChanged(object sender, NotifyCollectionChangedEventArgs e) { - if (e.Action == NotifyCollectionChangedAction.Move) - return; - - object mode = SortMode; - ListSortDirection sortDirection = SortDirection; - if (!IsLoaded) - return; - if (e.NewItems != null) { - var presenter = Presenter; - if (presenter == null) - return; - - for (int i = 0; i < e.NewItems.Count; i++) { - ColumnPair pair = GetColumnPairAt(presenter, i + e.NewStartingIndex); - if (mode == null || !object.Equals(mode, pair.Column.SortMode)) { - SetColumnSortDirection(pair.Column, null); - SetColumnSortDirection(pair.Header, null); - } - else { - SetColumnSortDirection(pair.Column, sortDirection); - SetColumnSortDirection(pair.Header, sortDirection); - } - } - } - } - - static SortListView() { - DefaultStyleKeyProperty.OverrideMetadata(typeof(SortListView), - new FrameworkPropertyMetadata(typeof(SortListView))); - ViewProperty.OverrideMetadata(typeof(SortListView), - new FrameworkPropertyMetadata(null, OnViewChanged)); - VirtualizingStackPanel.VirtualizationModeProperty.OverrideMetadata(typeof(SortListView), - new FrameworkPropertyMetadata(VirtualizationMode.Recycling)); - Grid.IsSharedSizeScopeProperty.OverrideMetadata(typeof(SortListView), - new FrameworkPropertyMetadata(true)); - - - EventManager.RegisterClassHandler(typeof(SortListView), - GridViewColumnHeader.ClickEvent, new RoutedEventHandler(OnGridViewColumnHeaderClick)); - } - - private static void OnGridViewColumnHeaderClick(object sender, RoutedEventArgs e) { - if (e.OriginalSource is GridViewColumnHeader header && sender is SortListView listView) { - if (!(header.Column is SortViewColumn column)) - return; - - string oldSortMode = listView.SortMode; - string newSortMode = column.SortMode; - - if (!object.Equals(oldSortMode, newSortMode)) { - listView.SetSort(newSortMode, column.DefaultSortDirection); - } - else if (newSortMode != null) { - listView.ToggleSortDirection(); - } - } - - e.Handled = true; - } - - private bool supressSortEvent; - - - public void ToggleSortDirection() { - if (SortDirection == ListSortDirection.Ascending) - SortDirection = ListSortDirection.Descending; - else - SortDirection = ListSortDirection.Ascending; - } - - public SortListView() { - Loaded += OnLoaded; - } - - private void OnLoaded(object sender, RoutedEventArgs e) { - UpdateColumns(); - } - - public void SetSort(string mode, ListSortDirection direction) { - // Do all this extra work to avoid triggering a sort 'only' once, if needed - bool newMode = !object.Equals(mode, SortMode); - bool newDirection = direction != SortDirection; - if (newMode) { - supressSortEvent = true; - if (newDirection) { - SortDirection = direction; - } - SortMode = mode; - supressSortEvent = false; - UpdateColumns(); - OnSort(); - } - else if (newDirection) { - supressSortEvent = true; - SortDirection = direction; - supressSortEvent = false; - UpdateColumns(); - OnSort(); - } - } - - protected virtual void OnSort() { - RaiseEvent(new SortViewEventArgs(SortEvent, SortMode, SortDirection)); - } - - private SortView SortView { - get => View as SortView; - } - - /*private IEnumerable SortColumns { - get { - if (View is SortView sortView) { - return sortView.Columns.Cast(); - } - return Enumerable.Empty(); - } - }*/ - - private GridViewHeaderRowPresenter Presenter { - get => GetDescendantByType(); - } - - private IEnumerable ColumnsPairs { - get { - if (View is SortView sortView) { - var presenter = Presenter; - if (presenter == null) - yield break; - - for (int i = 0; i < sortView.Columns.Count; i++) - yield return GetColumnPairAt(sortView, presenter, i); - } - } - } - - private ColumnPair GetColumnPairAt(GridViewHeaderRowPresenter presenter, int index) { - return new ColumnPair(GetColumnAt(index), GetHeader(SortView, presenter, index)); - } - - private ColumnPair GetColumnPairAt(SortView sortView, GridViewHeaderRowPresenter presenter, int index) { - return new ColumnPair(GetColumnAt(sortView, index), GetHeader(sortView, presenter, index)); - } - - private SortViewColumn GetColumnAt(int index) { - return (SortViewColumn) SortView.Columns[index]; - } - - private SortViewColumn GetColumnAt(SortView sortView, int index) { - return (SortViewColumn) sortView.Columns[index]; - } - - private GridViewColumnHeader GetHeader(SortView sortView, GridViewHeaderRowPresenter presenter, int index) { - return (GridViewColumnHeader) VisualTreeHelper.GetChild(presenter, sortView.Columns.Count - index); - } - - private T GetDescendantByType() where T : Visual { - return GetDescendantByType(this); - } - - private static T GetDescendantByType(Visual element) where T : Visual { - if (element == null) - return null; - if (element is T t) - return t; - - T foundElement = null; - if (element is FrameworkElement frameworkElement) - frameworkElement.ApplyTemplate(); - - for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) { - Visual visual = VisualTreeHelper.GetChild(element, i) as Visual; - foundElement = GetDescendantByType(visual); - if (foundElement != null) - break; - } - return foundElement; - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/SortList/SortView.cs b/WinDirStat.Net.Wpf/Controls/SortList/SortView.cs deleted file mode 100644 index f1b3b22..0000000 --- a/WinDirStat.Net.Wpf/Controls/SortList/SortView.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; - -namespace WinDirStat.Net.Wpf.Controls.SortList { - public class SortView : GridView { - - static SortView() { - ColumnHeaderContainerStyleProperty.OverrideMetadata(typeof(SortView), - new FrameworkPropertyMetadata(SortViewKeys.HeaderContainerLeftAlignStyle)); - } - - protected override object DefaultStyleKey { - get => SortViewStyleKey; - } - - protected override object ItemContainerDefaultStyleKey { - get => SortViewItemContainerStyleKey; - } - - public static ResourceKey SortViewStyleKey { get; } = - new ComponentResourceKey(typeof(SortView), "SortViewStyleKey"); - - public static ResourceKey SortViewItemContainerStyleKey { get; } = - new ComponentResourceKey(typeof(SortView), "SortViewItemContainerStyleKey"); - - public SortView() { - Columns.CollectionChanged += OnColumnsChanged; - } - - private void OnColumnsChanged(object sender, NotifyCollectionChangedEventArgs e) { - // Nothing needs to be changed if moving columns around - if (e.Action == NotifyCollectionChangedAction.Move) - return; - - if (e.NewItems != null) { - foreach (object item in e.NewItems) { - //if (item is SortViewColumn column) - // column.HeaderContainerStyle = SortViewKeys.HeaderContainerLeftAlignStyle; - if (!(item is SortViewColumn)) - throw new InvalidOperationException($"Column is not a {nameof(SortViewColumn)}!"); - } - } - } - - protected override void AddChild(object column) { - if (column is SortViewColumn c) - Columns.Add(c); - else - throw new InvalidOperationException($"column is not a {nameof(SortViewColumn)}!"); - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/SortList/SortViewColumn.cs b/WinDirStat.Net.Wpf/Controls/SortList/SortViewColumn.cs deleted file mode 100644 index 36eb52b..0000000 --- a/WinDirStat.Net.Wpf/Controls/SortList/SortViewColumn.cs +++ /dev/null @@ -1,180 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; - -namespace WinDirStat.Net.Wpf.Controls.SortList { - public class SortViewColumn : GridViewColumn { - - public static readonly DependencyProperty TextAlignmentProperty = - TextBlock.TextAlignmentProperty.AddOwner(typeof(SortViewColumn), - new FrameworkPropertyMetadata(TextAlignment.Left, OnTextAlignmentChanged)); - - private static void OnTextAlignmentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is SortViewColumn column) { - switch (column.TextAlignment) { - case TextAlignment.Left: - column.HeaderContainerStyle = SortViewKeys.HeaderContainerLeftAlignStyle; - break; - case TextAlignment.Right: - column.HeaderContainerStyle = SortViewKeys.HeaderContainerRightAlignStyle; - break; - default: - column.HeaderContainerStyle = SortViewKeys.HeaderContainerCenterAlignStyle; - break; - } - if (column.cellBinding != null) - column.RebuildCellTemplate(); - } - } - - public TextAlignment TextAlignment { - get => (TextAlignment) GetValue(TextAlignmentProperty); - set => SetValue(TextAlignmentProperty, value); - } - - public static readonly DependencyProperty DefaultSortDirectionProperty = - DependencyProperty.Register("DefaultSortDirection", typeof(ListSortDirection), typeof(SortViewColumn), - new FrameworkPropertyMetadata(ListSortDirection.Ascending)); - - public ListSortDirection DefaultSortDirection { - get => (ListSortDirection) GetValue(DefaultSortDirectionProperty); - set => SetValue(DefaultSortDirectionProperty, value); - } - - public static readonly DependencyProperty SortModeProperty = - DependencyProperty.Register("SortMode", typeof(string), typeof(SortViewColumn), - new FrameworkPropertyMetadata(null)); - - public string SortMode { - get => (string) GetValue(SortModeProperty); - set => SetValue(SortModeProperty, value); - } - - public ListSortDirection? SortDirection { - get => SortListView.GetColumnSortDirection(this); - //internal set => SetValue(SortDirectionPropertyKey, value); - } - - public static readonly DependencyProperty CellDataTemplateProperty = - DependencyProperty.Register("CellDataTemplate", typeof(DataTemplate), typeof(SortViewColumn), - new FrameworkPropertyMetadata(OnCellDataTemplateChanged)); - - public DataTemplate CellDataTemplate { - get => (DataTemplate) GetValue(CellDataTemplateProperty); - set => SetValue(CellDataTemplateProperty, value); - } - - static SortViewColumn() { - //HeaderContainerStyleProperty.OverrideMetadata(typeof(SortViewColumn), - // new FrameworkPropertyMetadata(Application.Current.FindResource(SortListView.ColumnHeaderContainerStyleKey))); - //CellTemplateProperty.OverrideMetadata(typeof(SortViewColumn), - // new FrameworkPropertyMetadata(SortListView.CellTemplateKey)); - //HeaderContainerStyleProperty.OverrideMetadata(typeof(SortViewColumn), - // new FrameworkPropertyMetadata(SortViewKeys.HeaderContainerLeftAlignStyle)); - /*CellTemplateProperty.OverrideMetadata(typeof(SortViewColumn), - new FrameworkPropertyMetadata(typeof(SortViewColumn)));*/ - } - - public SortViewColumn() { - HeaderContainerStyle = SortViewKeys.HeaderContainerLeftAlignStyle; - //if (SortViewKeys.HeaderContainerLeftAlignStyle == null) - // throw new InvalidOperationException("HALP!"); - /*SetValue(HeaderContainerStyleProperty, - Activator.CreateInstance(Type.GetType( - "System.Windows.ResourceReferenceExpression, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"), - SortViewKeys.HeaderContainerLeftAlignStyleKey));*/ - } - - /*private static Style headerContainerLeftAlignStyle; - private static Style headerContainerCenterAlignStyle; - private static Style headerContainerRightAlignStyle; - - private static ResourceDictionary resourceDictionary; - - private static ResourceDictionary ResourceDictionary { - get { - if (resourceDictionary == null) { - resourceDictionary = new ResourceDictionary(); - resourceDictionary.Source = new Uri("/WinDirStat.Net;component/Themes/Generic.xaml", UriKind.RelativeOrAbsolute); - } - return resourceDictionary; - } - } - - public static Style HeaderContainerLeftAlignStyle { - get { - if (headerContainerLeftAlignStyle == null) - headerContainerLeftAlignStyle = (Style) ResourceDictionary[HeaderContainerLeftAlignStyleKey]; - return headerContainerLeftAlignStyle; - } - } - - public static Style HeaderContainerCenterAlignStyle { - get { - if (headerContainerCenterAlignStyle == null) - headerContainerCenterAlignStyle = (Style) ResourceDictionary[HeaderContainerCenterAlignStyleKey]; - return headerContainerCenterAlignStyle; - } - } - - public static Style HeaderContainerRightAlignStyle { - get { - if (headerContainerRightAlignStyle == null) - headerContainerRightAlignStyle = (Style) ResourceDictionary[HeaderContainerRightAlignStyleKey]; - return headerContainerRightAlignStyle; - } - } - - public static ResourceKey HeaderContainerLeftAlignStyleKey { get; } = - new ComponentResourceKey(typeof(SortViewColumn), "HeaderContainerLeftAlignStyleKey"); - - public static ResourceKey HeaderContainerCenterAlignStyleKey { get; } = - new ComponentResourceKey(typeof(SortViewColumn), "HeaderContainerCenterAlignStyleKey"); - - public static ResourceKey HeaderContainerRightAlignStyleKey { get; } = - new ComponentResourceKey(typeof(SortViewColumn), "HeaderContainerRightAlignStyleKey");*/ - - private static void OnCellDataTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is SortViewColumn column) { - if (column.cellBinding == null) { - column.CellTemplate = column.CellDataTemplate; - } - } - } - - private void RebuildCellTemplate() { - var factory = new FrameworkElementFactory(typeof(TextBlock)); - factory.SetValue(TextBlock.TextAlignmentProperty, TextAlignment); - factory.SetValue(TextBlock.TextTrimmingProperty, TextTrimming.CharacterEllipsis); - factory.SetBinding(TextBlock.TextProperty, cellBinding); - DataTemplate template = new DataTemplate { - VisualTree = factory, - }; - CellTemplate = template; - } - - public BindingBase CellBinding { - get => cellBinding; - set { - if (cellBinding != value) { - cellBinding = value; - if (cellBinding == null) { - CellTemplate = CellDataTemplate; - } - else { - RebuildCellTemplate(); - } - OnPropertyChanged(new PropertyChangedEventArgs(nameof(CellBinding))); - } - } - } - - private BindingBase cellBinding; - } -} diff --git a/WinDirStat.Net.Wpf/Controls/SortList/SortViewKeys.cs b/WinDirStat.Net.Wpf/Controls/SortList/SortViewKeys.cs deleted file mode 100644 index 8c6dd23..0000000 --- a/WinDirStat.Net.Wpf/Controls/SortList/SortViewKeys.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace WinDirStat.Net.Wpf.Controls.SortList { - public class SortViewKeys { - private static Style headerContainerLeftAlignStyle; - private static Style headerContainerCenterAlignStyle; - private static Style headerContainerRightAlignStyle; - - public static Style HeaderContainerLeftAlignStyle { - get { - if (headerContainerLeftAlignStyle == null) - headerContainerLeftAlignStyle = (Style) Application.Current.FindResource(HeaderContainerLeftAlignStyleKey); - return headerContainerLeftAlignStyle; - } - } - - public static Style HeaderContainerCenterAlignStyle { - get { - if (headerContainerCenterAlignStyle == null) - headerContainerCenterAlignStyle = (Style) Application.Current.FindResource(HeaderContainerCenterAlignStyleKey); - return headerContainerCenterAlignStyle; - } - } - - public static Style HeaderContainerRightAlignStyle { - get { - if (headerContainerRightAlignStyle == null) - headerContainerRightAlignStyle = (Style) Application.Current.FindResource(HeaderContainerRightAlignStyleKey); - return headerContainerRightAlignStyle; - } - } - - public static ResourceKey HeaderContainerLeftAlignStyleKey { get; } = - new ComponentResourceKey(typeof(SortViewKeys), "HeaderContainerLeftAlignStyleKey"); - - public static ResourceKey HeaderContainerCenterAlignStyleKey { get; } = - new ComponentResourceKey(typeof(SortViewKeys), "HeaderContainerCenterAlignStyleKey"); - - public static ResourceKey HeaderContainerRightAlignStyleKey { get; } = - new ComponentResourceKey(typeof(SortViewKeys), "HeaderContainerRightAlignStyleKey"); - } -} diff --git a/WinDirStat.Net.Wpf/Controls/SubtreePercentage.cs b/WinDirStat.Net.Wpf/Controls/SubtreePercentage.cs deleted file mode 100644 index 427dbe8..0000000 --- a/WinDirStat.Net.Wpf/Controls/SubtreePercentage.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Shapes; -using WinDirStat.Net.ViewModel.Files; -using WinDirStat.Net.Wpf.Utils; -using WinDirStat.Net.Wpf.ViewModel; -//using WinDirStat.Net.Wpf.Controls.FileList; - -namespace WinDirStat.Net.Wpf.Controls { - public class SubtreePercentage : Control { - - public static readonly DependencyProperty FillProperty = - Rectangle.FillProperty.AddOwner(typeof(SubtreePercentage)); - - public static readonly DependencyProperty PercentageProperty = - DependencyProperty.Register("Percentage", typeof(double), typeof(SubtreePercentage), - new FrameworkPropertyMetadata(0d, OnPercentageChanged, CoercePercentage)); - - private static void OnPercentageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is SubtreePercentage subtreePercentage) { - subtreePercentage.UpdatePercentage(); - } - } - - private static object CoercePercentage(DependencyObject d, object baseValue) { - return Math.Max(0d, Math.Min(1d, (double) baseValue)); - } - - public Brush Fill { - get => (Brush) GetValue(FillProperty); - set => SetValue(FillProperty, value); - } - - public double Percentage { - get => (double) GetValue(PercentageProperty); - set => SetValue(PercentageProperty, value); - } - - static SubtreePercentage() { - DefaultStyleKeyProperty.OverrideMetadata(typeof(SubtreePercentage), - new FrameworkPropertyMetadata(typeof(SubtreePercentage))); - SnapsToDevicePixelsProperty.OverrideMetadata(typeof(SubtreePercentage), - new FrameworkPropertyMetadata(true)); - } - - private ColumnDefinition PART_FillColoumn; - private ColumnDefinition PART_EmptyColoumn; - - public override void OnApplyTemplate() { - base.OnApplyTemplate(); - PART_FillColoumn = GetTemplateChild("PART_FillColoumn") as ColumnDefinition; - PART_EmptyColoumn = GetTemplateChild("PART_EmptyColoumn") as ColumnDefinition; - UpdatePercentage(); - UpdateTemplate(); - } - - private void UpdatePercentage() { - if (Template != null) { - PART_FillColoumn.Width = new GridLength(Percentage, GridUnitType.Star); - PART_EmptyColoumn.Width = new GridLength(1d - Percentage, GridUnitType.Star); - } - } - - public FileItemViewModel Item { - get => ((FileItemViewModel) DataContext); - } - - /*public FileTreeViewItem ParentItem { get; private set; } - - public FileTreeView ParentTreeView { - get { return ParentItem.ParentTreeView; } - } - - protected override void OnVisualParentChanged(DependencyObject oldParent) { - base.OnVisualParentChanged(oldParent); - ParentItem = this.FindAncestor(); - }*/ - - protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { - base.OnPropertyChanged(e); - if (e.Property == DataContextProperty) { - UpdateDataContext(e.OldValue as FileItemViewModel, e.NewValue as FileItemViewModel); - } - } - - void UpdateDataContext(FileItemViewModel oldNode, FileItemViewModel newNode) { - if (newNode != null && Template != null) { - UpdateTemplate(); - } - } - - void UpdateTemplate() { - var spacer = GetTemplateChild("PART_SpacerColumn") as ColumnDefinition; - var filler = GetTemplateChild("PART_BarColumn") as ColumnDefinition; - int level = Item.Level; - double intent = CalculateIndent(level); - spacer.Width = new GridLength(1d - intent, GridUnitType.Star); - filler.Width = new GridLength(intent, GridUnitType.Star); - Fill = new SolidColorBrush(Item.ViewModel.Settings.GetSubtreePaletteColor(level).ToWpfColor()); - } - - private const double IndentRatio = 9d / 10d; - - internal double CalculateIndent(int level) { - if (Item == null || level == 0) - return 1d; - return Math.Max(0d, Math.Min(1d, Math.Pow(IndentRatio, level))); - } - } -} diff --git a/WinDirStat.Net.Wpf/Controls/VisibleColumnDefinition.cs b/WinDirStat.Net.Wpf/Controls/VisibleColumnDefinition.cs deleted file mode 100644 index 9ff87a1..0000000 --- a/WinDirStat.Net.Wpf/Controls/VisibleColumnDefinition.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; - -namespace WinDirStat.Net.Wpf.Controls { - public class VisibleColumnDefinition : ColumnDefinition { - - public static readonly DependencyProperty VisibleProperty = - DependencyProperty.Register("Visible", typeof(bool), typeof(VisibleColumnDefinition), - new PropertyMetadata(true, OnVisibleChanged)); - - private static void OnVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - VisibleColumnDefinition col = (VisibleColumnDefinition) d; - - if (col.Visible) { - col.visibleChanging = true; - col.Width = col.storedWidth; - col.MinWidth = col.storedMinWidth; - col.MaxWidth = col.storedMaxWidth; - col.visibleChanging = false; - } - else { - col.visibleChanging = true; - col.storedWidth = col.Width; - col.storedMinWidth = col.MinWidth; - col.storedMaxWidth = col.MaxWidth; - col.MinWidth = 0d; - col.Width = new GridLength(0); - col.MaxWidth = 0d; - col.visibleChanging = false; - } - } - - private static void OnWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - VisibleColumnDefinition col = (VisibleColumnDefinition) d; - if (!col.Visible && !col.visibleChanging) { - col.storedWidth = (GridLength) e.NewValue; - col.Width = new GridLength(0); - } - } - - private static void OnMinWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - VisibleColumnDefinition col = (VisibleColumnDefinition) d; - if (!col.Visible && !col.visibleChanging) { - col.storedMinWidth = (double) e.NewValue; - col.MinWidth = 0; - } - } - - private static void OnMaxWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - VisibleColumnDefinition col = (VisibleColumnDefinition) d; - if (!col.Visible && !col.visibleChanging) { - col.storedMaxWidth = (double) e.NewValue; - col.MaxWidth = 0; - } - } - - static VisibleColumnDefinition() { - WidthProperty.AddOwner(typeof(VisibleColumnDefinition), - new FrameworkPropertyMetadata(WidthProperty.DefaultMetadata.DefaultValue, OnWidthChanged)); - MinWidthProperty.AddOwner(typeof(VisibleColumnDefinition), - new FrameworkPropertyMetadata(MinWidthProperty.DefaultMetadata.DefaultValue, OnMinWidthChanged)); - MaxWidthProperty.AddOwner(typeof(VisibleColumnDefinition), - new FrameworkPropertyMetadata(MaxWidthProperty.DefaultMetadata.DefaultValue, OnMaxWidthChanged)); - } - - public bool Visible { - get => (bool) GetValue(VisibleProperty); - set => SetValue(VisibleProperty, value); - } - - private bool visibleChanging = false; - private GridLength storedWidth = (GridLength) WidthProperty.DefaultMetadata.DefaultValue; - private double storedMinWidth = (double) MinWidthProperty.DefaultMetadata.DefaultValue; - private double storedMaxWidth = (double) MaxWidthProperty.DefaultMetadata.DefaultValue; - } -} diff --git a/WinDirStat.Net.Wpf/Controls/VisibleRowDefinition.cs b/WinDirStat.Net.Wpf/Controls/VisibleRowDefinition.cs deleted file mode 100644 index 159a59f..0000000 --- a/WinDirStat.Net.Wpf/Controls/VisibleRowDefinition.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; - -namespace WinDirStat.Net.Wpf.Controls { - public class VisibleRowDefinition : RowDefinition { - - public static readonly DependencyProperty VisibleProperty = - DependencyProperty.Register("Visible", typeof(bool), typeof(VisibleRowDefinition), - new PropertyMetadata(true, OnVisibleChanged)); - - private static void OnVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - VisibleRowDefinition row = (VisibleRowDefinition) d; - - if (row.Visible) { - row.visibleChanging = true; - row.Height = row.storedHeight; - row.MinHeight = row.storedMinHeight; - row.MaxHeight = row.storedMaxHeight; - row.visibleChanging = false; - } - else { - row.visibleChanging = true; - row.storedHeight = row.Height; - row.storedMinHeight = row.MinHeight; - row.storedMaxHeight = row.MaxHeight; - row.MinHeight = 0d; - row.Height = new GridLength(0); - row.MaxHeight = 0d; - row.visibleChanging = false; - } - } - - private static void OnHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - VisibleRowDefinition row = (VisibleRowDefinition) d; - if (!row.Visible && !row.visibleChanging) { - row.storedHeight = (GridLength) e.NewValue; - row.Height = new GridLength(0); - } - } - - private static void OnMinHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - VisibleRowDefinition row = (VisibleRowDefinition) d; - if (!row.Visible && !row.visibleChanging) { - row.storedMinHeight = (double) e.NewValue; - row.MinHeight = 0; - } - } - - private static void OnMaxHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - VisibleRowDefinition row = (VisibleRowDefinition) d; - if (!row.Visible && !row.visibleChanging) { - row.storedMaxHeight = (double) e.NewValue; - row.MaxHeight = 0; - } - } - - static VisibleRowDefinition() { - HeightProperty.AddOwner(typeof(VisibleRowDefinition), - new FrameworkPropertyMetadata(HeightProperty.DefaultMetadata.DefaultValue, OnHeightChanged)); - MinHeightProperty.AddOwner(typeof(VisibleRowDefinition), - new FrameworkPropertyMetadata(MinHeightProperty.DefaultMetadata.DefaultValue, OnMinHeightChanged)); - MaxHeightProperty.AddOwner(typeof(VisibleRowDefinition), - new FrameworkPropertyMetadata(MaxHeightProperty.DefaultMetadata.DefaultValue, OnMaxHeightChanged)); - } - - public bool Visible { - get => (bool) GetValue(VisibleProperty); - set => SetValue(VisibleProperty, value); - } - - private bool visibleChanging = false; - private GridLength storedHeight = (GridLength) HeightProperty.DefaultMetadata.DefaultValue; - private double storedMinHeight = (double) MinHeightProperty.DefaultMetadata.DefaultValue; - private double storedMaxHeight = (double) MaxHeightProperty.DefaultMetadata.DefaultValue; - } -} diff --git a/WinDirStat.Net.Wpf/Converters/AttributesFormatter.cs b/WinDirStat.Net.Wpf/Converters/AttributesFormatter.cs deleted file mode 100644 index 3375e51..0000000 --- a/WinDirStat.Net.Wpf/Converters/AttributesFormatter.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Globalization; -using System.IO; -using System.Windows.Data; -using System.Windows.Markup; - -namespace WinDirStat.Net.Wpf.Converters { - public class AttributesFormatter : MarkupExtension, IValueConverter { - public static AttributesFormatter Instance = new AttributesFormatter(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (value is FileAttributes attr) { - string s = ""; - if (attr.HasFlag(FileAttributes.ReadOnly)) s += "R"; - if (attr.HasFlag(FileAttributes.Hidden)) s += "H"; - if (attr.HasFlag(FileAttributes.System)) s += "S"; - if (attr.HasFlag(FileAttributes.Archive)) s += "A"; - if (attr.HasFlag(FileAttributes.Compressed)) s += "C"; - if (attr.HasFlag(FileAttributes.Encrypted)) s += "E"; - return s; - } - return null; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); - } - } -} diff --git a/WinDirStat.Net.Wpf/Converters/ByteFormatter.cs b/WinDirStat.Net.Wpf/Converters/ByteFormatter.cs deleted file mode 100644 index 9cba909..0000000 --- a/WinDirStat.Net.Wpf/Converters/ByteFormatter.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Markup; -using WinDirStat.Net.Utils; - -namespace WinDirStat.Net.Wpf.Converters { - public class ByteFormatter : MarkupExtension, IValueConverter { - public static ByteFormatter Instance = new ByteFormatter(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - try { - return FormatBytes.Format(System.Convert.ToDouble(value)); - } - catch { - return null; - } - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); - } - } -} diff --git a/WinDirStat.Net.Wpf/Converters/CollapsedWhenBoolean.cs b/WinDirStat.Net.Wpf/Converters/CollapsedWhenBoolean.cs deleted file mode 100644 index a8c1717..0000000 --- a/WinDirStat.Net.Wpf/Converters/CollapsedWhenBoolean.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Data; -using System.Windows.Markup; - -namespace WinDirStat.Net.Wpf.Converters { - public class CollapsedWhenFalse : MarkupExtension, IValueConverter { - public static CollapsedWhenFalse Instance = new CollapsedWhenFalse(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return (bool) value ? Visibility.Visible : Visibility.Collapsed; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); - } - } - - public class CollapsedWhenTrue : MarkupExtension, IValueConverter { - public static CollapsedWhenTrue Instance = new CollapsedWhenTrue(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return (bool) value ? Visibility.Collapsed : Visibility.Visible; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); - } - } -} diff --git a/WinDirStat.Net.Wpf/Converters/DirectoryExistsToBoolean.cs b/WinDirStat.Net.Wpf/Converters/DirectoryExistsToBoolean.cs deleted file mode 100644 index dce9d56..0000000 --- a/WinDirStat.Net.Wpf/Converters/DirectoryExistsToBoolean.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Data; -using System.Windows.Markup; - -namespace WinDirStat.Net.Wpf.Converters { - public class DirectoryExistsToBoolean : MarkupExtension, IValueConverter { - public static DirectoryExistsToBoolean Instance = new DirectoryExistsToBoolean(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - try { - string fullPath = Path.GetFullPath(value.ToString()); - return Directory.Exists(fullPath); - } - catch { - // Path must be invalid - return false; - } - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); - } - } -} diff --git a/WinDirStat.Net.Wpf/Converters/FileTimeFormatter.cs b/WinDirStat.Net.Wpf/Converters/FileTimeFormatter.cs deleted file mode 100644 index a895b0f..0000000 --- a/WinDirStat.Net.Wpf/Converters/FileTimeFormatter.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Markup; - -namespace WinDirStat.Net.Wpf.Converters { - public class FileTimeFormatter : MarkupExtension, IValueConverter { - public static FileTimeFormatter Instance = new FileTimeFormatter(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - try { - DateTime dt = (DateTime) value; - if (dt == DateTime.MinValue) - return ""; - string shortDateFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern; - string dtFormatted = dt.ToString(shortDateFormat.Replace("yyyy", "yy")); - return $"{dtFormatted} {dt.ToShortTimeString()}"; - } - catch { - return null; - } - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); - } - } -} diff --git a/WinDirStat.Net.Wpf/Converters/InverseBoolean.cs b/WinDirStat.Net.Wpf/Converters/InverseBoolean.cs deleted file mode 100644 index 640018a..0000000 --- a/WinDirStat.Net.Wpf/Converters/InverseBoolean.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Data; -using System.Windows.Markup; - -namespace WinDirStat.Net.Wpf.Converters { - public class InverseBoolean : MarkupExtension, IValueConverter { - public static InverseBoolean Instance = new InverseBoolean(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return !(bool) value; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - return !(bool) value; - } - } -} diff --git a/WinDirStat.Net.Wpf/Converters/ItemCountFormatter.cs b/WinDirStat.Net.Wpf/Converters/ItemCountFormatter.cs deleted file mode 100644 index 774f754..0000000 --- a/WinDirStat.Net.Wpf/Converters/ItemCountFormatter.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Markup; - -namespace WinDirStat.Net.Wpf.Converters { - public class ItemCountFormatter : MarkupExtension, IValueConverter { - public static ItemCountFormatter Instance = new ItemCountFormatter(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - try { - long l = System.Convert.ToInt64(value); - if (l == -1) - return ""; - return l.ToString("N0"); - } - catch { - return null; - } - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); - } - } -} diff --git a/WinDirStat.Net.Wpf/Converters/RadioButtonConverter.cs b/WinDirStat.Net.Wpf/Converters/RadioButtonConverter.cs deleted file mode 100644 index 35bcb54..0000000 --- a/WinDirStat.Net.Wpf/Converters/RadioButtonConverter.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Data; -using System.Windows.Markup; - -namespace WinDirStat.Net.Wpf.Converters { - public class RadioButtonConverter : MarkupExtension, IValueConverter { - public static RadioButtonConverter Instance = new RadioButtonConverter(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return (parameter?.ToString() == value?.ToString()); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - if ((bool) value) { - if (targetType == typeof(string)) - return parameter.ToString(); - else if (targetType.IsEnum) - return Enum.Parse(targetType, parameter.ToString()); - else - return System.Convert.ChangeType(parameter, targetType); - } - return Binding.DoNothing; - } - } -} diff --git a/WinDirStat.Net.Wpf/Converters/ScaleConverter.cs b/WinDirStat.Net.Wpf/Converters/ScaleConverter.cs deleted file mode 100644 index bb406b1..0000000 --- a/WinDirStat.Net.Wpf/Converters/ScaleConverter.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Markup; - -namespace WinDirStat.Net.Wpf.Converters { - public class ScaleConverter : MarkupExtension, IValueConverter { - public static ScaleConverter Instance = new ScaleConverter(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (targetType == typeof(float)) - return System.Convert.ToSingle(value) * System.Convert.ToSingle(parameter); - else if (targetType == typeof(double)) - return System.Convert.ToDouble(value) * System.Convert.ToDouble(parameter); - else if (targetType == typeof(decimal)) - return System.Convert.ToDecimal(value) * System.Convert.ToDecimal(parameter); - return null; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - if (targetType == typeof(float)) - return System.Convert.ToSingle(value) / System.Convert.ToSingle(parameter); - else if (targetType == typeof(double)) - return System.Convert.ToDouble(value) / System.Convert.ToDouble(parameter); - else if (targetType == typeof(decimal)) - return System.Convert.ToDecimal(value) / System.Convert.ToDecimal(parameter); - return null; - } - } -} diff --git a/WinDirStat.Net.Wpf/Converters/ScanTimeFormatter.cs b/WinDirStat.Net.Wpf/Converters/ScanTimeFormatter.cs deleted file mode 100644 index 7319adc..0000000 --- a/WinDirStat.Net.Wpf/Converters/ScanTimeFormatter.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Markup; - -namespace WinDirStat.Net.Wpf.Converters { - public class ScanTimeFormatter : MarkupExtension, IValueConverter { - public static ScanTimeFormatter Instance = new ScanTimeFormatter(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (value is TimeSpan time) { - // Time - //TimeSpan time = node.Document.ScanTime; - string s = $"{time.Seconds:00}"; - string m = $"{time.Minutes}:"; - string h = ""; - if (time.TotalHours >= 1) { - m = m.PadLeft(2, '0'); - h = $"{time.TotalHours:N0}:"; - } - return $"[ {h}{m}{s} s ]"; - } - return null; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); - } - } -} diff --git a/WinDirStat.Net.Wpf/Converters/TextToHorizontalAlignment.cs b/WinDirStat.Net.Wpf/Converters/TextToHorizontalAlignment.cs deleted file mode 100644 index 930d3e3..0000000 --- a/WinDirStat.Net.Wpf/Converters/TextToHorizontalAlignment.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Data; -using System.Windows.Markup; - -namespace WinDirStat.Net.Wpf.Converters { - public class TextToHorizontalAlignment : MarkupExtension, IValueConverter { - public static TextToHorizontalAlignment Instance = new TextToHorizontalAlignment(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (value is TextAlignment textAlignment) { - switch (textAlignment) { - case TextAlignment.Left: return HorizontalAlignment.Left; - case TextAlignment.Center: return HorizontalAlignment.Center; - case TextAlignment.Right: return HorizontalAlignment.Right; - case TextAlignment.Justify: return HorizontalAlignment.Stretch; - } - } - return null; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - if (value is HorizontalAlignment horizontalAlignment) { - switch (horizontalAlignment) { - case HorizontalAlignment.Left: return TextAlignment.Left; - case HorizontalAlignment.Center: return TextAlignment.Center; - case HorizontalAlignment.Right: return TextAlignment.Right; - case HorizontalAlignment.Stretch: return TextAlignment.Justify; - } - } - return null; - } - } -} diff --git a/WinDirStat.Net.Wpf/Converters/ZeroGridLengthWhenBoolean.cs b/WinDirStat.Net.Wpf/Converters/ZeroGridLengthWhenBoolean.cs deleted file mode 100644 index c87bbcd..0000000 --- a/WinDirStat.Net.Wpf/Converters/ZeroGridLengthWhenBoolean.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Globalization; -using System.Windows; -using System.Windows.Data; -using System.Windows.Markup; - -namespace WinDirStat.Net.Wpf.Converters { - public class ZeroGridLengthWhenFalse : MarkupExtension, IValueConverter { - public static ZeroGridLengthWhenFalse Instance = new ZeroGridLengthWhenFalse(); - - private GridLengthConverter converter = new GridLengthConverter(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return (bool) value ? converter.ConvertFrom(parameter) : new GridLength(0); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); - } - } - public class ZeroGridLengthWhenTrue : MarkupExtension, IValueConverter { - public static ZeroGridLengthWhenTrue Instance = new ZeroGridLengthWhenTrue(); - - private GridLengthConverter converter = new GridLengthConverter(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return (bool) value ? new GridLength(0) : converter.ConvertFrom(parameter); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); - } - } -} diff --git a/WinDirStat.Net.Wpf/Converters/ZeroWhenBoolean.cs b/WinDirStat.Net.Wpf/Converters/ZeroWhenBoolean.cs deleted file mode 100644 index 2fcb026..0000000 --- a/WinDirStat.Net.Wpf/Converters/ZeroWhenBoolean.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Markup; - -namespace WinDirStat.Net.Wpf.Converters { - public class ZeroWhenFalse : MarkupExtension, IValueConverter { - public static ZeroWhenFalse Instance = new ZeroWhenFalse(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return (bool) value ? parameter : 0; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); - } - } - public class ZeroWhenTrue : MarkupExtension, IValueConverter { - public static ZeroWhenTrue Instance = new ZeroWhenTrue(); - - public override object ProvideValue(IServiceProvider serviceProvider) { - return Instance; - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return (bool) value ? 0 : parameter; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); - } - } -} diff --git a/WinDirStat.Net.Wpf/MainWindow.xaml b/WinDirStat.Net.Wpf/MainWindow.xaml deleted file mode 100644 index 7fe84f7..0000000 --- a/WinDirStat.Net.Wpf/MainWindow.xaml +++ /dev/null @@ -1,555 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WinDirStat.Net.Wpf/MainWindow.xaml.cs b/WinDirStat.Net.Wpf/MainWindow.xaml.cs deleted file mode 100644 index f1356a2..0000000 --- a/WinDirStat.Net.Wpf/MainWindow.xaml.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using WinDirStat.Net.ViewModel; -using WinDirStat.Net.ViewModel.Extensions; -using WinDirStat.Net.ViewModel.Files; -using WinDirStat.Net.Wpf.Services.Structures; - -namespace WinDirStat.Net.Wpf { - /// - /// Interaction logic for MainWindow.xaml - /// - public partial class MainWindow : Window { - - #region Constructors - - /// Constructs the . - public MainWindow() { - InitializeComponent(); - } - - #endregion - - #region Properties - - /// Gets the . - public MainViewModel ViewModel => DataContext as MainViewModel; - - #endregion - - #region Event Handlers - - private void OnLoaded(object sender, RoutedEventArgs e) { - ViewModel.WindowOwner = new WpfWindow(this); - } - - private void OnFileSelectionChanged(object sender, SelectionChangedEventArgs e) { - OnFileTreeGotFocus(sender, e); - } - - private void OnExtensionSelectionChanged(object sender, SelectionChangedEventArgs e) { - OnExtensionListGotFocus(sender, e); - } - - private void OnFileTreeGotFocus(object sender, RoutedEventArgs e) { - if (tree.SelectedItems.Count > 0 && ViewModel.IsOpen) { - graphView.HighlightSelection(tree.SelectedItems.Cast().Select(v => v.Model)); - } - } - - private void OnExtensionListGotFocus(object sender, RoutedEventArgs e) { - if (extensionList.SelectedItem != null && ViewModel.IsOpen) { - graphView.HighlightExtension(((ExtensionItemViewModel) extensionList.SelectedItem).Extension); - } - } - private void OnGraphFileSelected(object sender, MouseButtonEventArgs e) { - if (graphView.HasHover) { - FileItemViewModel view = ViewModel.RootItem.FindView(graphView.Hover, true); - tree.FocusNode(view); - tree.SelectedItem = view; - //tree.Focus(); - //Keyboard.Focus(tree); - } - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Properties/App.manifest b/WinDirStat.Net.Wpf/Properties/App.manifest deleted file mode 100644 index a002935..0000000 --- a/WinDirStat.Net.Wpf/Properties/App.manifest +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WinDirStat.Net.Wpf/Properties/AssemblyInfo.cs b/WinDirStat.Net.Wpf/Properties/AssemblyInfo.cs deleted file mode 100644 index 39a043f..0000000 --- a/WinDirStat.Net.Wpf/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Windows; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("WinDirStat.Net")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Trigger's Tools & Games")] -[assembly: AssemblyProduct("WinDirStat.Net")] -[assembly: AssemblyCopyright("Copyright © Robert Jordan {YEAR}")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -//In order to begin building localizable applications, set -//CultureYouAreCodingWith in your .csproj file -//inside a . For example, if you are using US english -//in your source files, set the to en-US. Then uncomment -//the NeutralResourceLanguage attribute below. Update the "en-US" in -//the line below to match the UICulture setting in the project file. - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] - - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] -[assembly: NeutralResourcesLanguage("en-US")] - diff --git a/WinDirStat.Net.Wpf/Resources/FileIcons/FileCollection.png b/WinDirStat.Net.Wpf/Resources/FileIcons/FileCollection.png deleted file mode 100644 index e03dc10..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/FileIcons/FileCollection.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/FileIcons/FreeSpace.png b/WinDirStat.Net.Wpf/Resources/FileIcons/FreeSpace.png deleted file mode 100644 index 0a10df4..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/FileIcons/FreeSpace.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/FileIcons/Missing.png b/WinDirStat.Net.Wpf/Resources/FileIcons/Missing.png deleted file mode 100644 index 815ca6c..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/FileIcons/Missing.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/FileIcons/Shortcut.png b/WinDirStat.Net.Wpf/Resources/FileIcons/Shortcut.png deleted file mode 100644 index 4145e99..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/FileIcons/Shortcut.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/FileIcons/UnknownSpace.png b/WinDirStat.Net.Wpf/Resources/FileIcons/UnknownSpace.png deleted file mode 100644 index d2f3758..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/FileIcons/UnknownSpace.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Close.png b/WinDirStat.Net.Wpf/Resources/Icons/Close.png deleted file mode 100644 index a360f9a..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Close.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Cmd.png b/WinDirStat.Net.Wpf/Resources/Icons/Cmd.png deleted file mode 100644 index 0a653e5..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Cmd.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/CmdElevated.png b/WinDirStat.Net.Wpf/Resources/Icons/CmdElevated.png deleted file mode 100644 index 11bd0d3..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/CmdElevated.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Copy.png b/WinDirStat.Net.Wpf/Resources/Icons/Copy.png deleted file mode 100644 index 5e88bb2..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Copy.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/CopyPath.png b/WinDirStat.Net.Wpf/Resources/Icons/CopyPath.png deleted file mode 100644 index 891b7d4..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/CopyPath.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Cut.png b/WinDirStat.Net.Wpf/Resources/Icons/Cut.png deleted file mode 100644 index 6208549..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Cut.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Delete.png b/WinDirStat.Net.Wpf/Resources/Icons/Delete.png deleted file mode 100644 index b7c941c..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Delete.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Elevate.png b/WinDirStat.Net.Wpf/Resources/Icons/Elevate.png deleted file mode 100644 index 2b03bc7..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Elevate.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/EmptyRecycleBin.png b/WinDirStat.Net.Wpf/Resources/Icons/EmptyRecycleBin.png deleted file mode 100644 index aa6adb2..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/EmptyRecycleBin.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Exit.png b/WinDirStat.Net.Wpf/Resources/Icons/Exit.png deleted file mode 100644 index a72ad58..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Exit.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Expand.png b/WinDirStat.Net.Wpf/Resources/Icons/Expand.png deleted file mode 100644 index 3fb1d43..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Expand.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Explore.png b/WinDirStat.Net.Wpf/Resources/Icons/Explore.png deleted file mode 100644 index b38a935..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Explore.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Open.png b/WinDirStat.Net.Wpf/Resources/Icons/Open.png deleted file mode 100644 index f3cb889..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Open.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Paste.png b/WinDirStat.Net.Wpf/Resources/Icons/Paste.png deleted file mode 100644 index 92bd510..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Paste.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/PowerShell.png b/WinDirStat.Net.Wpf/Resources/Icons/PowerShell.png deleted file mode 100644 index a936359..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/PowerShell.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/PowerShellElevated.png b/WinDirStat.Net.Wpf/Resources/Icons/PowerShellElevated.png deleted file mode 100644 index 3dda9ab..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/PowerShellElevated.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Properties.png b/WinDirStat.Net.Wpf/Resources/Icons/Properties.png deleted file mode 100644 index 512d9fd..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Properties.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/RecycleBin.png b/WinDirStat.Net.Wpf/Resources/Icons/RecycleBin.png deleted file mode 100644 index ea0f449..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/RecycleBin.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Redo.png b/WinDirStat.Net.Wpf/Resources/Icons/Redo.png deleted file mode 100644 index 6ea1ccf..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Redo.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/RefreshSelected.png b/WinDirStat.Net.Wpf/Resources/Icons/RefreshSelected.png deleted file mode 100644 index 330765f..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/RefreshSelected.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Reload.png b/WinDirStat.Net.Wpf/Resources/Icons/Reload.png deleted file mode 100644 index b1a6e05..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Reload.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Run.png b/WinDirStat.Net.Wpf/Resources/Icons/Run.png deleted file mode 100644 index d6018c0..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Run.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Save.png b/WinDirStat.Net.Wpf/Resources/Icons/Save.png deleted file mode 100644 index 5c5c63b..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Save.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Search.png b/WinDirStat.Net.Wpf/Resources/Icons/Search.png deleted file mode 100644 index 2bea427..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Search.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Settings.png b/WinDirStat.Net.Wpf/Resources/Icons/Settings.png deleted file mode 100644 index f1992b8..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Settings.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/ShowFileTypes.png b/WinDirStat.Net.Wpf/Resources/Icons/ShowFileTypes.png deleted file mode 100644 index e03dc10..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/ShowFileTypes.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/ShowTotalSpace.png b/WinDirStat.Net.Wpf/Resources/Icons/ShowTotalSpace.png deleted file mode 100644 index 441e4d1..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/ShowTotalSpace.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/ShowTreemap.png b/WinDirStat.Net.Wpf/Resources/Icons/ShowTreemap.png deleted file mode 100644 index 79e1b8b..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/ShowTreemap.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/Icons/Undo.png b/WinDirStat.Net.Wpf/Resources/Icons/Undo.png deleted file mode 100644 index 52123a2..0000000 Binary files a/WinDirStat.Net.Wpf/Resources/Icons/Undo.png and /dev/null differ diff --git a/WinDirStat.Net.Wpf/Resources/ImageResources.cs b/WinDirStat.Net.Wpf/Resources/ImageResources.cs deleted file mode 100644 index d206c66..0000000 --- a/WinDirStat.Net.Wpf/Resources/ImageResources.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Wpf.Resources { - public static class ImageResources { - - } -} diff --git a/WinDirStat.Net.Wpf/Services/ResourceImagesService.cs b/WinDirStat.Net.Wpf/Services/ResourceImagesService.cs deleted file mode 100644 index ea978dd..0000000 --- a/WinDirStat.Net.Wpf/Services/ResourceImagesService.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.IO; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Wpf.Services { - /// A service for image references. - public class ResourceImagesService : ImagesServiceBase { - - #region Constructors - - /// Constructs the . - public ResourceImagesService(IBitmapFactory bitmapFactory, - IUIService ui) - : base(bitmapFactory, - ui) - { - } - - #endregion - - #region ImagesServiceBase Implementation - - /// Loads the image resource with the specified path. - /// - /// The path of the image resource. - private IImage Load(string path) { - return BitmapFactory.FromResource(Path.Combine("Resources", path)); - } - - /// Loads the icon with the specified name. - /// - /// The name of the icon. - protected override IImage LoadIcon(string name) { - return Load(Path.Combine("Icons", name + ".png")); - } - - /// Loads the file icon with the specified name. - /// - /// The name of the file icon. - protected override IImage LoadFileIcon(string name) { - return Load(Path.Combine("FileIcons", name + ".png")); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Services/Structures/IWpfRelayCommand.cs b/WinDirStat.Net.Wpf/Services/Structures/IWpfRelayCommand.cs deleted file mode 100644 index 23abe96..0000000 --- a/WinDirStat.Net.Wpf/Services/Structures/IWpfRelayCommand.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; -using System.Windows.Media; -using WinDirStat.Net.ViewModel; - -namespace WinDirStat.Net.Wpf.Services.Structures { - public interface IWpfRelayCommand : IRelayUICommand { - - KeyGesture InputGesture { get; } - - ImageSource ImageSource { get; } - - } -} diff --git a/WinDirStat.Net.Wpf/Services/Structures/WpfImage.cs b/WinDirStat.Net.Wpf/Services/Structures/WpfImage.cs deleted file mode 100644 index aea080e..0000000 --- a/WinDirStat.Net.Wpf/Services/Structures/WpfImage.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Structures; -using WinDirStat.Net.Wpf.Utils; - -namespace WinDirStat.Net.Wpf.Services.Structures { - /// An implementation for a UI-independent WPF image. - public class WpfImage : IImage { - - #region Fields - - /// Gets the actual image object. - public ImageSource Source { get; } - - #endregion - - #region Constructors - - /// Constructs the . - public WpfImage(ImageSource source) { - Source = source; - } - - #endregion - - #region Properties - - /// Gets the actual image object. - object IImage.Source => Source; - - #endregion - } - - /// An implementation for a UI-independent WPF bitmap. - public class WpfBitmap : IBitmap { - - #region Fields - - /// Gets the actual bitmap object. - public BitmapSource Source { get; } - /// Gets the width of the bitmap. - public int Width { get; } - /// Gets the height of the bitmap. - public int Height { get; } - - #endregion - - #region Constructors - - /// Constructs the . - public WpfBitmap(BitmapSource source) { - Source = source; - Width = source.PixelWidth; - Height = source.PixelHeight; - } - - #endregion - - #region Properties - - /// Gets the size of the bitmap. - public Point2I Size => new Point2I(Width, Height); - /// Gets the bounds of the bitmap. - public Rectangle2I Bounds => new Rectangle2I(Width, Height); - /// Gets the actual image object. - object IImage.Source => Source; - - #endregion - } - - /// An implementation for a UI-independent WPF bitmap with writeable pixels. - public class WpfWriteableBitmap : IWriteableBitmap { - - #region Fields - - /// Gets the actual bitmap object. - public WriteableBitmap Source { get; } - /// Gets the width of the bitmap. - public int Width { get; } - /// Gets the height of the bitmap. - public int Height { get; } - /// Gets the service for invoking UI actions. - protected readonly IUIService ui; - - #endregion - - #region Constructors - - /// Constructs the . - public WpfWriteableBitmap(IUIService ui, WriteableBitmap source) { - Source = source; - Width = source.PixelWidth; - Height = source.PixelHeight; - this.ui = ui; - } - - #endregion - - #region Pixels - - /// Creates a new array of pixels for populating the bitmap. - public Rgba32Color[] CreatePixels() { - return new Rgba32Color[Width * Height * 4]; - } - /// Gets the bitmap's pixels. - public Rgba32Color[] GetPixels() { - Rgba32Color[] pixels = CreatePixels(); - ui.Invoke(() => Source.CopyPixels(pixels, Width * 4, 0)); - return pixels; - } - /// Sets the bitmap's pixels. - public void SetPixels(Rgba32Color[] pixels) { - ui.Invoke(() => Source.WritePixels(Bounds.ToWpfInt32Rect(), pixels, Stride, 0)); - } - /// Sets the bitmap's pixels. - public unsafe void SetPixels(Rgba32Color* pixels) { - ui.Invoke(() => Source.WritePixels(Bounds.ToWpfInt32Rect(), (IntPtr) pixels, BufferSize, Stride)); - } - - #endregion - - #region Properties - - /// Gets the stride for the bitmap. - public int Stride => Width * 4; - /// Gets the buffer size for the bitmap. - public int BufferSize => Width * Height * 4; - /// Gets the size of the bitmap. - public Point2I Size => new Point2I(Width, Height); - /// Gets the bounds of the bitmap. - public Rectangle2I Bounds => new Rectangle2I(Width, Height); - /// Gets the actual image object. - object IImage.Source => Source; - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Services/Structures/WpfRelayCommand.cs b/WinDirStat.Net.Wpf/Services/Structures/WpfRelayCommand.cs deleted file mode 100644 index 030cf9e..0000000 --- a/WinDirStat.Net.Wpf/Services/Structures/WpfRelayCommand.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using GalaSoft.MvvmLight.CommandWpf; -using WinDirStat.Net.ViewModel; - -namespace WinDirStat.Net.Wpf.Services.Structures { - public class WpfRelayCommand : RelayCommand, IWpfRelayUICommand, IRelayCommand { - - #region Constructors - - /// Constructs the . - /// - /// - /// The execution logic. IMPORTANT: If the action causes a closure, you must set to true to avoid side effects. - /// - /// - /// If true, the target of the Action will be kept as a hard reference, which might cause a memory - /// leak. You should only set this parameter to true if the action is causing a closures. - /// See http://galasoft.ch/s/mvvmweakaction. - /// - /// - /// is null. - public WpfRelayCommand(Action execute, bool keepTargetAlive = false) - : base(execute, null, keepTargetAlive) - { - } - - /// Constructs the . - /// - /// - /// The execution logic. IMPORTANT: If the action causes a closure, you must set to true to avoid side effects. - /// - /// - /// The execution status logic. IMPORTANT: If the func causes a closure, you must set to true to avoid side effects. - /// - /// - /// If true, the target of the Action will be kept as a hard reference, which might cause a memory - /// leak. You should only set this parameter to true if the action is causing a closures. - /// See http://galasoft.ch/s/mvvmweakaction. - /// - /// - /// is null. - public WpfRelayCommand(Action execute, Func canExecute, bool keepTargetAlive = false) - : base(execute, canExecute, keepTargetAlive) - { - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Services/Structures/WpfRelayCommandInfo.cs b/WinDirStat.Net.Wpf/Services/Structures/WpfRelayCommandInfo.cs deleted file mode 100644 index 9279d98..0000000 --- a/WinDirStat.Net.Wpf/Services/Structures/WpfRelayCommandInfo.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Wpf.Services.Structures { - public class WpfRelayCommandInfo : IRelayCommandInfo { - - } -} diff --git a/WinDirStat.Net.Wpf/Services/Structures/WpfRelayUICommand.cs b/WinDirStat.Net.Wpf/Services/Structures/WpfRelayUICommand.cs deleted file mode 100644 index fcda4d1..0000000 --- a/WinDirStat.Net.Wpf/Services/Structures/WpfRelayUICommand.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; -using System.Windows.Media; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.ViewModel; - -namespace WinDirStat.Net.Wpf.Services.Structures { - public class WpfRelayUICommand : WpfRelayCommand, IWpfRelayCommand { - - #region Fields - - public string Text { get; } - public WpfImage Icon { get; } - public WpfShortcut Shortcut { get; } - - #endregion - - #region Constructors - - public WpfRelayUICommand(IRelayUICommandInfo info, Action execute, bool keepTargetAlive = false) - : this(info, execute, null, keepTargetAlive) - { - } - public WpfRelayUICommand(IRelayUICommandInfo info, Action execute, Func canExecute, - bool keepTargetAlive = false) - : base(execute, canExecute, keepTargetAlive) - { - Text = info.Text; - Icon = (WpfImage) info.Icon; - Shortcut = (WpfShortcut) info.Shortcut; - } - - #endregion - - #region Properties - - public KeyGesture InputGesture => Shortcut.Shortcut; - public ImageSource ImageSource => Icon.Source; - - IImage IRelayUICommand.Icon => Icon; - IShortcut IRelayUICommand.Shortcut => Shortcut; - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Services/Structures/WpfShortcut.cs b/WinDirStat.Net.Wpf/Services/Structures/WpfShortcut.cs deleted file mode 100644 index c3841ee..0000000 --- a/WinDirStat.Net.Wpf/Services/Structures/WpfShortcut.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Wpf.Services.Structures { - public class WpfShortcut : IShortcut { - - #region Fields - - /// The actual shortcut object. - public KeyGesture Shortcut { get; } - - #endregion - - #region Constructors - - public WpfShortcut(Key key) : this(key, ModifierKeys.None) { } - public WpfShortcut(Key key, string displayString) : this(key, ModifierKeys.None, displayString) { } - public WpfShortcut(Key key, ModifierKeys modifiers) { - Shortcut = new KeyGesture(key, modifiers); - } - public WpfShortcut(Key key, ModifierKeys modifiers, string displayString) { - Shortcut = new KeyGesture(key, modifiers, displayString); - } - - #endregion - - /// The actual shortcut object. - object IShortcut.Shortcut => Shortcut; - - /// Gets the display text for the shortcut. - public string DisplayText => Shortcut.GetDisplayStringForCulture(CultureInfo.CurrentCulture); - - /// Gets the display image for the shortcut. - public IImage DisplayImage => null; - } -} diff --git a/WinDirStat.Net.Wpf/Services/Structures/WpfUITimer.cs b/WinDirStat.Net.Wpf/Services/Structures/WpfUITimer.cs deleted file mode 100644 index 85ac84e..0000000 --- a/WinDirStat.Net.Wpf/Services/Structures/WpfUITimer.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Windows; -using System.Windows.Threading; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Wpf.Services.Structures { - /// A timer that runs its callbacks on the UI thread. - public class WpfUITimer : IUITimer { - - #region Fields - - /// The wrapped dispatcher timer. - private readonly DispatcherTimer dispatcherTimer; - /// The event handler callback constructed from the action. - private EventHandler handlerCallback; - /// The action used for the callback. - private Action callback; - - #endregion - - #region Constructors - - /// Constructs the see . - /// - /// The interval for the timer. - /// True if the timer runs at normal priority. - /// The callback on the timer tick event. - /// True if the timer should start running. - public WpfUITimer(TimeSpan interval, bool normalPriority, Action callback, bool start) { - this.callback = callback ?? throw new ArgumentNullException(nameof(callback)); - handlerCallback = (o, s) => callback(); - dispatcherTimer = new DispatcherTimer( - interval, - WpfUIService.GetPriority(normalPriority), - handlerCallback, - Application.Current.Dispatcher); - if (!start) - dispatcherTimer.Stop(); - } - - #endregion - - #region Properties - - /// Gets or sets the callback method for the timer. - public Action Callback { - get => callback; - set { - if (callback != value) { - callback = value ?? throw new ArgumentNullException(nameof(Callback)); - dispatcherTimer.Tick -= handlerCallback; - handlerCallback = (o, s) => callback(); - dispatcherTimer.Tick += handlerCallback; - } - } - } - /// Gets or sets the interval for the timer. - public TimeSpan Interval { - get => dispatcherTimer.Interval; - set => dispatcherTimer.Interval = value; - } - /// Gets or sets if the timer is running. - public bool IsRunning { - get => dispatcherTimer.IsEnabled; - set { - if (dispatcherTimer.IsEnabled != value) { - if (value) - dispatcherTimer.Start(); - else - dispatcherTimer.Stop(); - } - } - } - - #endregion - - #region Start/Stop - - /// Starts the timer. - public void Start() { - dispatcherTimer.Start(); - } - /// Stops the timer. - public void Stop() { - dispatcherTimer.Stop(); - } - /// Restarts the timer. - public void Restart() { - dispatcherTimer.Stop(); - dispatcherTimer.Start(); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Services/Structures/WpfWindow.cs b/WinDirStat.Net.Wpf/Services/Structures/WpfWindow.cs deleted file mode 100644 index c2710f3..0000000 --- a/WinDirStat.Net.Wpf/Services/Structures/WpfWindow.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Linq; -using System.Windows; -using System.Windows.Interop; -using WinDirStat.Net.Services.Structures; - -namespace WinDirStat.Net.Wpf.Services.Structures { - /// A WPF implementation of . - public class WpfWindow : IWindow { - - #region Fields - - /// Gets the actual Wpf window. - public Window Window { get; } - - #endregion - - #region Constructors - - /// Constructs the from a . - public WpfWindow(Window window) { - Window = window ?? throw new ArgumentNullException(nameof(window)); - } - - #endregion - - #region Properties - - /// Gets the window that owns this window. - public IWindow Owner { - get => Invoke(() => (Window.Owner != null ? new WpfWindow(Window.Owner) : null)); - } - /// Gets the children owned by this window. - IWindow[] IWindow.Children { - get => Invoke(() => Window.OwnedWindows.Cast().Select(w => (IWindow) new WpfWindow(w)).ToArray()); - } - /// Gets or sets the dialog result. - public bool DialogResult { - get => Invoke(() => Window.DialogResult.HasValue && Window.DialogResult.Value); - set => Invoke(() => Window.DialogResult = value); - } - /// Gets the handle for the window. - public IntPtr Handle => Invoke(() => new WindowInteropHelper(Window).Handle); - /// Gets the actual Wpf window. - object IWindow.Window => Window; - - #endregion - - #region Private Helpers - - /// Invokes the action on the dispatcher thread. - private void Invoke(Action callback) { - Window.Dispatcher.Invoke(callback); - } - - /// Gets the values from the dispatcher thread. - private T Invoke(Func callback) { - return Window.Dispatcher.Invoke(callback); - } - - #endregion - - #region Close - - /// Closes the window. - public void Close() { - Invoke(Window.Close); - } - - /// Called when the window is closed. - public event EventHandler Closed { - add => Invoke(() => Window.Closed += value); - remove => Invoke(() => Window.Closed -= value); - } - - #endregion - - #region Equals - - /// Gets if the two windows are referencing the same window. - /// - /// The window wrapper to compare. - /// True if the interfaces are referencing the same window. - public bool Equals(IWindow window) { - return Window == window?.Window; - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Services/WpfBitmapFactory.cs b/WinDirStat.Net.Wpf/Services/WpfBitmapFactory.cs deleted file mode 100644 index 10ec3fe..0000000 --- a/WinDirStat.Net.Wpf/Services/WpfBitmapFactory.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; -using System.IO; -using System.Reflection; -using System.Windows; -using System.Windows.Interop; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Structures; -using WinDirStat.Net.Wpf.Services.Structures; -using WinDirStat.Net.Wpf.Utils; - -namespace WinDirStat.Net.Wpf.Services { - /// An service for creating and loading bitmaps. - public class WpfBitmapFactory : IBitmapFactory { - - #region Fields - - /// The service for performing UI actions such as dispatcher invoking. - private readonly IUIService ui; - - #endregion - - #region Constructors - - /// Constructs the . - public WpfBitmapFactory(IUIService ui) { - this.ui = ui; - } - - #endregion - - #region Create - - /// Creates a new writeable bitmap. - /// - /// The size of the bitmap. - /// The new writeable bitmap. - public IWriteableBitmap CreateBitmap(Point2I size) { - return ui.Invoke(() => new WpfWriteableBitmap(ui, - new WriteableBitmap(size.X, size.Y, 96, 96, PixelFormats.Bgra32, null))); - } - - #endregion - - #region From Source - - /// Loads a bitmap from the specified resource path. - /// - /// The resource path to load the bitmap from. - /// The assembly to load teh embedded resource from. - /// The loaded bitmap. - public IBitmap FromResource(string resourcePath, Assembly assembly = null) { - assembly = assembly ?? Assembly.GetCallingAssembly(); - return ui.Invoke(() => { - BitmapImage bitmapImage = new BitmapImage(); - bitmapImage.BeginInit(); - bitmapImage.CacheOption = BitmapCacheOption.OnLoad; - bitmapImage.UriSource = WpfUtils.MakePackUri(resourcePath, assembly); - bitmapImage.EndInit(); - bitmapImage.Freeze(); - return new WpfBitmap(bitmapImage); - }); - } - - /// Loads a bitmap from the specified file path. - /// - /// The file path to load the bitmap from. - /// The loaded bitmap. - public IBitmap FromFile(string filePath) { - return ui.Invoke(() => { - BitmapImage bitmapImage = new BitmapImage(); - bitmapImage.BeginInit(); - bitmapImage.CacheOption = BitmapCacheOption.OnLoad; - bitmapImage.UriSource = new Uri(filePath); - bitmapImage.EndInit(); - bitmapImage.Freeze(); - return new WpfBitmap(bitmapImage); - }); - } - - /// Loads a bitmap from the specified stream. - /// - /// The stream to load the bitmap from. - /// The loaded bitmap. - public IBitmap FromStream(Stream stream) { - return ui.Invoke(() => { - BitmapImage bitmapImage = new BitmapImage(); - bitmapImage.BeginInit(); - bitmapImage.CacheOption = BitmapCacheOption.OnLoad; - bitmapImage.StreamSource = stream; - bitmapImage.EndInit(); - bitmapImage.Freeze(); - return new WpfBitmap(bitmapImage); - }); - } - - /// Loads a bitmap from the specified icon handle. - /// - /// The handle of the icon to load. - /// The loaded bitmap. - public IBitmap FromHIcon(IntPtr hIcon) { - return ui.Invoke(() => { - return new WpfBitmap( - Imaging.CreateBitmapSourceFromHIcon( - hIcon, - Int32Rect.Empty, - BitmapSizeOptions.FromEmptyOptions())); - }); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Services/WpfClipboardService.cs b/WinDirStat.Net.Wpf/Services/WpfClipboardService.cs deleted file mode 100644 index 267b73a..0000000 --- a/WinDirStat.Net.Wpf/Services/WpfClipboardService.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Windows; -using WinDirStat.Net.Services; - -namespace WinDirStat.Net.Wpf.Services { - /// The service for managing the clipboard state. - public class WpfClipboardService : IClipboardService { - - #region Text - - /// Gets the text assigned to the clipboard. - /// - /// A string if the clipboard has text assigned to it. - public string GetText() { - return Clipboard.GetText(); - } - /// Assigns text to the clipboard. - /// - /// The new text to assign to the clipboard. - public void SetText(string text) { - Clipboard.SetText(text); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Services/WpfUIService.cs b/WinDirStat.Net.Wpf/Services/WpfUIService.cs deleted file mode 100644 index df7cd3e..0000000 --- a/WinDirStat.Net.Wpf/Services/WpfUIService.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Threading; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Wpf.Services.Structures; - -namespace WinDirStat.Net.Wpf.Services { - /// A service for UI interactions. - public class WpfUIService : IUIService { - - #region Fields - - /// The UI dispatcher. - public Dispatcher Dispatcher { get; } - - #endregion - - #region Constructors - - /// Constructs the . - public WpfUIService() { - Dispatcher = Application.Current.Dispatcher; - } - - #endregion - - #region Dispatcher - - /// Invokes the action on the UI thread. - /// - /// The action to invoke. - public void Invoke(Action action) { - try { - Dispatcher.Invoke(action); - } - catch (TaskCanceledException) { } - } - - /// Invokes the function on the UI thread. - /// - /// The function to invoke. - /// The result of the function. - public T Invoke(Func action) { - return Dispatcher.Invoke(action); - } - - /// Invokes the action asynchronously on the UI thread. - /// - /// The action to invoke. - /// True if the action should use normal priority. - public void BeginInvoke(Action action, bool normalPriority) { - Dispatcher.BeginInvoke(action, GetPriority(normalPriority)); - } - - /// Checks if the current thread is the UI thread. - /// - /// True if the current thread is the UI thread. - public bool CheckAccess() { - return Dispatcher.CheckAccess(); - } - - #endregion - - #region Shutdown - - /// Shuts down the application. - public void Shutdown() { - Dispatcher.InvokeShutdown(); - } - - public event EventHandler ShuttingDown { - add => Dispatcher.ShutdownStarted += value; - remove => Dispatcher.ShutdownStarted -= value; - } - - #endregion - - #region Create Timer - - /// Creates a new stopped UI timer. - /// - /// The interval for the timer. - /// True if the timer runs at normal priority. - /// The callback on the timer tick event. - /// The newly created timer. - public IUITimer CreateTimer(TimeSpan interval, bool normalPriority, Action callback) { - return new WpfUITimer(interval, normalPriority, callback, false); - } - /// Creates a new running UI timer. - /// - /// The interval for the timer. - /// True if the timer runs at normal priority. - /// The callback on the timer tick event. - /// The newly created timer. - public IUITimer StartTimer(TimeSpan interval, bool normalPriority, Action callback) { - return new WpfUITimer(interval, normalPriority, callback, true); - } - - #endregion - - #region Static Helpers - - /// Gets the priorty as a . - public static DispatcherPriority GetPriority(bool normalPriority) { - return (normalPriority ? DispatcherPriority.Normal : DispatcherPriority.Background); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Services/WpfWindowDialogService.cs b/WinDirStat.Net.Wpf/Services/WpfWindowDialogService.cs deleted file mode 100644 index aeb5d57..0000000 --- a/WinDirStat.Net.Wpf/Services/WpfWindowDialogService.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System.Media; -using System.Windows; -using WinDirStat.Net.Model.Drives; -using WinDirStat.Net.Services; -using WinDirStat.Net.Services.Structures; -using WinDirStat.Net.Wpf.Windows; - -namespace WinDirStat.Net.Wpf.Services { - /// A service for launching dialogs and showing messages. - public class WpfWindowDialogService : IWindowDialogService { - - #region Fields - - /// The service for performing UI actions such as dispatcher invoking. - private readonly IUIService ui; - - #endregion - - #region Constructors - - /// Constructs the . - public WpfWindowDialogService(IUIService ui) { - this.ui = ui; - } - - #endregion - - #region Dialogs - - /// Shows the dialog for selecting paths to scan. - /// - /// The owner window for this dialog. - /// The selected root paths on success, otherwise null. - public DriveSelectResult ShowDriveSelect(IWindow owner) { - return ui.Invoke(() => { - return DriveSelectDialog.ShowDialog((Window) owner.Window); - }); - } - - /// Shows the folder browser dialog to select a folder. - /// - /// The owner window for this dialog. - /// The description to display. - /// True if the new folder button is present. - /// The currently selected path. Use an empty string for nothing. - /// The selected path on success, otherwise null. - public string ShowFolderBrowser(IWindow owner, string description, bool showNewFolder, string selectedPath = "") { - return ui.Invoke(() => { - FolderBrowserDialog dialog = new FolderBrowserDialog() { - Description = description, - ShowNewFolderButton = showNewFolder, - SelectedPath = selectedPath, - }; - bool? result = dialog.ShowDialog((Window) owner.Window); - if (result ?? false) { - return dialog.SelectedPath; - } - return null; - }); - } - - #endregion - - #region Messages - - /// Shows a message with no icon. - /// - /// The owner window for this dialog message. - /// The text message. - /// The message window title. - /// The message buttons to display. - public MessageResult ShowMessage(IWindow owner, string message, string title, MessageButton button = MessageButton.OK) { - return ui.Invoke(() => { - return (MessageResult) MessageBox.Show((Window) owner.Window, message, title, (MessageBoxButton) button); - }); - } - - /// Shows a message with an information icon. - /// - /// The owner window for this dialog message. - /// The text message. - /// The message window title. - /// The message buttons to display. - public MessageResult ShowInformation(IWindow owner, string message, string title, MessageButton button = MessageButton.OK) { - return ui.Invoke(() => { - SystemSounds.Asterisk.Play(); - return (MessageResult) MessageBox.Show((Window) owner.Window, message, title, (MessageBoxButton) button, MessageBoxImage.Information); - }); - } - - /// Shows a message with a question icon. - /// - /// The owner window for this dialog message. - /// The text message. - /// The message window title. - /// The message buttons to display. - public MessageResult ShowQuestion(IWindow owner, string message, string title, MessageButton button = MessageButton.OK) { - return ui.Invoke(() => { - SystemSounds.Asterisk.Play(); - return (MessageResult) MessageBox.Show((Window) owner.Window, message, title, (MessageBoxButton) button, MessageBoxImage.Question); - }); - } - - /// Shows a message with a warning icon. - /// - /// The owner window for this dialog message. - /// The text message. - /// The message window title. - /// The message buttons to display. - public MessageResult ShowWarning(IWindow owner, string message, string title, MessageButton button = MessageButton.OK) { - return ui.Invoke(() => { - SystemSounds.Exclamation.Play(); - return (MessageResult) MessageBox.Show((Window) owner.Window, message, title, (MessageBoxButton) button, MessageBoxImage.Warning); - }); - } - - /// Shows a message with an error icon. - /// - /// The owner window for this dialog message. - /// The text message. - /// The message window title. - /// The message buttons to display. - public MessageResult ShowError(IWindow owner, string message, string title, MessageButton button = MessageButton.OK) { - return ui.Invoke(() => { - SystemSounds.Hand.Play(); - return (MessageResult) MessageBox.Show((Window) owner.Window, message, title, (MessageBoxButton) button, MessageBoxImage.Error); - }); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Themes/Generic.xaml b/WinDirStat.Net.Wpf/Themes/Generic.xaml deleted file mode 100644 index 8756492..0000000 --- a/WinDirStat.Net.Wpf/Themes/Generic.xaml +++ /dev/null @@ -1,751 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/WinDirStat.Net.Wpf/Themes/SortView.xaml b/WinDirStat.Net.Wpf/Themes/SortView.xaml deleted file mode 100644 index 1cde7ed..0000000 --- a/WinDirStat.Net.Wpf/Themes/SortView.xaml +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/WinDirStat.Net.Wpf/Utils/DependencyObjectExtensions.cs b/WinDirStat.Net.Wpf/Utils/DependencyObjectExtensions.cs deleted file mode 100644 index 7ee2051..0000000 --- a/WinDirStat.Net.Wpf/Utils/DependencyObjectExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace WinDirStat.Net.Wpf.Utils { - public static class DependencyObjectExtensions { - - - public static bool IsValueUnset(this DependencyObject d, DependencyProperty dp) { - return d.ReadLocalValue(dp) == DependencyProperty.UnsetValue; - } - - public static bool IsValueUnsetAndNull(this DependencyObject d, DependencyProperty dp, object value) { - if (d.ReadLocalValue(dp) == DependencyProperty.UnsetValue) { - return (value == null || (value is string str && string.IsNullOrEmpty(str))); - } - return false; - } - } -} diff --git a/WinDirStat.Net.Wpf/Utils/WindowExtensions.cs b/WinDirStat.Net.Wpf/Utils/WindowExtensions.cs deleted file mode 100644 index 918940c..0000000 --- a/WinDirStat.Net.Wpf/Utils/WindowExtensions.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Interop; -using static WinDirStat.Net.Windows.Native.Win32; - -namespace WinDirStat.Net.Wpf.Utils { - public static class WindowExtensions { - - public static void ShowMaximizeMinimize(this Window window, bool maximize, bool minimize) { - IntPtr hwnd = new WindowInteropHelper(window).Handle; - WindowStyles styles = (WindowStyles) GetWindowLong(hwnd, WindowLongs.Style); - if (maximize) - styles |= WindowStyles.MaximizeBox; - else - styles &= ~WindowStyles.MaximizeBox; - if (minimize) - styles |= WindowStyles.MinimizeBox; - else - styles &= ~WindowStyles.MinimizeBox; - SetWindowLong(hwnd, WindowLongs.Style, (uint) styles); - } - - public static void ShowMaximize(this Window window, bool enabled) { - IntPtr hwnd = new WindowInteropHelper(window).Handle; - WindowStyles styles = (WindowStyles) GetWindowLong(hwnd, WindowLongs.Style); - if (enabled) - styles |= WindowStyles.MaximizeBox; - else - styles &= ~WindowStyles.MaximizeBox; - SetWindowLong(hwnd, WindowLongs.Style, (uint) styles); - } - - public static void ShowMinimize(this Window window, bool enabled) { - IntPtr hwnd = new WindowInteropHelper(window).Handle; - WindowStyles styles = (WindowStyles) GetWindowLong(hwnd, WindowLongs.Style); - if (enabled) - styles |= WindowStyles.MinimizeBox; - else - styles &= ~WindowStyles.MinimizeBox; - SetWindowLong(hwnd, WindowLongs.Style, (uint) styles); - } - } -} diff --git a/WinDirStat.Net.Wpf/Utils/WpfCasting.cs b/WinDirStat.Net.Wpf/Utils/WpfCasting.cs deleted file mode 100644 index 0dd1dea..0000000 --- a/WinDirStat.Net.Wpf/Utils/WpfCasting.cs +++ /dev/null @@ -1,135 +0,0 @@ -using WinDirStat.Net.Structures; - -using WpfColor = System.Windows.Media.Color; -using WpfPoint = System.Windows.Point; -using WpfSize = System.Windows.Size; -using WpfRect = System.Windows.Rect; -using WpfInt32Rect = System.Windows.Int32Rect; - -namespace WinDirStat.Net.Wpf.Utils { - /// Static extensions for casting between Wpf and WinDirStat.Net values. - public static class WpfCasting { - - #region Color - - /// Casts the to a . - public static WpfColor ToWpfColor(this Rgb24Color color) { - return WpfColor.FromRgb(color.R, color.G, color.B); - } - - /// Casts the to a . - public static WpfColor ToWpfColor(this Rgba32Color color) { - return WpfColor.FromArgb(color.A, color.R, color.G, color.B); - } - - /// Casts the to an . - public static Rgb24Color ToRgb24Color(this WpfColor color) { - return new Rgb24Color(color.R, color.G, color.B); - } - - /// Casts the to an . - public static Rgba32Color ToRgba32Color(this WpfColor color) { - return new Rgba32Color(color.R, color.G, color.B, color.A); - } - - #endregion - - #region Point - - /// Casts the to a . - public static WpfPoint ToWpfPoint(this Point2I point) { - return new WpfPoint(point.X, point.Y); - } - - /// Casts the to a . - public static WpfPoint ToWpfPoint(this Point2F point) { - return new WpfPoint(point.X, point.Y); - } - - /// Casts the to a . - public static Point2I ToPoint2I(this WpfPoint point) { - return new Point2I((int) point.X, (int) point.Y); - } - - /// Casts the to a . - public static Point2F ToPoint2F(this WpfPoint point) { - return new Point2F((float) point.X, (float) point.Y); - } - - #endregion - - #region Size - - /// Casts the to a . - public static WpfSize ToWpfSize(this Point2I point) { - return new WpfSize(point.X, point.Y); - } - - /// Casts the to a . - public static WpfSize ToWpfSize(this Point2F point) { - return new WpfSize(point.X, point.Y); - } - - /// Casts the to a . - public static Point2I ToPoint2I(this WpfSize size) { - return new Point2I((int) size.Width, (int) size.Height); - } - - /// Casts the to a . - public static Point2F ToPoint2F(this WpfSize size) { - return new Point2F((float) size.Width, (float) size.Height); - } - - #endregion - - #region Rect - - /// Casts the to a . - public static WpfRect ToWpfRect(this Rectangle2S rect) { - return new WpfRect(rect.X, rect.Y, rect.Width, rect.Height); - } - - /// Casts the to a . - public static WpfRect ToWpfRect(this Rectangle2I rect) { - return new WpfRect(rect.X, rect.Y, rect.Width, rect.Height); - } - - /// Casts the to a . - public static Rectangle2S ToRectangle2S(this WpfRect rect) { - return new Rectangle2S((int) rect.X, (int) rect.Y, - (int) rect.Width, (int) rect.Height); - } - - /// Casts the to a . - public static Rectangle2I ToRectangle2I(this WpfRect rect) { - return new Rectangle2I((int) rect.X, (int) rect.Y, - (int) rect.Width, (int) rect.Height); - } - - #endregion - - #region Int32Rect - - /// Casts the to a . - public static WpfInt32Rect ToWpfInt32Rect(this Rectangle2S rect) { - return new WpfInt32Rect(rect.X, rect.Y, rect.Width, rect.Height); - } - - /// Casts the to a . - public static WpfInt32Rect ToWpfInt32Rect(this Rectangle2I rect) { - return new WpfInt32Rect(rect.X, rect.Y, rect.Width, rect.Height); - } - - /// Casts the to a . - public static Rectangle2S ToRectangle2S(this WpfInt32Rect rect) { - return new Rectangle2S(rect.X, rect.Y, rect.Width, rect.Height); - } - - /// Casts the to a . - public static Rectangle2I ToRectangle2I(this WpfInt32Rect rect) { - return new Rectangle2I(rect.X, rect.Y, rect.Width, rect.Height); - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Utils/WpfExtensions.cs b/WinDirStat.Net.Wpf/Utils/WpfExtensions.cs deleted file mode 100644 index 169d479..0000000 --- a/WinDirStat.Net.Wpf/Utils/WpfExtensions.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using System.Windows; -using System.Windows.Controls; -using System.Windows.Navigation; -using System.Reflection; -using System.IO.Packaging; -using System.Windows.Markup; -using System.IO; -using System.ComponentModel; - -namespace WinDirStat.Net.Wpf.Utils { - public static class WpfExtensions { - /*/// Fix the VS designer being a steaming pile of garbage. - /// - /// - /// - /// - /// - /// Source - /// - public static void LoadViewFromUri(this UserControl userControl, string baseUri) { - Uri resourceLocater = new Uri(baseUri, UriKind.Relative); - PackagePart exprCa = (PackagePart) typeof(Application).GetMethod("GetResourceOrContentPart", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { resourceLocater }); - Stream stream = exprCa.GetStream(); - Uri uri = new Uri((Uri) typeof(BaseUriHelper).GetProperty("PackAppBaseUri", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null, null), resourceLocater); - ParserContext parserContext = new ParserContext { - BaseUri = uri - }; - typeof(XamlReader).GetMethod("LoadBaml", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { stream, parserContext, userControl, true }); - }*/ - - /// Fix the VS designer being a steaming pile of garbage. - /// - /// - /// - /// True if the design uri was loaded - /// - /// - /// Improved From: - /// Source - /// - public static bool DesignerInitializeComponent(this UserControl userControl, string path) { - if (DesignerProperties.GetIsInDesignMode(userControl)) { - Type type = userControl.GetType(); - Assembly assembly = type.Assembly; - string baseUri = $"/{assembly.GetName().Name};component/{path}/{type.Name}.xaml"; - - Uri resourceLocater = new Uri(baseUri, UriKind.Relative); - PackagePart exprCa = (PackagePart) typeof(Application).GetMethod("GetResourceOrContentPart", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { resourceLocater }); - Stream stream = exprCa.GetStream(); - Uri uri = new Uri((Uri) typeof(BaseUriHelper).GetProperty("PackAppBaseUri", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null, null), resourceLocater); - ParserContext parserContext = new ParserContext { - BaseUri = uri, - }; - typeof(XamlReader).GetMethod("LoadBaml", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { stream, parserContext, userControl, true }); - return true; - } - return false; - } - } -} diff --git a/WinDirStat.Net.Wpf/Utils/WpfUtils.cs b/WinDirStat.Net.Wpf/Utils/WpfUtils.cs deleted file mode 100644 index 4e26232..0000000 --- a/WinDirStat.Net.Wpf/Utils/WpfUtils.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace WinDirStat.Net.Wpf.Utils { - public static class WpfUtils { - - /// Creates a pack Uri for loading resource images. - public static Uri MakePackUri(string resourcePath, Assembly assembly = null) { - assembly = assembly ?? Assembly.GetCallingAssembly(); - // Pull out the short name. - string assemblyShortName = assembly.ToString().Split(',')[0]; - string uriString = $"pack://application:,,,/{assemblyShortName};component/{resourcePath}"; - return new Uri(uriString); - } - } -} diff --git a/WinDirStat.Net.Wpf/ViewModel/ViewModelLocator.cs b/WinDirStat.Net.Wpf/ViewModel/ViewModelLocator.cs deleted file mode 100644 index 8fa0512..0000000 --- a/WinDirStat.Net.Wpf/ViewModel/ViewModelLocator.cs +++ /dev/null @@ -1,79 +0,0 @@ -/* - In App.xaml: - - - - - In the View: - DataContext="{Binding Source={StaticResource Locator}, Path=ViewModelName}" - - You can also use Blend to do all this with the tool's support. - See http://www.galasoft.ch/mvvm -*/ - -using GalaSoft.MvvmLight; -using GalaSoft.MvvmLight.Ioc; -using CommonServiceLocator; -using WinDirStat.Net.ViewModel; -using WinDirStat.Net.Rendering; -using WinDirStat.Net.Services; -using WinDirStat.Net.Wpf.Services; -using WinDirStat.Net.Windows.Services; - -namespace WinDirStat.Net.Wpf.ViewModel { - /// - /// This class contains static references to all the view models in the - /// application and provides an entry point for the bindings. - /// - public class ViewModelLocator { - /// Initializes the ViewModelLocator class. - static ViewModelLocator() { - ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); - - ////if (ViewModelBase.IsInDesignModeStatic) - ////{ - //// // Create design time view services and models - //// SimpleIoc.Default.Register(); - ////} - ////else - ////{ - //// // Create run time view services and models - //// SimpleIoc.Default.Register(); - ////} - - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - SimpleIoc.Default.Register(); - } - - /// Initializes a new instance of the ViewModelLocator class. - public ViewModelLocator() { - - } - - public MainViewModel Main => ServiceLocator.Current.GetInstance(); - public DriveSelectViewModel DriveSelect => ServiceLocator.Current.GetInstance(); - public ConfigureViewModel Configure => ServiceLocator.Current.GetInstance(); - /*public TreemapRendererFactory TreemapFactory => ServiceLocator.Current.GetInstance(); - - public TreemapRenderer CreateTreemap() { - return TreemapFactory.Create(); - }*/ - - public static void Cleanup() { - ServiceLocator.Current.GetInstance().Dispose(); - } - } -} \ No newline at end of file diff --git a/WinDirStat.Net.Wpf/WinDirStat.Net.Wpf.csproj b/WinDirStat.Net.Wpf/WinDirStat.Net.Wpf.csproj deleted file mode 100644 index bb1b69c..0000000 --- a/WinDirStat.Net.Wpf/WinDirStat.Net.Wpf.csproj +++ /dev/null @@ -1,317 +0,0 @@ - - - - - Debug - AnyCPU - {BF8C1ACF-CCB6-4CAD-BDB9-A99475606605} - WinExe - WinDirStat.Net.Wpf - WinDirStat.Net - v4.6.2 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - true - true - - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - latest - true - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - latest - true - - - App.ico - - - Properties\App.manifest - - - - - - - - - - - - 4.0 - - - - - - - - - MSBuild:Compile - Designer - - - - - - - - - - - - - - - - - - GraphView.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DriveSelectDialog.xaml - - - - ConfigureDialog.xaml - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - MainWindow.xaml - Code - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - - - Code - - - - - - - - - {7da5a107-b474-4ac0-b861-63a489db0c02} - FunctionalFun.UI.Behaviors - - - {0ed71f8b-0797-468b-8420-2e2879da2302} - WinDirStat.Net.Base - - - {6416aa44-0296-4ff8-b408-a39a6c80dc2b} - WinDirStat.Net.Windows - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5.4.1.1 - - - 1.0.0 - - - 1.0.0 - - - 1.6.2 - - - - \ No newline at end of file diff --git a/WinDirStat.Net.Wpf/Windows/ConfigureDialog.xaml b/WinDirStat.Net.Wpf/Windows/ConfigureDialog.xaml deleted file mode 100644 index 1592433..0000000 --- a/WinDirStat.Net.Wpf/Windows/ConfigureDialog.xaml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/WinDirStat.Net.Wpf/Windows/ConfigureDialog.xaml.cs b/WinDirStat.Net.Wpf/Windows/ConfigureDialog.xaml.cs deleted file mode 100644 index 64d0a73..0000000 --- a/WinDirStat.Net.Wpf/Windows/ConfigureDialog.xaml.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Shapes; -using WinDirStat.Net.Wpf.Utils; - -namespace WinDirStat.Net.Wpf.Windows { - /// - /// Interaction logic for ConfigureDialog.xaml - /// - public partial class ConfigureDialog : Window { - public ConfigureDialog() { - InitializeComponent(); - } - - #region Properties - - /// Gets the . - //public ConfigureViewModel ViewModel => DataContext as ConfigureViewModel; - - #endregion - - #region Event Handlers - - private void OnLoaded(object sender, RoutedEventArgs e) { - //ViewModel.WindowOwner = this; - } - - private void OnSourceInitialized(object sender, EventArgs e) { - this.ShowMaximizeMinimize(false, false); - } - - private void OnOK(object sender, RoutedEventArgs e) { - DialogResult = true; - } - - #endregion - } -} diff --git a/WinDirStat.Net.Wpf/Windows/DriveSelectDialog.xaml b/WinDirStat.Net.Wpf/Windows/DriveSelectDialog.xaml deleted file mode 100644 index 462f817..0000000 --- a/WinDirStat.Net.Wpf/Windows/DriveSelectDialog.xaml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -