using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Windows.Forms; public static class IniStateManager { // CrapFixer.ini path private static readonly string IniPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CrapFixer.ini"); private static readonly object FileLock = new object(); // Saves the global states (App size, TreeView nodes states) public static void Save(TreeView tree, Form form) { lock (FileLock) { // Read existing lines if file exists var lines = File.Exists(IniPath) ? File.ReadAllLines(IniPath).ToList() : new List(); // Remove old APP and FEATURES sections RemoveSection(lines, "APP"); RemoveSection(lines, "FEATURES"); // Append new APP section lines.Add("[APP]"); lines.Add($"Width={form.Width}"); lines.Add($"Height={form.Height}"); lines.Add($"Top={form.Top}"); lines.Add($"Left={form.Left}"); // lines.Add(""); // empty line for spacing // Append new FEATURES section (TreeView nodes states) lines.Add("[FEATURES]"); AppendNodeStates(lines, tree.Nodes); // Write all back File.WriteAllLines(IniPath, lines); } } // Removes a section from the INI content private static void RemoveSection(List lines, string sectionName) { int start = lines.FindIndex(l => l.Trim().Equals($"[{sectionName}]", StringComparison.OrdinalIgnoreCase)); if (start < 0) return; int end = start + 1; while (end < lines.Count && !lines[end].TrimStart().StartsWith("[")) end++; lines.RemoveRange(start, end - start); } // Helper to write TreeNode states to a list of strings private static void AppendNodeStates(List lines, TreeNodeCollection nodes) { foreach (TreeNode node in nodes) { lines.Add($"{node.Text.Trim()}={node.Checked}"); if (node.Nodes.Count > 0) AppendNodeStates(lines, node.Nodes); } } // Loads the global states (App size, TreeView nodes states) if enabled public static void LoadFeaturesIfEnabled(TreeView tree) { if (IsViewSettingEnabled("SETTINGS", "checkSaveToINI")) LoadFeatureStates(tree); } public static void ApplyWindowState(Form form) { if (File.Exists(IniPath)) { // Load window size and position from INI file LoadWindowState(form); form.StartPosition = FormStartPosition.Manual; } else { // If INI file doesn't exist, set default position form.StartPosition = FormStartPosition.CenterScreen; } } // Loads only the window size and position from the INI file public static void LoadWindowState(Form form) { if (!File.Exists(IniPath)) return; var lines = File.ReadAllLines(IniPath); var section = ""; foreach (var line in lines) { var trimmed = line.Trim(); if (string.IsNullOrWhiteSpace(trimmed)) continue; // Check if line is a section header if (trimmed.StartsWith("[") && trimmed.EndsWith("]")) { section = trimmed; continue; } if (section == "[APP]") { // Split line into key and value var parts = trimmed.Split(new[] { '=' }, 2); if (parts.Length != 2) continue; var key = parts[0].Trim(); var value = parts[1].Trim(); // Parse and apply window size and position if (int.TryParse(value, out int size)) { if (key.Equals("Width", StringComparison.OrdinalIgnoreCase)) form.Width = size; else if (key.Equals("Height", StringComparison.OrdinalIgnoreCase)) form.Height = size; else if (key.Equals("Top", StringComparison.OrdinalIgnoreCase)) form.Top = size; else if (key.Equals("Left", StringComparison.OrdinalIgnoreCase)) form.Left = size; } } } } // Loads only the feature states (TreeView node checked states) from the INI file public static void LoadFeatureStates(TreeView tree) { if (!File.Exists(IniPath)) return; var lines = File.ReadAllLines(IniPath); var section = ""; var states = new Dictionary(); foreach (var line in lines) { var trimmed = line.Trim(); if (string.IsNullOrWhiteSpace(trimmed)) continue; // Check if line is a section header if (trimmed.StartsWith("[") && trimmed.EndsWith("]")) { section = trimmed; continue; } if (section == "[FEATURES]") { // Split line into key and value var parts = trimmed.Split(new[] { '=' }, 2); if (parts.Length != 2) continue; var key = parts[0].Trim(); var value = parts[1].Trim(); // Save checked state for each feature node states[key] = value.ToLower() == "true"; } } // Apply saved feature states to the TreeView nodes recursively ApplyStates(tree.Nodes, states); } // Applies the saved states to the TreeView nodes private static void ApplyStates(TreeNodeCollection nodes, Dictionary states) { foreach (TreeNode node in nodes) { string nodeName = node.Text.Trim(); if (states.ContainsKey(nodeName)) node.Checked = states[nodeName]; if (node.Nodes.Count > 0) ApplyStates(node.Nodes, states); } } // Saves individual settings (like checkbox states) for a specific view public static void SaveViewSettings(string viewName, Dictionary settings) { lock (FileLock) { var lines = File.Exists(IniPath) ? File.ReadAllLines(IniPath).ToList() : new List(); // Remove previous section to avoid duplicates RemoveSection(lines, viewName); // Append new section with updated settings lines.Add($"[{viewName}]"); foreach (var kvp in settings) { lines.Add($"{kvp.Key}={kvp.Value}"); } File.WriteAllLines(IniPath, lines); } } // Loads individual settings for a specific view (e.g. checkboxes) public static Dictionary LoadViewSettings(string viewName) { var result = new Dictionary(); if (!File.Exists(IniPath)) return result; var lines = File.ReadAllLines(IniPath); bool inTargetSection = false; foreach (var line in lines) { var trimmed = line.Trim(); if (string.IsNullOrWhiteSpace(trimmed)) continue; // Check if we are in the desired view section if (trimmed.StartsWith("[") && trimmed.EndsWith("]")) { inTargetSection = trimmed.Equals($"[{viewName}]", StringComparison.OrdinalIgnoreCase); continue; } if (!inTargetSection) continue; var parts = trimmed.Split(new[] { '=' }, 2); if (parts.Length != 2) continue; var key = parts[0].Trim(); var value = parts[1].Trim(); result[key] = value.ToLower() == "true"; } return result; } // Checks if a setting exists in a specific section public static bool IsViewSettingEnabled(string sectionName, string settingName) { var settings = LoadViewSettings(sectionName); return settings.ContainsKey(settingName) && settings[settingName]; } } /// /// Extension methods for IDictionary to provide default value retrieval. /// public static class DictionaryExtensions { public static TValue GetValueOrDefault(this IDictionary dict, TKey key, TValue defaultValue = default) { return dict.TryGetValue(key, out var value) ? value : defaultValue; } }