-
Notifications
You must be signed in to change notification settings - Fork 117
Expand file tree
/
Copy pathFeatureManager.cs
More file actions
330 lines (294 loc) · 12.3 KB
/
Copy pathFeatureManager.cs
File metadata and controls
330 lines (294 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
using Features;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;
using CFixer;
namespace CrapFixer
{
/// <summary>
/// Provides operations to load, analyze, fix, restore, and show help for FeatureNodes.
/// </summary>
public static class FeatureNodeManager
{
private static int totalChecked;
private static int issuesFound;
// Public properties to access the analysis results
public static int TotalChecked => totalChecked;
public static int IssuesFound => issuesFound;
public static void ResetAnalysis()
{
totalChecked = 0;
issuesFound = 0;
Logger.Clear();
}
/// <summary>
/// Loads all features into the TreeView.
/// </summary>
public static void LoadFeatures(TreeView tree)
{
// Hide the TreeView to avoid flickering and visible scroll jump
tree.Visible = false;
var features = FeatureLoader.Load();
tree.Nodes.Clear();
foreach (var feature in features)
AddNode(tree.Nodes, feature);
// root nodes (categories)
foreach (TreeNode root in tree.Nodes)
{
root.NodeFont = new Font(tree.Font, FontStyle.Bold);
root.ForeColor = Color.RoyalBlue; // category color
}
tree.ExpandAll(); // expand all nodes
// Set scroll to top and make TreeView visible
tree.BeginInvoke(new Action(() =>
{
// Ensure the first node is shown at the top (prevents auto-scroll to bottom)
if (tree.Nodes.Count > 0) tree.TopNode = tree.Nodes[0];
tree.Visible = true;
}));
}
/// <summary>
/// Recursively adds a FeatureNode and its children into the TreeView.
/// </summary>
private static void AddNode(TreeNodeCollection treeNodes, FeatureNode featureNode)
{
string localizedName = featureNode.IsCategory
? LocalizationManager.LocalizeFeatureCategory(featureNode.Name)
: LocalizationManager.LocalizeFeatureName(featureNode);
string text = featureNode.IsCategory
? " " + localizedName + " " // add extra space to avoid clipping
: localizedName;
TreeNode node = new TreeNode(text)
{
Name = featureNode.Name,
Tag = featureNode,
Checked = featureNode.DefaultChecked,
};
treeNodes.Add(node);
foreach (var child in featureNode.Children)
AddNode(node.Nodes, child);
}
/// <summary>
/// Analyzes all checked features recursively and logs only issues.
/// </summary>
public static async Task AnalyzeAll(TreeNodeCollection nodes)
{
ResetAnalysis();
// Iterate through all nodes and analyze each one recursively
foreach (TreeNode node in nodes)
{
// Recursively analyze each node and ensure async tasks are awaited
await AnalyzeCheckedRecursive(node);
}
Logger.Log("ANALYSIS COMPLETE", LogLevel.Info);
Logger.Log(new string('=', 50), LogLevel.Info);
int ok = totalChecked - issuesFound;
Logger.Log($"Summary: {ok} of {totalChecked} checked settings are OK; {issuesFound} require attention.",
issuesFound > 0 ? LogLevel.Warning : LogLevel.Info);
}
/// <summary>
/// Recursively checks all features and logs misconfigurations.
/// </summary>
private static async Task AnalyzeCheckedRecursive(TreeNode node)
{
if (node.Tag is FeatureNode fn)
{
// If the node is not a category, is checked, and has a feature to check
if (!fn.IsCategory && node.Checked && fn.Feature != null)
{
totalChecked++;
bool isOk = await fn.Feature.CheckFeature(); // Await the async operation
if (!isOk)
{
issuesFound++;
node.ForeColor = Color.Red; // Mark as misconfigured
string category = node.Parent?.Text ?? "General";
Logger.Log($"[{category}] {fn.Name} - Not configured as recommended.");
Logger.Log($" {fn.Feature.GetFeatureDetails()}");
// Log a separator when an issue was found
Logger.Log(new string('-', 50), LogLevel.Info);
}
else
{
node.ForeColor = Color.Gray; // Mark as properly configured
}
}
// Recursively process child nodes and ensure awaiting the tasks
foreach (TreeNode child in node.Nodes)
{
await AnalyzeCheckedRecursive(child); // Recursively call and await the result
}
}
}
/// <summary>
/// Fixes all checked features recursively.
/// </summary>
public static async Task FixChecked(TreeNode node)
{
if (node.Tag is FeatureNode fn)
{
if (!fn.IsCategory && node.Checked && fn.Feature != null)
{
string displayName = LocalizationManager.LocalizeFeatureName(fn);
bool result = await fn.Feature.DoFeature();
Logger.Log(result
? $"{displayName} - Fixed"
: $"{displayName} - Fix failed (This feature may require admin privileges)",
result ? LogLevel.Info : LogLevel.Error);
}
foreach (TreeNode child in node.Nodes)
await FixChecked(child);
}
}
/// <summary>
/// Restores all checked features recursively.
/// </summary>
public static void RestoreChecked(TreeNode node)
{
if (node.Tag is FeatureNode fn)
{
if (!fn.IsCategory && node.Checked && fn.Feature != null)
{
string displayName = LocalizationManager.LocalizeFeatureName(fn);
bool ok = fn.Feature.UndoFeature();
string category = node.Parent?.Text ?? "General";
Logger.Log(ok
? $"[{category}] {displayName} - Restored"
: $"[{category}] {displayName} - Restore failed",
ok ? LogLevel.Info : LogLevel.Error);
}
foreach (TreeNode child in node.Nodes)
RestoreChecked(child);
}
}
/// <summary>
/// Analyzes a selected feature or, if it's a category, analyzes only checked child features.
/// </summary>
public static async void AnalyzeFeature(TreeNode node)
{
// Analyze this node if it's a leaf node (not a category)
if (node.Tag is FeatureNode fn && !fn.IsCategory && fn.Feature != null)
{
bool isOk = await fn.Feature.CheckFeature();
node.ForeColor = isOk ? Color.Gray : Color.Red;
if (isOk)
{
Logger.Log($"Feature: {fn.Name} is properly configured.", LogLevel.Info);
}
else
{
string category = node.Parent?.Text ?? "General";
Logger.Log($"Feature: {fn.Name} requires attention.", LogLevel.Warning);
Logger.Log($" {fn.Feature.GetFeatureDetails()}");
Logger.Log(new string('-', 50), LogLevel.Info);
}
}
else
{
// If it's a category node, analyze only checked child nodes
foreach (TreeNode child in node.Nodes)
{
if (child.Checked)
AnalyzeFeature(child);
}
}
}
/// <summary>
/// Attempts to fix the selected feature or, if it is a category, fixes only checked child features.
/// </summary>
public static async Task FixFeature(TreeNode node)
{
// Try to fix this node if it is NOT a category (i.e., a leaf node)
if (node.Tag is FeatureNode fn && !fn.IsCategory && fn.Feature != null)
{
string displayName = LocalizationManager.LocalizeFeatureName(fn);
// Always fix the selected leaf node, regardless of Checked
bool result = await fn.Feature.DoFeature();
Logger.Log(result
? $"{displayName} - Fixed"
: $"{displayName} - Fix failed (This feature may require admin privileges)",
result ? LogLevel.Info : LogLevel.Error);
}
else
{
// If it's a category node, fix only checked child nodes (recursively)
foreach (TreeNode child in node.Nodes)
{
if (child.Checked)
await FixFeature(child);
}
}
}
/// <summary>
/// Restores a selected feature (always) or, if it's a category, only restores checked child features.
/// Logs success or failure.
/// </summary>
public static void RestoreFeature(TreeNode node)
{
// Restore feature node regardless of Checked state
if (node.Tag is FeatureNode fn && !fn.IsCategory && fn.Feature != null)
{
string displayName = LocalizationManager.LocalizeFeatureName(fn);
bool ok = fn.Feature.UndoFeature();
Logger.Log(ok
? $"{displayName} - Restored"
: $"{displayName} - Restore failed",
ok ? LogLevel.Info : LogLevel.Error);
}
else
{
// For category nodes, only restore checked children
foreach (TreeNode child in node.Nodes)
{
if (child.Checked)
RestoreFeature(child);
}
}
}
/// <summary>
/// Displays help information for the selected feature or plugin.
/// If a feature is selected, also offers to search online.
/// </summary>
public static void ShowHelp(TreeNode node)
{
// Show help for features
if (node?.Tag is FeatureNode fn && fn.Feature != null)
{
string displayName = LocalizationManager.LocalizeFeatureName(fn);
string info = fn.Feature.Info();
MessageBox.Show(
!string.IsNullOrEmpty(info) ? info : "No additional information available.",
$"Help: {displayName}",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
// Optional online help
var result = MessageBox.Show(
"Would you like to search online for more information about this feature?",
"Online Help",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
string searchQuery = Uri.EscapeDataString(fn.Feature.GetFeatureDetails());
string webUrl = $"https://www.google.com/search?q={searchQuery}";
System.Diagnostics.Process.Start(new ProcessStartInfo
{
FileName = webUrl,
UseShellExecute = true
});
}
return;
}
// Show help for plugins
if (!PluginManager.ShowHelp(node))
{
MessageBox.Show("No feature or plugin selected, or help info unavailable.",
"Help",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}
}
}
}