Skip to content

Commit 2c5daec

Browse files
author
BRUNER Patrick
committed
fixed
1 parent 2cecf4d commit 2c5daec

13 files changed

Lines changed: 713 additions & 230 deletions

File tree

src/LogExpert.Configuration/ConfigManager.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public class ConfigManager : IConfigManager
4646
};
4747

4848
private const string SETTINGS_FILE_NAME = "settings.json";
49+
private const int MAX_FILE_HISTORY = 10;
4950

5051
#endregion
5152

@@ -251,6 +252,35 @@ public void ImportHighlightSettings (FileInfo fileInfo, ExportImportFlags import
251252
Save(SettingsFlags.All);
252253
}
253254

255+
/// <summary>
256+
/// Adds the specified file name to the file history list, moving it to the top if it already exists.
257+
/// </summary>
258+
/// <remarks>If the file name already exists in the history, it is moved to the top of the list. The file
259+
/// history list is limited to a maximum number of entries; the oldest entries are removed if the limit is exceeded.
260+
/// This method is supported only on Windows platforms.</remarks>
261+
/// <param name="fileName">The name of the file to add to the file history list. Comparison is case-insensitive.</param>
262+
[SupportedOSPlatform("windows")]
263+
public void AddToFileHistory (string fileName)
264+
{
265+
bool findName (string s) => s.ToUpperInvariant().Equals(fileName.ToUpperInvariant(), StringComparison.Ordinal);
266+
267+
var index = Instance.Settings.FileHistoryList.FindIndex(findName);
268+
269+
if (index != -1)
270+
{
271+
Instance.Settings.FileHistoryList.RemoveAt(index);
272+
}
273+
274+
Instance.Settings.FileHistoryList.Insert(0, fileName);
275+
276+
while (Instance.Settings.FileHistoryList.Count > MAX_FILE_HISTORY)
277+
{
278+
Instance.Settings.FileHistoryList.RemoveAt(Instance.Settings.FileHistoryList.Count - 1);
279+
}
280+
281+
Save(SettingsFlags.FileHistory);
282+
}
283+
254284
#endregion
255285

256286
#region Private Methods
@@ -1061,6 +1091,7 @@ private bool ValidateSettings (Settings settings)
10611091

10621092
return true;
10631093
}
1094+
10641095
#endregion
10651096

10661097
/// <summary>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System.Collections.ObjectModel;
2+
3+
using LogExpert.Core.Interface;
4+
5+
namespace LogExpert.Core.Classes.Persister;
6+
7+
public static class PersisterHelpers
8+
{
9+
10+
private const string LOCAL_FILE_SYSTEM_NAME = "LocalFileSystem";
11+
12+
/// <summary>
13+
/// Checks if the file name is a settings file (.lxp). If so, the contained logfile name
14+
/// is returned. If not, the given file name is returned unchanged.
15+
/// </summary>
16+
/// <param name="fileName">The file name to resolve</param>
17+
/// <param name="pluginRegistry">Plugin registry for file system resolution (optional)</param>
18+
/// <returns>The resolved log file path</returns>
19+
public static string FindFilenameForSettings (string fileName, IPluginRegistry pluginRegistry)
20+
{
21+
ArgumentException.ThrowIfNullOrWhiteSpace(fileName, nameof(fileName));
22+
23+
if (fileName.EndsWith(".lxp", StringComparison.OrdinalIgnoreCase))
24+
{
25+
var persistenceData = Persister.Load(fileName);
26+
if (persistenceData == null)
27+
{
28+
return fileName;
29+
}
30+
31+
if (!string.IsNullOrEmpty(persistenceData.FileName))
32+
{
33+
if (pluginRegistry != null)
34+
{
35+
var fs = pluginRegistry.FindFileSystemForUri(persistenceData.FileName);
36+
// Use file system plugin for non-local files (network, SFTP, etc.)
37+
if (fs != null && fs.GetType().Name != LOCAL_FILE_SYSTEM_NAME)
38+
{
39+
return persistenceData.FileName;
40+
}
41+
}
42+
43+
// Handle rooted paths (absolute paths)
44+
if (Path.IsPathRooted(persistenceData.FileName))
45+
{
46+
return persistenceData.FileName;
47+
}
48+
49+
// Handle relative paths in .lxp files
50+
var dir = Path.GetDirectoryName(fileName);
51+
return Path.Join(dir, persistenceData.FileName);
52+
}
53+
}
54+
55+
return fileName;
56+
}
57+
58+
public static ReadOnlyCollection<string> FindFilenameForSettings (ReadOnlyCollection<string> fileNames, IPluginRegistry pluginRegistry)
59+
{
60+
ArgumentNullException.ThrowIfNull(fileNames);
61+
62+
var foundFiles = new List<string>(fileNames.Count);
63+
64+
foreach (var fileName in fileNames)
65+
{
66+
foundFiles.Add(FindFilenameForSettings(fileName, pluginRegistry));
67+
}
68+
69+
return foundFiles.AsReadOnly();
70+
}
71+
}

src/LogExpert.Core/Classes/Persister/PersisterXML.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,8 @@ public static PersistenceData Load (string fileName)
601601
}
602602
catch (Exception xmlParsingException) when (xmlParsingException is XmlException or
603603
UnauthorizedAccessException or
604-
IOException)
604+
IOException or
605+
FileNotFoundException)
605606
{
606607
_logger.Error(xmlParsingException, $"Error loading persistence data from {fileName}, unknown format, parsing xml or json was not possible");
607608
return null;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System.Collections.ObjectModel;
2+
3+
using LogExpert.Core.Interface;
4+
5+
namespace LogExpert.Core.Classes.Persister;
6+
7+
/// <summary>
8+
/// Helper class to resolve project file references to actual log files.
9+
/// Handles .lxp (persistence) files by extracting the actual log file path.
10+
/// </summary>
11+
public static class ProjectFileResolver
12+
{
13+
/// <summary>
14+
/// Resolves project file names to actual log files.
15+
/// If a file is a .lxp persistence file, extracts the log file path from it.
16+
/// </summary>
17+
/// <param name="projectData">The project data containing file references</param>
18+
/// <param name="pluginRegistry">Plugin registry for file system resolution (optional)</param>
19+
/// <returns>List of tuples containing (logFilePath, originalFilePath)</returns>
20+
public static ReadOnlyCollection<(string LogFile, string OriginalFile)> ResolveProjectFiles (ProjectData projectData, IPluginRegistry pluginRegistry = null)
21+
{
22+
ArgumentNullException.ThrowIfNull(projectData);
23+
24+
var resolved = new List<(string LogFile, string OriginalFile)>();
25+
26+
foreach (var fileName in projectData.FileNames)
27+
{
28+
var logFile = PersisterHelpers.FindFilenameForSettings(fileName, pluginRegistry);
29+
resolved.Add((logFile, fileName));
30+
}
31+
32+
return resolved.AsReadOnly();
33+
}
34+
}

src/LogExpert.Core/Classes/Persister/ProjectLoadResult.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace LogExpert.Core.Classes.Persister;
66
public class ProjectLoadResult
77
{
88
/// <summary>
9-
/// The loaded project data.
9+
/// The loaded project data (contains resolved log file paths).
1010
/// </summary>
1111
public ProjectData ProjectData { get; set; }
1212

@@ -15,6 +15,14 @@ public class ProjectLoadResult
1515
/// </summary>
1616
public ProjectValidationResult ValidationResult { get; set; }
1717

18+
/// <summary>
19+
/// Mapping of original file references to resolved log files.
20+
/// Key: resolved log file path (.log)
21+
/// Value: original file reference (.lxp or .log)
22+
/// Used to update persistence files when user selects alternatives.
23+
/// </summary>
24+
public Dictionary<string, string> LogToOriginalFileMapping { get; set; } = [];
25+
1826
/// <summary>
1927
/// Indicates whether the project has at least one valid file to load.
2028
/// </summary>

src/LogExpert.Core/Classes/Persister/ProjectPersister.cs

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public static class ProjectPersister
1616

1717
/// <summary>
1818
/// Loads the project session data from a specified file, including validation of referenced files.
19+
/// Resolves .lxp persistence files to actual .log files before validation.
1920
/// </summary>
2021
/// <param name="projectFileName">The path to the project file (.lxj)</param>
2122
/// <param name="pluginRegistry">The plugin registry for file system validation</param>
@@ -35,13 +36,32 @@ public static ProjectLoadResult LoadProjectData (string projectFileName, IPlugin
3536
// Set project file path for alternative file search
3637
projectData.ProjectFilePath = projectFileName;
3738

38-
// Validate all files referenced in the project
39-
var validationResult = ProjectFileValidator.ValidateProject(projectData, pluginRegistry);
39+
// Resolve .lxp files to actual .log files
40+
var resolvedFiles = ProjectFileResolver.ResolveProjectFiles(projectData, pluginRegistry);
41+
42+
// Create mapping: logFile → originalFile
43+
var logToOriginalMapping = new Dictionary<string, string>();
44+
foreach (var (logFile, originalFile) in resolvedFiles)
45+
{
46+
logToOriginalMapping[logFile] = originalFile;
47+
}
48+
49+
// Create new ProjectData with resolved log file paths
50+
var resolvedProjectData = new ProjectData
51+
{
52+
FileNames = [.. resolvedFiles.Select(r => r.LogFile)],
53+
TabLayoutXml = projectData.TabLayoutXml,
54+
ProjectFilePath = projectData.ProjectFilePath
55+
};
56+
57+
// Validate the actual log files (not .lxp files)
58+
var validationResult = ProjectFileValidator.ValidateProject(resolvedProjectData, pluginRegistry);
4059

4160
return new ProjectLoadResult
4261
{
43-
ProjectData = projectData,
44-
ValidationResult = validationResult
62+
ProjectData = resolvedProjectData,
63+
ValidationResult = validationResult,
64+
LogToOriginalFileMapping = logToOriginalMapping
4565
};
4666
}
4767
catch (Exception ex) when (ex is UnauthorizedAccessException or
@@ -55,13 +75,29 @@ IOException or
5575
// Set project file path for alternative file search
5676
projectData.ProjectFilePath = projectFileName;
5777

58-
// Validate files from XML fallback as well
59-
var validationResult = ProjectFileValidator.ValidateProject(projectData, pluginRegistry);
78+
// Resolve .lxp files for XML fallback as well
79+
var resolvedFiles = ProjectFileResolver.ResolveProjectFiles(projectData, pluginRegistry);
80+
81+
var logToOriginalMapping = new Dictionary<string, string>();
82+
foreach (var (logFile, originalFile) in resolvedFiles)
83+
{
84+
logToOriginalMapping[logFile] = originalFile;
85+
}
86+
87+
var resolvedProjectData = new ProjectData
88+
{
89+
FileNames = [.. resolvedFiles.Select(r => r.LogFile)],
90+
TabLayoutXml = projectData.TabLayoutXml,
91+
ProjectFilePath = projectData.ProjectFilePath
92+
};
93+
94+
var validationResult = ProjectFileValidator.ValidateProject(resolvedProjectData, pluginRegistry);
6095

6196
return new ProjectLoadResult
6297
{
63-
ProjectData = projectData,
64-
ValidationResult = validationResult
98+
ProjectData = resolvedProjectData,
99+
ValidationResult = validationResult,
100+
LogToOriginalFileMapping = logToOriginalMapping
65101
};
66102
}
67103
}

src/LogExpert.Core/Interface/IConfigManager.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,13 @@ public interface IConfigManager
142142
/// <exception cref="InvalidOperationException">Thrown if settings validation fails.</exception>
143143
/// <exception cref="IOException">Thrown if the file cannot be written.</exception>
144144
void Save (SettingsFlags flags);
145+
146+
/// <summary>
147+
/// Adds the specified file name to the file history list, moving it to the top if it already exists.
148+
/// </summary>
149+
/// <remarks>If the file name already exists in the history, it is moved to the top of the list. The file
150+
/// history list is limited to a maximum number of entries; the oldest entries are removed if the limit is exceeded.
151+
/// This method is supported only on Windows platforms.</remarks>
152+
/// <param name="fileName">The name of the file to add to the file history list. Comparison is case-insensitive.</param>
153+
void AddToFileHistory (string fileName);
145154
}

0 commit comments

Comments
 (0)