|
1 | 1 | #region Copyright (C) |
2 | 2 | // <copyright file="ProtectedDrivesDisplay.cs" company="Smurf-IV"> |
3 | 3 | // |
4 | | -// Copyright (C) 2019-2021 Smurf-IV |
| 4 | +// Copyright (C) 2019-2025 Smurf-IV |
5 | 5 | // |
6 | 6 | // This program is free software: you can redistribute it and/or modify |
7 | 7 | // it under the terms of the GNU General Public License as published by |
|
36 | 36 |
|
37 | 37 | using NLog; |
38 | 38 |
|
39 | | -namespace Elucidate.Controls |
| 39 | +namespace Elucidate.Controls; |
| 40 | + |
| 41 | +internal partial class ProtectedDrivesDisplay : UserControl |
40 | 42 | { |
41 | | - internal partial class ProtectedDrivesDisplay : UserControl |
| 43 | + private static readonly Logger Log = LogManager.GetCurrentClassLogger(); |
| 44 | + private CancellationTokenSource cancelTokenSrc; |
| 45 | + |
| 46 | + private volatile int useWaitCursor; |
| 47 | + |
| 48 | + internal ProtectedDrivesDisplay() |
42 | 49 | { |
43 | | - private static readonly Logger Log = LogManager.GetCurrentClassLogger(); |
44 | | - private CancellationTokenSource cancelTokenSrc; |
| 50 | + InitializeComponent(); |
| 51 | + cancelTokenSrc = new CancellationTokenSource(); |
| 52 | + } |
45 | 53 |
|
46 | | - private volatile int useWaitCursor; |
| 54 | + internal void StopProcessing() |
| 55 | + { |
| 56 | + // have to stop "any" processes that might be refreshing as this is now closing |
| 57 | + cancelTokenSrc.Cancel(); |
| 58 | + } |
47 | 59 |
|
48 | | - internal ProtectedDrivesDisplay() |
| 60 | + private void IncrementWaitCursor() |
| 61 | + { |
| 62 | + if (Interlocked.Increment(ref useWaitCursor) == 1) |
49 | 63 | { |
50 | | - InitializeComponent(); |
51 | | - cancelTokenSrc = new CancellationTokenSource(); |
| 64 | + BeginInvoke((MethodInvoker)(() => UseWaitCursor = true)); |
52 | 65 | } |
| 66 | + } |
53 | 67 |
|
54 | | - internal void StopProcessing() |
| 68 | + private void DecrementWaitCursor() |
| 69 | + { |
| 70 | + if (Interlocked.Decrement(ref useWaitCursor) <= 0) |
55 | 71 | { |
56 | | - // have to stop "any" processes that might be refreshing as this is now closing |
57 | | - cancelTokenSrc.Cancel(); |
| 72 | + BeginInvoke((MethodInvoker)(() => UseWaitCursor = false)); |
58 | 73 | } |
| 74 | + } |
59 | 75 |
|
60 | | - private void IncrementWaitCursor() |
| 76 | + /// <summary> |
| 77 | + /// Take an existing config file and populate the Grid |
| 78 | + /// </summary> |
| 79 | + /// <param name="srConfig"></param> |
| 80 | + /// <param name="excludeParity"></param> |
| 81 | + public void RefreshGrid(ConfigFileHelper srConfig, bool excludeParity) |
| 82 | + { |
| 83 | + Interlocked.Exchange(ref useWaitCursor, 0); |
| 84 | + IncrementWaitCursor(); |
| 85 | + // have to stop "any" processes that might be refreshing as this is a new list |
| 86 | + cancelTokenSrc.Cancel(); |
| 87 | + while (driveGrid.Rows.Count > 1) // Got to leave the "New" edit row |
61 | 88 | { |
62 | | - if (Interlocked.Increment(ref useWaitCursor) == 1) |
| 89 | + driveGrid.Rows.RemoveAt(0); |
| 90 | + } |
| 91 | + var pathsOfInterest = srConfig.GetPathsOfInterest(); |
| 92 | + cancelTokenSrc = new CancellationTokenSource(); |
| 93 | + if (excludeParity) |
| 94 | + { |
| 95 | + foreach (CoveragePath coveragePath in pathsOfInterest.Where(static s => s.PathType == PathTypeEnum.Source)) |
63 | 96 | { |
64 | | - BeginInvoke((MethodInvoker)(() => UseWaitCursor = true)); |
| 97 | + AddCoverage(coveragePath); |
65 | 98 | } |
66 | 99 | } |
| 100 | + else |
| 101 | + { |
| 102 | + pathsOfInterest.ForEach(AddCoverage); |
| 103 | + } |
| 104 | + |
| 105 | + DecrementWaitCursor(); |
| 106 | + } |
67 | 107 |
|
68 | | - private void DecrementWaitCursor() |
| 108 | + public void AddCoverage(CoveragePath coveragePath) |
| 109 | + { |
| 110 | + var row = (DataGridViewRow)driveGrid.RowTemplate.Clone()!; |
| 111 | + row.CreateCells(driveGrid, coveragePath.FullPath, coveragePath.Name, null, @"Processing"); |
| 112 | + row.Tag = coveragePath; |
| 113 | + driveGrid.Rows.Add(row); |
| 114 | + } |
| 115 | + |
| 116 | + private void driveGrid_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e) |
| 117 | + { |
| 118 | + if (!cancelTokenSrc.IsCancellationRequested) |
69 | 119 | { |
70 | | - if (Interlocked.Decrement(ref useWaitCursor) <= 0) |
| 120 | + for (var index = e.RowIndex; index < e.RowIndex + e.RowCount; index++) |
71 | 121 | { |
72 | | - BeginInvoke((MethodInvoker)(() => UseWaitCursor = false)); |
| 122 | + // Get data to perform drive usage display |
| 123 | + DataGridViewRow row = driveGrid.Rows[index]; |
| 124 | + StartDriveUsage(row, cancelTokenSrc.Token); |
73 | 125 | } |
74 | 126 | } |
| 127 | + } |
75 | 128 |
|
76 | | - /// <summary> |
77 | | - /// Take an existing config file and populate the Grid |
78 | | - /// </summary> |
79 | | - /// <param name="srConfig"></param> |
80 | | - /// <param name="excludeParity"></param> |
81 | | - public void RefreshGrid(ConfigFileHelper srConfig, bool excludeParity) |
| 129 | + private void StartDriveUsage(DataGridViewRow row, CancellationToken token) |
| 130 | + { |
| 131 | + if (row.Tag is CoveragePath coveragePath) |
82 | 132 | { |
83 | | - Interlocked.Exchange(ref useWaitCursor, 0); |
84 | | - IncrementWaitCursor(); |
85 | | - // have to stop "any" processes that might be refreshing as this is a new list |
86 | | - cancelTokenSrc.Cancel(); |
87 | | - while (driveGrid.Rows.Count > 1) // Got to leave the "New" edit row |
88 | | - { |
89 | | - driveGrid.Rows.RemoveAt(0); |
90 | | - } |
91 | | - var pathsOfInterest = srConfig.GetPathsOfInterest(); |
92 | | - cancelTokenSrc = new CancellationTokenSource(); |
93 | | - if (excludeParity) |
| 133 | + var dirInfo = new DirectoryInfo(coveragePath.DirectoryPath, PathFormat.FullPath); |
| 134 | + var driveInfo = new DriveInfo(dirInfo.Root.FullName); |
| 135 | + if (coveragePath.PathType == PathTypeEnum.Parity) |
94 | 136 | { |
95 | | - foreach (CoveragePath coveragePath in pathsOfInterest.Where(static s => s.PathType == PathTypeEnum.Source)) |
96 | | - { |
97 | | - AddCoverage(coveragePath); |
98 | | - } |
| 137 | + var totalUsed = driveInfo.TotalSize - driveInfo.AvailableFreeSpace; |
| 138 | + var protectedUse = File.Exists(coveragePath.FullPath) ? new FileInfo(coveragePath.FullPath).Length : 0L; |
| 139 | + row.Cells[2].Value = $@"{protectedUse}:{totalUsed}:{driveInfo.TotalSize}"; |
| 140 | + row.Cells[3].Value = $@"{new ByteSize(protectedUse)} : {new ByteSize(totalUsed)} : {new ByteSize(driveInfo.TotalSize)}"; |
99 | 141 | } |
100 | 142 | else |
101 | 143 | { |
102 | | - pathsOfInterest.ForEach(AddCoverage); |
| 144 | + // Start background processing |
| 145 | + IncrementWaitCursor(); |
| 146 | + Task.Run(() => ProcessProtectedSpace(row, driveInfo, dirInfo, token), token); |
103 | 147 | } |
104 | | - |
105 | | - DecrementWaitCursor(); |
106 | 148 | } |
| 149 | + } |
107 | 150 |
|
108 | | - public void AddCoverage(CoveragePath coveragePath) |
109 | | - { |
110 | | - DataGridViewRow row = (DataGridViewRow)driveGrid.RowTemplate.Clone(); |
111 | | - row.CreateCells(driveGrid, coveragePath.FullPath, coveragePath.Name, null, @"Processing"); |
112 | | - row.Tag = coveragePath; |
113 | | - driveGrid.Rows.Add(row); |
114 | | - } |
| 151 | + private void ProcessProtectedSpace(DataGridViewRow row, DriveInfo driveInfo, |
| 152 | + DirectoryInfo dirInfo, CancellationToken token) |
| 153 | + { |
| 154 | + var totalUsed = driveInfo.TotalSize - driveInfo.AvailableFreeSpace; |
115 | 155 |
|
116 | | - private void driveGrid_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e) |
| 156 | + var protectedUse = DirSize(dirInfo, token); |
| 157 | + if (!token.IsCancellationRequested) |
117 | 158 | { |
118 | | - if (!cancelTokenSrc.IsCancellationRequested) |
119 | | - { |
120 | | - for (var index = e.RowIndex; index < e.RowIndex + e.RowCount; index++) |
121 | | - { |
122 | | - // Get data to perform drive usage display |
123 | | - DataGridViewRow row = driveGrid.Rows[index]; |
124 | | - StartDriveUsage(row, cancelTokenSrc.Token); |
125 | | - } |
126 | | - } |
| 159 | + BeginInvoke((MethodInvoker)delegate |
| 160 | + { |
| 161 | + try |
| 162 | + { |
| 163 | + row.Cells[2].Value = $@"{protectedUse}:{totalUsed}:{driveInfo.TotalSize}"; |
| 164 | + row.Cells[3].Value = |
| 165 | + $@"{new ByteSize(protectedUse)} : {new ByteSize(totalUsed)} : {new ByteSize(driveInfo.TotalSize)}"; |
| 166 | + } |
| 167 | + catch |
| 168 | + { |
| 169 | + // Do nothing |
| 170 | + // Might be caused by fast closure |
| 171 | + } |
| 172 | + }); |
127 | 173 | } |
128 | 174 |
|
129 | | - private void StartDriveUsage(DataGridViewRow row, CancellationToken token) |
| 175 | + DecrementWaitCursor(); |
| 176 | + } |
| 177 | + |
| 178 | + /// <summary> |
| 179 | + /// Recursive and allow cancellation |
| 180 | + /// </summary> |
| 181 | + /// <param name="dir"></param> |
| 182 | + /// <param name="token"></param> |
| 183 | + /// <returns></returns> |
| 184 | + private static ulong DirSize(DirectoryInfo dir, CancellationToken token) |
| 185 | + { |
| 186 | + try |
130 | 187 | { |
131 | | - if (row.Tag is CoveragePath coveragePath) |
| 188 | + if (token.IsCancellationRequested) |
132 | 189 | { |
133 | | - var dirInfo = new DirectoryInfo(coveragePath.DirectoryPath, PathFormat.FullPath); |
134 | | - var driveInfo = new DriveInfo(dirInfo.Root.FullName); |
135 | | - if (coveragePath.PathType == PathTypeEnum.Parity) |
136 | | - { |
137 | | - var totalUsed = driveInfo.TotalSize - driveInfo.AvailableFreeSpace; |
138 | | - var protectedUse = File.Exists(coveragePath.FullPath) ? new FileInfo(coveragePath.FullPath).Length : 0L; |
139 | | - row.Cells[2].Value = $@"{protectedUse}:{totalUsed}:{driveInfo.TotalSize}"; |
140 | | - row.Cells[3].Value = $@"{new ByteSize(protectedUse)} : {new ByteSize(totalUsed)} : {new ByteSize(driveInfo.TotalSize)}"; |
141 | | - } |
142 | | - else |
143 | | - { |
144 | | - // Start background processing |
145 | | - IncrementWaitCursor(); |
146 | | - Task.Run(() => ProcessProtectedSpace(row, driveInfo, dirInfo, token), token); |
147 | | - } |
| 190 | + return 0UL; |
148 | 191 | } |
149 | 192 |
|
| 193 | + return dir.EnumerateFiles().AsParallel().Sum(static fi => (ulong)fi.Length) |
| 194 | + + dir.EnumerateDirectories() |
| 195 | + .Where(static d => (d.Attributes & System.IO.FileAttributes.System) == 0 |
| 196 | + && (d.Attributes & System.IO.FileAttributes.Hidden) == 0) |
| 197 | + .AsParallel() |
| 198 | + .Sum(info => DirSize(info, token)); |
150 | 199 | } |
151 | | - |
152 | | - private void ProcessProtectedSpace(DataGridViewRow row, DriveInfo driveInfo, |
153 | | - DirectoryInfo dirInfo, CancellationToken token) |
| 200 | + catch (UnauthorizedAccessException ex) |
154 | 201 | { |
155 | | - var totalUsed = driveInfo.TotalSize - driveInfo.AvailableFreeSpace; |
156 | | - |
157 | | - var protectedUse = DirSize(dirInfo, token); |
158 | | - if (!token.IsCancellationRequested) |
159 | | - { |
160 | | - BeginInvoke((MethodInvoker)delegate |
161 | | - { |
162 | | - try |
163 | | - { |
164 | | - row.Cells[2].Value = $@"{protectedUse}:{totalUsed}:{driveInfo.TotalSize}"; |
165 | | - row.Cells[3].Value = |
166 | | - $@"{new ByteSize(protectedUse)} : {new ByteSize(totalUsed)} : {new ByteSize(driveInfo.TotalSize)}"; |
167 | | - } |
168 | | - catch |
169 | | - { |
170 | | - // Do nothing |
171 | | - // Might be caused by fast closure |
172 | | - } |
173 | | - }); |
174 | | - } |
175 | | - |
176 | | - DecrementWaitCursor(); |
| 202 | + Log.Warn(ex, @"No Access to [{0}]", dir.FullName); |
177 | 203 | } |
178 | | - |
179 | | - /// <summary> |
180 | | - /// Recursive and allow cancellation |
181 | | - /// </summary> |
182 | | - /// <param name="dir"></param> |
183 | | - /// <param name="token"></param> |
184 | | - /// <returns></returns> |
185 | | - private static ulong DirSize(DirectoryInfo dir, CancellationToken token) |
| 204 | + catch (Exception ex) |
186 | 205 | { |
187 | | - try |
188 | | - { |
189 | | - if (token.IsCancellationRequested) |
190 | | - { |
191 | | - return 0UL; |
192 | | - } |
193 | | - |
194 | | - return dir.EnumerateFiles().AsParallel().Sum(static fi => (ulong)fi.Length) |
195 | | - + dir.EnumerateDirectories() |
196 | | - .Where(static d => (d.Attributes & System.IO.FileAttributes.System) == 0 |
197 | | - && (d.Attributes & System.IO.FileAttributes.Hidden) == 0) |
198 | | - .AsParallel() |
199 | | - .Sum(info => DirSize(info, token)); |
200 | | - } |
201 | | - catch (UnauthorizedAccessException ex) |
202 | | - { |
203 | | - Log.Warn(ex, @"No Access to [{0}]", dir.FullName); |
204 | | - } |
205 | | - catch (Exception ex) |
206 | | - { |
207 | | - Log.Warn(ex); |
208 | | - } |
209 | | - |
210 | | - return 0UL; |
| 206 | + Log.Warn(ex); |
211 | 207 | } |
212 | 208 |
|
213 | | - private void DriveGrid_MouseDown(object sender, MouseEventArgs e) |
| 209 | + return 0UL; |
| 210 | + } |
| 211 | + |
| 212 | + private void DriveGrid_MouseDown(object sender, MouseEventArgs e) |
| 213 | + { |
| 214 | + if (e.Button == MouseButtons.Right) |
214 | 215 | { |
215 | | - if (e.Button == MouseButtons.Right) |
216 | | - { |
217 | | - DataGridView.HitTestInfo hti = driveGrid.HitTest(e.X, e.Y); |
218 | | - driveGrid.ClearSelection(); |
219 | | - driveGrid.Rows[hti.RowIndex].Selected = true; |
220 | | - } |
| 216 | + DataGridView.HitTestInfo hti = driveGrid.HitTest(e.X, e.Y); |
| 217 | + driveGrid.ClearSelection(); |
| 218 | + driveGrid.Rows[hti.RowIndex].Selected = true; |
221 | 219 | } |
222 | 220 | } |
223 | 221 | } |
0 commit comments