mirror of
https://github.com/AntonyCorbett/JWLMerge
synced 2026-01-16 21:04:20 -05:00
analyzer warnings
This commit is contained in:
@@ -2,3 +2,21 @@
|
||||
|
||||
# S112: General exceptions should never be thrown
|
||||
dotnet_diagnostic.S112.severity = silent
|
||||
|
||||
# U2U1202: Use LINQ Count methods efficiently
|
||||
dotnet_diagnostic.U2U1202.severity = silent
|
||||
|
||||
# RCS1037: Remove trailing white-space.
|
||||
dotnet_diagnostic.RCS1037.severity = silent
|
||||
|
||||
# U2U1108: StringBuilders should be initialized with capacity
|
||||
dotnet_diagnostic.U2U1108.severity = silent
|
||||
|
||||
# U2U1009: Async or iterator methods should avoid state machine generation for early exits (throws or synchronous returns)
|
||||
dotnet_diagnostic.U2U1009.severity = silent
|
||||
|
||||
# U2U1212: Capture intermediate results in lambda expressions
|
||||
dotnet_diagnostic.U2U1212.severity = silent
|
||||
|
||||
# U2U1201: Local collections should be initialized with capacity
|
||||
dotnet_diagnostic.U2U1201.severity = silent
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using JWLMerge.BackupFileServices.Events;
|
||||
using JWLMerge.BackupFileServices.Exceptions;
|
||||
using JWLMerge.BackupFileServices.Helpers;
|
||||
using JWLMerge.BackupFileServices.Models;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using JWLMerge.BackupFileServices.Models.ManifestFile;
|
||||
using JWLMerge.ExcelServices;
|
||||
using Events;
|
||||
using Exceptions;
|
||||
using Helpers;
|
||||
using Models;
|
||||
using Models.DatabaseModels;
|
||||
using Models.ManifestFile;
|
||||
using ExcelServices;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
@@ -33,7 +33,7 @@
|
||||
_merger.ProgressEvent += MergerProgressEvent;
|
||||
}
|
||||
|
||||
public event EventHandler<ProgressEventArgs> ProgressEvent;
|
||||
public event EventHandler<ProgressEventArgs>? ProgressEvent;
|
||||
|
||||
/// <inheritdoc />
|
||||
public BackupFile Load(string backupFilePath)
|
||||
@@ -53,18 +53,16 @@
|
||||
var filename = Path.GetFileName(backupFilePath);
|
||||
ProgressMessage($"Loading {filename}");
|
||||
|
||||
using (var archive = new ZipArchive(File.OpenRead(backupFilePath), ZipArchiveMode.Read))
|
||||
using var archive = new ZipArchive(File.OpenRead(backupFilePath), ZipArchiveMode.Read);
|
||||
var manifest = ReadManifest(filename, archive);
|
||||
|
||||
var database = ReadDatabase(archive, manifest.UserDataBackup.DatabaseName);
|
||||
|
||||
return new BackupFile
|
||||
{
|
||||
var manifest = ReadManifest(filename, archive);
|
||||
|
||||
var database = ReadDatabase(archive, manifest.UserDataBackup.DatabaseName);
|
||||
|
||||
return new BackupFile
|
||||
{
|
||||
Manifest = manifest,
|
||||
Database = database,
|
||||
};
|
||||
}
|
||||
Manifest = manifest,
|
||||
Database = database,
|
||||
};
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
@@ -137,7 +135,7 @@
|
||||
/// <inheritdoc />
|
||||
public int RemoveNotesByTag(
|
||||
BackupFile backup,
|
||||
int[] tagIds,
|
||||
int[]? tagIds,
|
||||
bool removeUntaggedNotes,
|
||||
bool removeAssociatedUnderlining,
|
||||
bool removeAssociatedTags)
|
||||
@@ -147,10 +145,7 @@
|
||||
throw new ArgumentNullException(nameof(backup));
|
||||
}
|
||||
|
||||
if (tagIds == null)
|
||||
{
|
||||
tagIds = Array.Empty<int>();
|
||||
}
|
||||
tagIds ??= Array.Empty<int>();
|
||||
|
||||
var tagIdsHash = tagIds.ToHashSet();
|
||||
|
||||
@@ -199,17 +194,14 @@
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int RemoveUnderliningByColour(BackupFile backup, int[] colorIndexes, bool removeAssociatedNotes)
|
||||
public int RemoveUnderliningByColour(BackupFile backup, int[]? colorIndexes, bool removeAssociatedNotes)
|
||||
{
|
||||
if (backup == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(backup));
|
||||
}
|
||||
|
||||
if (colorIndexes == null)
|
||||
{
|
||||
colorIndexes = Array.Empty<int>();
|
||||
}
|
||||
colorIndexes ??= Array.Empty<int>();
|
||||
|
||||
var userMarkIdsToRemove = new HashSet<int>();
|
||||
|
||||
@@ -229,7 +221,7 @@
|
||||
BackupFile backup,
|
||||
int colorIndex,
|
||||
bool anyColor,
|
||||
string publicationSymbol,
|
||||
string? publicationSymbol,
|
||||
bool anyPublication,
|
||||
bool removeAssociatedNotes)
|
||||
{
|
||||
@@ -277,48 +269,45 @@
|
||||
}
|
||||
|
||||
ProgressMessage("Writing merged database file");
|
||||
|
||||
using (var memoryStream = new MemoryStream())
|
||||
|
||||
using var memoryStream = new MemoryStream();
|
||||
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
|
||||
{
|
||||
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
|
||||
Log.Logger.Debug("Created ZipArchive");
|
||||
|
||||
var tmpDatabaseFileName = ExtractDatabaseToFile(originalJwlibraryFilePathForSchema);
|
||||
try
|
||||
{
|
||||
Log.Logger.Debug("Created ZipArchive");
|
||||
backup.Manifest.UserDataBackup.Hash = GenerateDatabaseHash(tmpDatabaseFileName);
|
||||
|
||||
var tmpDatabaseFileName = ExtractDatabaseToFile(originalJwlibraryFilePathForSchema);
|
||||
try
|
||||
var manifestEntry = archive.CreateEntry(ManifestEntryName);
|
||||
using (var entryStream = manifestEntry.Open())
|
||||
using (var streamWriter = new StreamWriter(entryStream))
|
||||
{
|
||||
backup.Manifest.UserDataBackup.Hash = GenerateDatabaseHash(tmpDatabaseFileName);
|
||||
|
||||
var manifestEntry = archive.CreateEntry(ManifestEntryName);
|
||||
using (var entryStream = manifestEntry.Open())
|
||||
using (var streamWriter = new StreamWriter(entryStream))
|
||||
{
|
||||
streamWriter.Write(
|
||||
JsonConvert.SerializeObject(
|
||||
backup.Manifest,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
}));
|
||||
}
|
||||
streamWriter.Write(
|
||||
JsonConvert.SerializeObject(
|
||||
backup.Manifest,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
}));
|
||||
}
|
||||
|
||||
AddDatabaseEntryToArchive(archive, backup.Database, tmpDatabaseFileName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.Logger.Debug("Deleting {tmpDatabaseFileName}", tmpDatabaseFileName);
|
||||
File.Delete(tmpDatabaseFileName);
|
||||
}
|
||||
AddDatabaseEntryToArchive(archive, backup.Database, tmpDatabaseFileName);
|
||||
}
|
||||
|
||||
using (var fileStream = new FileStream(newDatabaseFilePath, FileMode.Create))
|
||||
finally
|
||||
{
|
||||
ProgressMessage("Finishing");
|
||||
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
memoryStream.CopyTo(fileStream);
|
||||
Log.Logger.Debug("Deleting {tmpDatabaseFileName}", tmpDatabaseFileName);
|
||||
File.Delete(tmpDatabaseFileName);
|
||||
}
|
||||
}
|
||||
|
||||
using var fileStream = new FileStream(newDatabaseFilePath, FileMode.Create);
|
||||
|
||||
ProgressMessage("Finishing");
|
||||
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
memoryStream.CopyTo(fileStream);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -407,7 +396,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
int countRemoved = 0;
|
||||
var countRemoved = 0;
|
||||
foreach (var userMark in Enumerable.Reverse(database.UserMarks))
|
||||
{
|
||||
if (!userMarksToRetain.Contains(userMark.UserMarkId))
|
||||
@@ -457,7 +446,7 @@
|
||||
|
||||
ProgressMessage($"Merging {files.Count} backup files");
|
||||
|
||||
int fileNumber = 1;
|
||||
var fileNumber = 1;
|
||||
var originals = new List<BackupFile>();
|
||||
foreach (var file in files)
|
||||
{
|
||||
@@ -547,10 +536,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
notesToWrite.Add(new ExcelServices.Models.BibleNote
|
||||
notesToWrite.Add(new ExcelServices.Models.BibleNote(
|
||||
location.BookNumber.Value, BibleBookNames.GetName(location.BookNumber.Value))
|
||||
{
|
||||
BookNumber = location.BookNumber.Value,
|
||||
BookName = BibleBookNames.GetName(location.BookNumber.Value),
|
||||
ChapterNumber = location.ChapterNumber,
|
||||
VerseNumber = note.BlockIdentifier,
|
||||
NoteTitle = note.Title?.Trim(),
|
||||
@@ -573,13 +561,14 @@
|
||||
|
||||
private static string GetTagsAsCsv(ILookup<int?, TagMap> tags, int noteId, Database database)
|
||||
{
|
||||
var t = tags[noteId]?.ToArray();
|
||||
if (t == null || !t.Any())
|
||||
var t = tags[noteId].ToArray();
|
||||
if (!t.Any())
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return string.Join(", ", t.Select(x => database.FindTag(x.TagId).Name));
|
||||
var tagNames = t.Select(x => database.FindTag(x.TagId)?.Name).Where(x => !string.IsNullOrEmpty(x));
|
||||
return string.Join(", ", tagNames);
|
||||
}
|
||||
|
||||
private static bool SupportDatabaseVersion(int version)
|
||||
@@ -641,7 +630,7 @@
|
||||
}
|
||||
|
||||
private static bool ShouldRemoveUnderlining(
|
||||
UserMark mark, Database database, int colorIndex, bool anyColor, string publicationSymbol, bool anyPublication)
|
||||
UserMark mark, Database database, int colorIndex, bool anyColor, string? publicationSymbol, bool anyPublication)
|
||||
{
|
||||
if (!anyColor && mark.ColorIndex != colorIndex)
|
||||
{
|
||||
@@ -654,7 +643,7 @@
|
||||
}
|
||||
|
||||
var location = database.FindLocation(mark.LocationId);
|
||||
return location.KeySymbol == publicationSymbol;
|
||||
return location != null && location.KeySymbol == publicationSymbol;
|
||||
}
|
||||
|
||||
private static int RemoveUnderlining(Database database, HashSet<int> userMarkIdsToRemove, bool removeAssociatedNotes)
|
||||
@@ -797,20 +786,18 @@
|
||||
private string ExtractDatabaseToFile(string jwlibraryFile)
|
||||
{
|
||||
Log.Logger.Debug("Opening ZipArchive {jwlibraryFile}", jwlibraryFile);
|
||||
|
||||
using (var archive = new ZipArchive(File.OpenRead(jwlibraryFile), ZipArchiveMode.Read))
|
||||
{
|
||||
var manifest = ReadManifest(Path.GetFileName(jwlibraryFile), archive);
|
||||
|
||||
var databaseEntry = archive.Entries.FirstOrDefault(x => x.Name.Equals(manifest.UserDataBackup.DatabaseName, StringComparison.OrdinalIgnoreCase));
|
||||
using var archive = new ZipArchive(File.OpenRead(jwlibraryFile), ZipArchiveMode.Read);
|
||||
var manifest = ReadManifest(Path.GetFileName(jwlibraryFile), archive);
|
||||
|
||||
var databaseEntry = archive.Entries.FirstOrDefault(x => x.Name.Equals(manifest.UserDataBackup.DatabaseName, StringComparison.OrdinalIgnoreCase));
|
||||
#pragma warning disable S5445 // Insecure temporary file creation methods should not be used
|
||||
var tmpFile = Path.GetTempFileName();
|
||||
var tmpFile = Path.GetTempFileName();
|
||||
#pragma warning restore S5445 // Insecure temporary file creation methods should not be used
|
||||
databaseEntry.ExtractToFile(tmpFile, overwrite: true);
|
||||
databaseEntry.ExtractToFile(tmpFile, overwrite: true);
|
||||
|
||||
Log.Logger.Information("Created temp file: {tmpDatabaseFileName}", tmpFile);
|
||||
return tmpFile;
|
||||
}
|
||||
Log.Logger.Information("Created temp file: {tmpDatabaseFileName}", tmpFile);
|
||||
return tmpFile;
|
||||
}
|
||||
|
||||
private Manifest ReadManifest(string filename, ZipArchive archive)
|
||||
@@ -822,32 +809,81 @@
|
||||
{
|
||||
throw new BackupFileServicesException($"Could not find manifest entry in jwlibrary file: {filename}");
|
||||
}
|
||||
|
||||
using (var stream = new StreamReader(manifestEntry.Open()))
|
||||
{
|
||||
var fileContents = stream.ReadToEnd();
|
||||
|
||||
Log.Logger.Debug("Parsing manifest");
|
||||
dynamic data = JObject.Parse(fileContents);
|
||||
using var stream = new StreamReader(manifestEntry.Open());
|
||||
|
||||
var fileContents = stream.ReadToEnd();
|
||||
|
||||
Log.Logger.Debug("Parsing manifest");
|
||||
dynamic data = JObject.Parse(fileContents);
|
||||
|
||||
int manifestVersion = data.version ?? 0;
|
||||
if (!SupportManifestVersion(manifestVersion))
|
||||
{
|
||||
throw new WrongManifestVersionException(filename, ManifestVersionSupported, manifestVersion);
|
||||
}
|
||||
int manifestVersion = data.version ?? 0;
|
||||
if (!SupportManifestVersion(manifestVersion))
|
||||
{
|
||||
throw new WrongManifestVersionException(filename, ManifestVersionSupported, manifestVersion);
|
||||
}
|
||||
|
||||
int databaseVersion = data.userDataBackup.schemaVersion ?? 0;
|
||||
if (!SupportDatabaseVersion(databaseVersion))
|
||||
{
|
||||
throw new WrongDatabaseVersionException(filename, DatabaseVersionSupported, databaseVersion);
|
||||
}
|
||||
int databaseVersion = data.userDataBackup?.schemaVersion ?? 0;
|
||||
if (!SupportDatabaseVersion(databaseVersion))
|
||||
{
|
||||
throw new WrongDatabaseVersionException(filename, DatabaseVersionSupported, databaseVersion);
|
||||
}
|
||||
|
||||
var result = JsonConvert.DeserializeObject<Manifest>(fileContents);
|
||||
var result = JsonConvert.DeserializeObject<Manifest>(fileContents);
|
||||
|
||||
var prettyJson = JsonConvert.SerializeObject(result, Formatting.Indented);
|
||||
Log.Logger.Debug("Parsed manifest {manifestJson}", prettyJson);
|
||||
ValidateManifest(filename, result);
|
||||
|
||||
return result;
|
||||
var prettyJson = JsonConvert.SerializeObject(result, Formatting.Indented);
|
||||
Log.Logger.Debug("Parsed manifest {manifestJson}", prettyJson);
|
||||
|
||||
return result!;
|
||||
}
|
||||
|
||||
private static void ValidateManifest(string filename, Manifest? result)
|
||||
{
|
||||
if (result == null)
|
||||
{
|
||||
throw new BackupFileServicesException($"Could not deserialize manifest entry from jwlibrary file: {filename}");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(result.Name))
|
||||
{
|
||||
throw new BackupFileServicesException($"Could not retrieve manifest name from jwlibrary file: {filename}");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(result.CreationDate))
|
||||
{
|
||||
throw new BackupFileServicesException($"Could not retrieve manifest creation date from jwlibrary file: {filename}");
|
||||
}
|
||||
|
||||
ValidateUserDataBackup(filename, result.UserDataBackup);
|
||||
}
|
||||
|
||||
private static void ValidateUserDataBackup(string filename, UserDataBackup userDataBackup)
|
||||
{
|
||||
if (userDataBackup == null)
|
||||
{
|
||||
throw new BackupFileServicesException($"Could not retrieve UserDataBackup element from jwlibrary file: {filename}");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(userDataBackup.DatabaseName))
|
||||
{
|
||||
throw new BackupFileServicesException($"DatabaseName element empty in UserDataBackup from jwlibrary file: {filename}");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(userDataBackup.DeviceName))
|
||||
{
|
||||
throw new BackupFileServicesException($"DeviceName element empty in UserDataBackup from jwlibrary file: {filename}");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(userDataBackup.Hash))
|
||||
{
|
||||
throw new BackupFileServicesException($"Hash element empty in UserDataBackup from jwlibrary file: {filename}");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(userDataBackup.LastModifiedDate))
|
||||
{
|
||||
throw new BackupFileServicesException($"LastModifiedDate element empty in UserDataBackup from jwlibrary file: {filename}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -862,21 +898,18 @@
|
||||
{
|
||||
ProgressMessage("Generating database hash");
|
||||
|
||||
using (var fs = new FileStream(databaseFilePath, FileMode.Open))
|
||||
{
|
||||
using (var bs = new BufferedStream(fs))
|
||||
using (var sha1 = new SHA256Managed())
|
||||
{
|
||||
byte[] hash = sha1.ComputeHash(bs);
|
||||
var sb = new StringBuilder(2 * hash.Length);
|
||||
foreach (byte b in hash)
|
||||
{
|
||||
sb.Append($"{b:x2}");
|
||||
}
|
||||
using var fs = new FileStream(databaseFilePath, FileMode.Open);
|
||||
using var bs = new BufferedStream(fs);
|
||||
using var sha1 = new SHA256Managed();
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
byte[] hash = sha1.ComputeHash(bs);
|
||||
var sb = new StringBuilder(2 * hash.Length);
|
||||
foreach (byte b in hash)
|
||||
{
|
||||
sb.Append($"{b:x2}");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private void AddDatabaseEntryToArchive(
|
||||
@@ -904,7 +937,7 @@
|
||||
|
||||
private void OnProgressEvent(string message)
|
||||
{
|
||||
OnProgressEvent(new ProgressEventArgs { Message = message });
|
||||
OnProgressEvent(new ProgressEventArgs(message));
|
||||
}
|
||||
|
||||
private void ProgressMessage(string logMessage)
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
|
||||
public class ProgressEventArgs : EventArgs
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public ProgressEventArgs(string msg)
|
||||
{
|
||||
Message = msg;
|
||||
}
|
||||
|
||||
public string Message { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
[Serializable]
|
||||
#pragma warning disable RCS1194 // Implement exception constructors.
|
||||
public class WrongDatabaseVersionException : BackupFileServicesException
|
||||
#pragma warning restore RCS1194 // Implement exception constructors.
|
||||
{
|
||||
public WrongDatabaseVersionException(string filename, int expectedVersion, int foundVersion)
|
||||
: base($"Wrong database version found ({foundVersion}) in {filename}. Expecting {expectedVersion}")
|
||||
@@ -20,7 +22,7 @@
|
||||
{
|
||||
}
|
||||
|
||||
public string Filename { get; }
|
||||
public string? Filename { get; }
|
||||
|
||||
public int ExpectedVersion { get; }
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
[Serializable]
|
||||
#pragma warning disable RCS1194 // Implement exception constructors.
|
||||
public class WrongManifestVersionException : BackupFileServicesException
|
||||
#pragma warning restore RCS1194 // Implement exception constructors.
|
||||
{
|
||||
public WrongManifestVersionException(string filename, int expectedVersion, int foundVersion)
|
||||
: base($"Wrong manifest version found ({foundVersion}) in {filename}. Expecting {expectedVersion}")
|
||||
@@ -20,7 +22,7 @@
|
||||
{
|
||||
}
|
||||
|
||||
public string Filename { get; }
|
||||
public string? Filename { get; }
|
||||
|
||||
public int ExpectedVersion { get; }
|
||||
|
||||
|
||||
@@ -4,18 +4,18 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using JWLMerge.BackupFileServices.Models;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using Models;
|
||||
using Models.DatabaseModels;
|
||||
|
||||
public class BibleNotesFile
|
||||
{
|
||||
private const int MaxTitleLength = 50;
|
||||
private const string BibleKeySymbolToken = @"[BibleKeySymbol";
|
||||
private const string MepsLanguageIdToken = @"[MepsLanguageId";
|
||||
private const string BibleKeySymbolToken = "[BibleKeySymbol";
|
||||
private const string MepsLanguageIdToken = "[MepsLanguageId";
|
||||
|
||||
private readonly List<BibleNote> _notes = new List<BibleNote>();
|
||||
private readonly string _path;
|
||||
private string _bibleKeySymbol;
|
||||
private string _bibleKeySymbol = null!;
|
||||
private int _mepsLanguageId;
|
||||
private bool _initialised;
|
||||
|
||||
@@ -61,15 +61,17 @@
|
||||
ParseNotes(lines);
|
||||
}
|
||||
|
||||
private void RemoveParamLines(string[] lines)
|
||||
private static void RemoveParamLines(string[] lines)
|
||||
{
|
||||
RemoveLineStarting(BibleKeySymbolToken, lines);
|
||||
RemoveLineStarting(MepsLanguageIdToken, lines);
|
||||
}
|
||||
|
||||
private void RemoveLineStarting(string token, string[] lines)
|
||||
private static void RemoveLineStarting(string token, string[] lines)
|
||||
{
|
||||
for (int n = 0; n < lines.Length; ++n)
|
||||
#pragma warning disable U2U1015 // Do not index an array multiple times within a loop body
|
||||
for (var n = 0; n < lines.Length; ++n)
|
||||
#pragma warning restore U2U1015 // Do not index an array multiple times within a loop body
|
||||
{
|
||||
if (lines[n].Trim().StartsWith(token, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
@@ -98,7 +100,7 @@
|
||||
{
|
||||
var linesInNote = new List<string>();
|
||||
|
||||
BibleNotesVerseSpecification currentVerseSpec = null;
|
||||
BibleNotesVerseSpecification? currentVerseSpec = null;
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
@@ -122,7 +124,7 @@
|
||||
StoreNote(linesInNote, currentVerseSpec);
|
||||
}
|
||||
|
||||
private void StoreNote(IReadOnlyList<string> lines, BibleNotesVerseSpecification currentVerseSpec)
|
||||
private void StoreNote(IReadOnlyList<string> lines, BibleNotesVerseSpecification? currentVerseSpec)
|
||||
{
|
||||
if (currentVerseSpec == null)
|
||||
{
|
||||
@@ -142,15 +144,15 @@
|
||||
currentVerseSpec.ChapterNumber,
|
||||
currentVerseSpec.VerseNumber),
|
||||
|
||||
NoteTitle = titleAndContent.Title.Trim(),
|
||||
NoteContent = titleAndContent.Content.Trim(),
|
||||
NoteTitle = titleAndContent.Title?.Trim(),
|
||||
NoteContent = titleAndContent.Content?.Trim(),
|
||||
ColourIndex = currentVerseSpec.ColourIndex,
|
||||
StartTokenInVerse = currentVerseSpec.StartWordIndex,
|
||||
EndTokenInVerse = currentVerseSpec.EndWordIndex,
|
||||
});
|
||||
}
|
||||
|
||||
private NoteTitleAndContent ParseTitleAndContent(IReadOnlyList<string> lines)
|
||||
private static NoteTitleAndContent? ParseTitleAndContent(IReadOnlyList<string> lines)
|
||||
{
|
||||
if (lines.Count == 0)
|
||||
{
|
||||
@@ -174,11 +176,11 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
private BibleNotesVerseSpecification GetVerseSpecification(string line)
|
||||
private static BibleNotesVerseSpecification? GetVerseSpecification(string line)
|
||||
{
|
||||
var trimmed = line.Trim();
|
||||
|
||||
if (!trimmed.StartsWith("[") || !trimmed.EndsWith("]"))
|
||||
if (!trimmed.StartsWith("[", StringComparison.Ordinal) || !trimmed.EndsWith("]", StringComparison.Ordinal))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -251,7 +253,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
private string FindValue(string[] lines, string token)
|
||||
private static string? FindValue(string[] lines, string token)
|
||||
{
|
||||
var line = lines.FirstOrDefault(x =>
|
||||
x.Trim().StartsWith(token, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using Models.DatabaseModels;
|
||||
using Serilog;
|
||||
|
||||
/// <summary>
|
||||
/// Cleans jwlibrary files by removing redundant or anomalous database rows.
|
||||
/// </summary>
|
||||
internal class Cleaner
|
||||
internal sealed class Cleaner
|
||||
{
|
||||
private readonly Database _database;
|
||||
|
||||
@@ -114,11 +114,10 @@
|
||||
{
|
||||
int removed = 0;
|
||||
|
||||
var userMarkIdsFound = new HashSet<int>();
|
||||
|
||||
var ranges = _database.BlockRanges;
|
||||
if (ranges.Any())
|
||||
{
|
||||
var userMarkIdsFound = new HashSet<int>();
|
||||
var userMarkIds = GetUserMarkIdsInUse();
|
||||
|
||||
foreach (var range in Enumerable.Reverse(ranges))
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using Models.DatabaseModels;
|
||||
using Serilog;
|
||||
|
||||
/// <summary>
|
||||
/// Isolates all data access to the SQLite database embedded in
|
||||
/// jwlibrary files.
|
||||
/// </summary>
|
||||
internal class DataAccessLayer
|
||||
internal sealed class DataAccessLayer
|
||||
{
|
||||
private readonly string _databaseFilePath;
|
||||
|
||||
@@ -27,13 +27,12 @@
|
||||
public void CreateEmptyClone(string cloneFilePath)
|
||||
{
|
||||
Log.Logger.Debug($"Creating empty clone: {cloneFilePath}");
|
||||
|
||||
using (var source = CreateConnection(_databaseFilePath))
|
||||
using (var destination = CreateConnection(cloneFilePath))
|
||||
{
|
||||
source.BackupDatabase(destination, "main", "main");
|
||||
ClearData(destination);
|
||||
}
|
||||
|
||||
using var source = CreateConnection(_databaseFilePath);
|
||||
using var destination = CreateConnection(cloneFilePath);
|
||||
|
||||
source.BackupDatabase(destination, "main", "main");
|
||||
ClearData(destination);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -62,23 +61,22 @@
|
||||
{
|
||||
var result = new Database();
|
||||
|
||||
using (var connection = CreateConnection())
|
||||
{
|
||||
result.InitBlank();
|
||||
using var connection = CreateConnection();
|
||||
|
||||
result.LastModified.TimeLastModified = ReadAllRows(connection, ReadLastModified)?.FirstOrDefault()?.TimeLastModified;
|
||||
result.Locations.AddRange(ReadAllRows(connection, ReadLocation));
|
||||
result.Notes.AddRange(ReadAllRows(connection, ReadNote));
|
||||
result.Tags.AddRange(ReadAllRows(connection, ReadTag));
|
||||
result.TagMaps.AddRange(ReadAllRows(connection, ReadTagMap));
|
||||
result.BlockRanges.AddRange(ReadAllRows(connection, ReadBlockRange));
|
||||
result.Bookmarks.AddRange(ReadAllRows(connection, ReadBookmark));
|
||||
result.UserMarks.AddRange(ReadAllRows(connection, ReadUserMark));
|
||||
result.InputFields.AddRange(ReadAllRows(connection, ReadInputField));
|
||||
result.InitBlank();
|
||||
|
||||
// ensure bookmarks appear in similar order to original.
|
||||
result.Bookmarks.Sort((bookmark1, bookmark2) => bookmark1.Slot.CompareTo(bookmark2.Slot));
|
||||
}
|
||||
result.LastModified.TimeLastModified = ReadAllRows(connection, ReadLastModified).FirstOrDefault()?.TimeLastModified;
|
||||
result.Locations.AddRange(ReadAllRows(connection, ReadLocation));
|
||||
result.Notes.AddRange(ReadAllRows(connection, ReadNote));
|
||||
result.Tags.AddRange(ReadAllRows(connection, ReadTag));
|
||||
result.TagMaps.AddRange(ReadAllRows(connection, ReadTagMap));
|
||||
result.BlockRanges.AddRange(ReadAllRows(connection, ReadBlockRange));
|
||||
result.Bookmarks.AddRange(ReadAllRows(connection, ReadBookmark));
|
||||
result.UserMarks.AddRange(ReadAllRows(connection, ReadUserMark));
|
||||
result.InputFields.AddRange(ReadAllRows(connection, ReadInputField));
|
||||
|
||||
// ensure bookmarks appear in similar order to original.
|
||||
result.Bookmarks.Sort((bookmark1, bookmark2) => bookmark1.Slot.CompareTo(bookmark2.Slot));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -87,26 +85,25 @@
|
||||
SqliteConnection connection,
|
||||
Func<SqliteDataReader, TRowType> readRowFunction)
|
||||
{
|
||||
using (var cmd = connection.CreateCommand())
|
||||
using var cmd = connection.CreateCommand();
|
||||
|
||||
var result = new List<TRowType>();
|
||||
var tableName = typeof(TRowType).Name;
|
||||
|
||||
cmd.CommandText = $"select * from {tableName}";
|
||||
Log.Logger.Debug($"SQL: {cmd.CommandText}");
|
||||
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
var result = new List<TRowType>();
|
||||
var tableName = typeof(TRowType).Name;
|
||||
|
||||
cmd.CommandText = $"select * from {tableName}";
|
||||
Log.Logger.Debug($"SQL: {cmd.CommandText}");
|
||||
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
while (reader.Read())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
result.Add(readRowFunction(reader));
|
||||
}
|
||||
result.Add(readRowFunction(reader));
|
||||
}
|
||||
|
||||
Log.Logger.Debug($"SQL result set count: {result.Count}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Log.Logger.Debug($"SQL result set count: {result.Count}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string ReadString(SqliteDataReader reader, string columnName)
|
||||
@@ -114,7 +111,7 @@
|
||||
return reader[columnName].ToString();
|
||||
}
|
||||
|
||||
private static string ReadNullableString(SqliteDataReader reader, string columnName)
|
||||
private static string? ReadNullableString(SqliteDataReader reader, string columnName)
|
||||
{
|
||||
var value = reader[columnName];
|
||||
return value == DBNull.Value ? null : value.ToString();
|
||||
@@ -159,35 +156,32 @@
|
||||
|
||||
private static void VacuumDatabase(SqliteConnection connection)
|
||||
{
|
||||
using (var command = connection.CreateCommand())
|
||||
{
|
||||
command.CommandText = "vacuum;";
|
||||
Log.Logger.Debug($"SQL: {command.CommandText}");
|
||||
using var command = connection.CreateCommand();
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
command.CommandText = "vacuum;";
|
||||
Log.Logger.Debug($"SQL: {command.CommandText}");
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
private static void UpdateLastModified(SqliteConnection connection)
|
||||
{
|
||||
using (var command = connection.CreateCommand())
|
||||
{
|
||||
command.CommandText = "delete from LastModified; insert into LastModified default values";
|
||||
Log.Logger.Debug($"SQL: {command.CommandText}");
|
||||
using var command = connection.CreateCommand();
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
command.CommandText = "delete from LastModified; insert into LastModified default values";
|
||||
Log.Logger.Debug($"SQL: {command.CommandText}");
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
private static void ClearTable(SqliteConnection connection, string tableName)
|
||||
{
|
||||
using (var command = connection.CreateCommand())
|
||||
{
|
||||
command.CommandText = $"delete from {tableName}";
|
||||
Log.Logger.Debug($"SQL: {command.CommandText}");
|
||||
using var command = connection.CreateCommand();
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
command.CommandText = $"delete from {tableName}";
|
||||
Log.Logger.Debug($"SQL: {command.CommandText}");
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
private static void PopulateTable<TRowType>(SqliteConnection connection, List<TRowType> rows)
|
||||
@@ -202,6 +196,11 @@
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
if (row == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
using var cmd = connection.CreateCommand();
|
||||
cmd.CommandText = $"insert into {tableName} ({columnNamesCsv}) values ({paramNamesCsv})";
|
||||
AddPopulateTableParams(cmd, columnNames, paramNames, row);
|
||||
@@ -220,7 +219,7 @@
|
||||
{
|
||||
for (int n = 0; n < columnNames.Count; ++n)
|
||||
{
|
||||
var value = row.GetType().GetProperty(columnNames[n])?.GetValue(row) ?? DBNull.Value;
|
||||
var value = row!.GetType().GetProperty(columnNames[n])?.GetValue(row) ?? DBNull.Value;
|
||||
cmd.Parameters.AddWithValue(paramNames[n], value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/// <summary>
|
||||
/// Used by the <see cref="Merger"/> to map old and new id values./>
|
||||
/// </summary>
|
||||
internal class IdTranslator
|
||||
internal sealed class IdTranslator
|
||||
{
|
||||
private readonly Dictionary<int, int> _ids;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JWLMerge.BackupFileServices.Events;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using Events;
|
||||
using Models.DatabaseModels;
|
||||
using Serilog;
|
||||
|
||||
/// <summary>
|
||||
@@ -25,7 +25,7 @@
|
||||
private int _maxBlockRangeId;
|
||||
private int _maxBookmarkId;
|
||||
|
||||
public event EventHandler<ProgressEventArgs> ProgressEvent;
|
||||
public event EventHandler<ProgressEventArgs>? ProgressEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Merges the specified databases.
|
||||
@@ -158,7 +158,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
private bool OverlappingBlockRanges(BlockRange blockRange1, BlockRange blockRange2)
|
||||
private static bool OverlappingBlockRanges(BlockRange blockRange1, BlockRange blockRange2)
|
||||
{
|
||||
if (blockRange1.StartToken == blockRange2.StartToken &&
|
||||
blockRange1.EndToken == blockRange2.EndToken)
|
||||
@@ -192,7 +192,7 @@
|
||||
|
||||
var tagId = _translatedTagIds.GetTranslatedId(sourceTagMap.TagId);
|
||||
var id = 0;
|
||||
TagMap existingTagMap = null;
|
||||
TagMap? existingTagMap = null;
|
||||
|
||||
if (sourceTagMap.LocationId != null)
|
||||
{
|
||||
@@ -202,8 +202,11 @@
|
||||
{
|
||||
// must add location...
|
||||
var location = source.FindLocation(sourceTagMap.LocationId.Value);
|
||||
InsertLocation(location, destination);
|
||||
id = _translatedLocationIds.GetTranslatedId(sourceTagMap.LocationId.Value);
|
||||
if (location != null)
|
||||
{
|
||||
InsertLocation(location, destination);
|
||||
id = _translatedLocationIds.GetTranslatedId(sourceTagMap.LocationId.Value);
|
||||
}
|
||||
}
|
||||
|
||||
existingTagMap = destination.FindTagMapForLocation(tagId, id);
|
||||
@@ -224,7 +227,7 @@
|
||||
NormaliseTagMapPositions(destination.TagMaps);
|
||||
}
|
||||
|
||||
private void NormaliseTagMapPositions(List<TagMap> entries)
|
||||
private static void NormaliseTagMapPositions(List<TagMap> entries)
|
||||
{
|
||||
// there is unique constraint on TagId, Position
|
||||
var tmpStorage = entries.GroupBy(x => x.TagId).ToDictionary(x => x.Key);
|
||||
@@ -273,8 +276,11 @@
|
||||
{
|
||||
var referencedLocation = sourceUserMark.LocationId;
|
||||
var location = source.FindLocation(referencedLocation);
|
||||
if (location != null)
|
||||
{
|
||||
InsertLocation(location, destination);
|
||||
}
|
||||
|
||||
InsertLocation(location, destination);
|
||||
InsertUserMark(sourceUserMark, destination);
|
||||
}
|
||||
}
|
||||
@@ -300,7 +306,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
private void InsertInputField(InputField inputField, int locationId, Database destination)
|
||||
private static void InsertInputField(InputField inputField, int locationId, Database destination)
|
||||
{
|
||||
var inputFldClone = inputField.Clone();
|
||||
inputFldClone.LocationId = locationId;
|
||||
@@ -438,8 +444,10 @@
|
||||
{
|
||||
var referencedLocation = note.LocationId.Value;
|
||||
var location = source.FindLocation(referencedLocation);
|
||||
|
||||
InsertLocation(location, destination);
|
||||
if (location != null)
|
||||
{
|
||||
InsertLocation(location, destination);
|
||||
}
|
||||
}
|
||||
|
||||
InsertNote(note, destination);
|
||||
@@ -447,7 +455,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateNote(Note source, Note destination)
|
||||
private static void UpdateNote(Note source, Note destination)
|
||||
{
|
||||
destination.Title = source.Title;
|
||||
destination.Content = source.Content;
|
||||
@@ -456,7 +464,7 @@
|
||||
|
||||
private void OnProgressEvent(string message)
|
||||
{
|
||||
ProgressEvent?.Invoke(this, new ProgressEventArgs { Message = message });
|
||||
ProgressEvent?.Invoke(this, new ProgressEventArgs(message));
|
||||
}
|
||||
|
||||
private void ProgressMessage(string logMessage)
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JWLMerge.BackupFileServices.Models;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using Models;
|
||||
using Models.DatabaseModels;
|
||||
|
||||
internal sealed class NotesImporter
|
||||
{
|
||||
@@ -74,7 +74,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!existingNote.Content.Equals(note.NoteContent))
|
||||
if (NoteIsDifferent(existingNote, note.NoteContent))
|
||||
{
|
||||
// need to update the note.
|
||||
result.BibleNotesUpdated++;
|
||||
@@ -92,6 +92,16 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool NoteIsDifferent(Note existingNote, string? newNote)
|
||||
{
|
||||
if (string.IsNullOrEmpty(existingNote.Content))
|
||||
{
|
||||
return !string.IsNullOrEmpty(newNote);
|
||||
}
|
||||
|
||||
return !existingNote.Content.Equals(newNote);
|
||||
}
|
||||
|
||||
private void InsertNote(BibleNote note)
|
||||
{
|
||||
var book = note.BookChapterAndVerse.BookNumber;
|
||||
@@ -100,7 +110,7 @@
|
||||
var location = _targetDatabase.FindLocationByBibleChapter(_bibleKeySymbol, book, chapter) ??
|
||||
InsertLocation(book, chapter);
|
||||
|
||||
UserMark userMark = null;
|
||||
UserMark? userMark = null;
|
||||
if (note.StartTokenInVerse != null && note.EndTokenInVerse != null)
|
||||
{
|
||||
// the note should be associated with some
|
||||
@@ -185,7 +195,7 @@
|
||||
return userMark;
|
||||
}
|
||||
|
||||
private UserMark FindExistingUserMark(int locationId, int startToken, int endToken)
|
||||
private UserMark? FindExistingUserMark(int locationId, int startToken, int endToken)
|
||||
{
|
||||
var userMarksForLocation = _targetDatabase.FindUserMarks(locationId);
|
||||
if (userMarksForLocation == null)
|
||||
@@ -228,7 +238,7 @@
|
||||
return location;
|
||||
}
|
||||
|
||||
private Note FindExistingNote(Database database, BibleNote note)
|
||||
private static Note? FindExistingNote(Database database, BibleNote note)
|
||||
{
|
||||
var existingVerseNotes = database.FindNotes(note.BookChapterAndVerse);
|
||||
return existingVerseNotes?.FirstOrDefault(verseNote => verseNote.Title == note.NoteTitle);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using System.Text;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
internal class RedactService
|
||||
internal sealed class RedactService
|
||||
{
|
||||
private readonly Lazy<string[]> _loremIpsumLines;
|
||||
private readonly Random _random = new Random();
|
||||
@@ -32,7 +32,7 @@
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
sb.Append(" ");
|
||||
sb.Append(' ');
|
||||
}
|
||||
|
||||
sb.Append(GetRandomSentence());
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JWLMerge.BackupFileServices.Events;
|
||||
using JWLMerge.BackupFileServices.Models;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using JWLMerge.ExcelServices;
|
||||
using Events;
|
||||
using Models;
|
||||
using Models.DatabaseModels;
|
||||
using ExcelServices;
|
||||
|
||||
/// <summary>
|
||||
/// The BackupFileService interface.
|
||||
@@ -71,7 +71,7 @@
|
||||
/// <returns>Number of notes removed.</returns>
|
||||
int RemoveNotesByTag(
|
||||
BackupFile backup,
|
||||
int[] tagIds,
|
||||
int[]? tagIds,
|
||||
bool removeUntaggedNotes,
|
||||
bool removeAssociatedUnderlining,
|
||||
bool removeAssociatedTags);
|
||||
@@ -83,7 +83,7 @@
|
||||
/// <param name="colorIndexes">The color indexes to target.</param>
|
||||
/// <param name="removeAssociatedNotes">Whether associated notes should also be removed.</param>
|
||||
/// <returns>Number of underlined items removed.</returns>
|
||||
int RemoveUnderliningByColour(BackupFile backup, int[] colorIndexes, bool removeAssociatedNotes);
|
||||
int RemoveUnderliningByColour(BackupFile backup, int[]? colorIndexes, bool removeAssociatedNotes);
|
||||
|
||||
/// <summary>
|
||||
/// Removes underlining by publication and colour.
|
||||
@@ -99,7 +99,7 @@
|
||||
BackupFile backup,
|
||||
int colorIndex,
|
||||
bool anyColor,
|
||||
string publicationSymbol,
|
||||
string? publicationSymbol,
|
||||
bool anyPublication,
|
||||
bool removeAssociatedNotes);
|
||||
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="5.0.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JWLMerge.BackupFileServices.Models.ManifestFile;
|
||||
using ManifestFile;
|
||||
|
||||
/// <summary>
|
||||
/// The Backup file.
|
||||
@@ -10,15 +10,15 @@
|
||||
/// <remarks>We implement INotifyPropertyChanged to prevent the common "WPF binding leak".</remarks>
|
||||
public sealed class BackupFile : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public Manifest Manifest { get; set; }
|
||||
public Manifest Manifest { get; set; } = null!;
|
||||
|
||||
public DatabaseModels.Database Database { get; set; }
|
||||
public DatabaseModels.Database Database { get; set; } = null!;
|
||||
|
||||
#pragma warning disable IDE0051 // Remove unused private members
|
||||
#pragma warning disable S1144 // Remove unused private members
|
||||
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
#pragma warning restore S1144 // Remove unused private members
|
||||
#pragma warning restore IDE0051 // Remove unused private members
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
using System;
|
||||
|
||||
public struct BibleBookChapterAndVerse : IEquatable<BibleBookChapterAndVerse>
|
||||
public readonly struct BibleBookChapterAndVerse : IEquatable<BibleBookChapterAndVerse>
|
||||
{
|
||||
public BibleBookChapterAndVerse(int bookNum, int chapterNum, int verseNum)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace JWLMerge.BackupFileServices.Models
|
||||
{
|
||||
internal class BibleNotesVerseSpecification
|
||||
internal sealed class BibleNotesVerseSpecification
|
||||
{
|
||||
public int BookNumber { get; set; }
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
|
||||
public int ColourIndex { get; set; }
|
||||
|
||||
public string NoteTitle { get; set; }
|
||||
public string? NoteTitle { get; set; }
|
||||
|
||||
public string NoteContent { get; set; }
|
||||
public string? NoteContent { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,12 +28,12 @@
|
||||
/// <summary>
|
||||
/// The title text.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
public string Title { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// A snippet of the bookmarked text (can be null)
|
||||
/// </summary>
|
||||
public string Snippet { get; set; }
|
||||
public string? Snippet { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The block type. Compare Locations.cs > BlockType
|
||||
|
||||
@@ -3,29 +3,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JWLMerge.BackupFileServices.Exceptions;
|
||||
using Exceptions;
|
||||
using Serilog;
|
||||
|
||||
public class Database
|
||||
{
|
||||
private readonly Dictionary<int, int> _bookmarkSlots = new Dictionary<int, int>();
|
||||
|
||||
private Lazy<Dictionary<string, Note>> _notesGuidIndex;
|
||||
private Lazy<Dictionary<int, Note>> _notesIdIndex;
|
||||
private Lazy<Dictionary<int, List<InputField>>> _inputFieldsIndex;
|
||||
private Lazy<Dictionary<BibleBookChapterAndVerse, List<Note>>> _notesVerseIndex;
|
||||
private Lazy<Dictionary<string, UserMark>> _userMarksGuidIndex;
|
||||
private Lazy<Dictionary<int, UserMark>> _userMarksIdIndex;
|
||||
private Lazy<Dictionary<int, List<UserMark>>> _userMarksLocationIdIndex;
|
||||
private Lazy<Dictionary<int, Location>> _locationsIdIndex;
|
||||
private Lazy<Dictionary<string, Location>> _locationsValueIndex;
|
||||
private Lazy<Dictionary<string, Location>> _locationsBibleChapterIndex;
|
||||
private Lazy<Dictionary<TagTypeAndName, Tag>> _tagsNameIndex;
|
||||
private Lazy<Dictionary<int, Tag>> _tagsIdIndex;
|
||||
private Lazy<Dictionary<string, TagMap>> _tagMapNoteIndex;
|
||||
private Lazy<Dictionary<string, TagMap>> _tagMapLocationIndex;
|
||||
private Lazy<Dictionary<int, List<BlockRange>>> _blockRangesUserMarkIdIndex;
|
||||
private Lazy<Dictionary<string, Bookmark>> _bookmarksIndex;
|
||||
private Lazy<Dictionary<string, Note>> _notesGuidIndex = null!;
|
||||
private Lazy<Dictionary<int, Note>> _notesIdIndex = null!;
|
||||
private Lazy<Dictionary<int, List<InputField>>> _inputFieldsIndex = null!;
|
||||
private Lazy<Dictionary<BibleBookChapterAndVerse, List<Note>>> _notesVerseIndex = null!;
|
||||
private Lazy<Dictionary<string, UserMark>> _userMarksGuidIndex = null!;
|
||||
private Lazy<Dictionary<int, UserMark>> _userMarksIdIndex = null!;
|
||||
private Lazy<Dictionary<int, List<UserMark>>> _userMarksLocationIdIndex = null!;
|
||||
private Lazy<Dictionary<int, Location>> _locationsIdIndex = null!;
|
||||
private Lazy<Dictionary<string, Location>> _locationsValueIndex = null!;
|
||||
private Lazy<Dictionary<string, Location>> _locationsBibleChapterIndex = null!;
|
||||
private Lazy<Dictionary<TagTypeAndName, Tag>> _tagsNameIndex = null!;
|
||||
private Lazy<Dictionary<int, Tag>> _tagsIdIndex = null!;
|
||||
private Lazy<Dictionary<string, TagMap>> _tagMapNoteIndex = null!;
|
||||
private Lazy<Dictionary<string, TagMap>> _tagMapLocationIndex = null!;
|
||||
private Lazy<Dictionary<int, List<BlockRange>>> _blockRangesUserMarkIdIndex = null!;
|
||||
private Lazy<Dictionary<string, Bookmark>> _bookmarksIndex = null!;
|
||||
|
||||
public Database()
|
||||
{
|
||||
@@ -99,7 +99,7 @@
|
||||
public void AddBibleNoteAndUpdateIndex(
|
||||
BibleBookChapterAndVerse verseRef,
|
||||
Note value,
|
||||
TagMap tagMap)
|
||||
TagMap? tagMap)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
@@ -226,63 +226,63 @@
|
||||
}
|
||||
}
|
||||
|
||||
public Note FindNote(string noteGuid)
|
||||
public Note? FindNote(string noteGuid)
|
||||
{
|
||||
return _notesGuidIndex.Value.TryGetValue(noteGuid, out var note) ? note : null;
|
||||
}
|
||||
|
||||
public Note FindNote(int noteId)
|
||||
public Note? FindNote(int noteId)
|
||||
{
|
||||
return _notesIdIndex.Value.TryGetValue(noteId, out var note) ? note : null;
|
||||
}
|
||||
|
||||
public IEnumerable<Note> FindNotes(BibleBookChapterAndVerse verseRef)
|
||||
public IEnumerable<Note>? FindNotes(BibleBookChapterAndVerse verseRef)
|
||||
{
|
||||
return _notesVerseIndex.Value.TryGetValue(verseRef, out var notes) ? notes : null;
|
||||
}
|
||||
|
||||
public UserMark FindUserMark(string userMarkGuid)
|
||||
public UserMark? FindUserMark(string userMarkGuid)
|
||||
{
|
||||
return _userMarksGuidIndex.Value.TryGetValue(userMarkGuid, out var userMark) ? userMark : null;
|
||||
}
|
||||
|
||||
public UserMark FindUserMark(int userMarkId)
|
||||
public UserMark? FindUserMark(int userMarkId)
|
||||
{
|
||||
return _userMarksIdIndex.Value.TryGetValue(userMarkId, out var userMark) ? userMark : null;
|
||||
}
|
||||
|
||||
public IEnumerable<UserMark> FindUserMarks(int locationId)
|
||||
public IEnumerable<UserMark>? FindUserMarks(int locationId)
|
||||
{
|
||||
return _userMarksLocationIdIndex.Value.TryGetValue(locationId, out var userMarks) ? userMarks : null;
|
||||
}
|
||||
|
||||
public Tag FindTag(int tagType, string tagName)
|
||||
public Tag? FindTag(int tagType, string tagName)
|
||||
{
|
||||
var key = new TagTypeAndName(tagType, tagName);
|
||||
return _tagsNameIndex.Value.TryGetValue(key, out var tag) ? tag : null;
|
||||
}
|
||||
|
||||
public Tag FindTag(int tagId)
|
||||
public Tag? FindTag(int tagId)
|
||||
{
|
||||
return _tagsIdIndex.Value.TryGetValue(tagId, out var tag) ? tag : null;
|
||||
}
|
||||
|
||||
public TagMap FindTagMapForNote(int tagId, int noteId)
|
||||
public TagMap? FindTagMapForNote(int tagId, int noteId)
|
||||
{
|
||||
return _tagMapNoteIndex.Value.TryGetValue(GetTagMapNoteKey(tagId, noteId), out var tag) ? tag : null;
|
||||
}
|
||||
|
||||
public TagMap FindTagMapForLocation(int tagId, int locationId)
|
||||
public TagMap? FindTagMapForLocation(int tagId, int locationId)
|
||||
{
|
||||
return _tagMapLocationIndex.Value.TryGetValue(GetTagMapLocationKey(tagId, locationId), out var tag) ? tag : null;
|
||||
}
|
||||
|
||||
public Location FindLocation(int locationId)
|
||||
public Location? FindLocation(int locationId)
|
||||
{
|
||||
return _locationsIdIndex.Value.TryGetValue(locationId, out var location) ? location : null;
|
||||
}
|
||||
|
||||
public InputField FindInputField(int locationId, string textTag)
|
||||
public InputField? FindInputField(int locationId, string textTag)
|
||||
{
|
||||
if (!_inputFieldsIndex.Value.TryGetValue(locationId, out var list))
|
||||
{
|
||||
@@ -292,7 +292,7 @@
|
||||
return list.SingleOrDefault(x => x.TextTag.Equals(textTag, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public Location FindLocationByValues(Location locationValues)
|
||||
public Location? FindLocationByValues(Location locationValues)
|
||||
{
|
||||
if (locationValues == null)
|
||||
{
|
||||
@@ -303,18 +303,18 @@
|
||||
return _locationsValueIndex.Value.TryGetValue(key, out var location) ? location : null;
|
||||
}
|
||||
|
||||
public Location FindLocationByBibleChapter(string bibleKeySymbol, int bibleBookNumber, int bibleChapter)
|
||||
public Location? FindLocationByBibleChapter(string bibleKeySymbol, int bibleBookNumber, int bibleChapter)
|
||||
{
|
||||
var key = GetLocationByBibleChapterKey(bibleBookNumber, bibleChapter, bibleKeySymbol);
|
||||
return _locationsBibleChapterIndex.Value.TryGetValue(key, out var location) ? location : null;
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<BlockRange> FindBlockRanges(int userMarkId)
|
||||
public IReadOnlyCollection<BlockRange>? FindBlockRanges(int userMarkId)
|
||||
{
|
||||
return _blockRangesUserMarkIdIndex.Value.TryGetValue(userMarkId, out var ranges) ? ranges : null;
|
||||
}
|
||||
|
||||
public Bookmark FindBookmark(int locationId, int publicationLocationId)
|
||||
public Bookmark? FindBookmark(int locationId, int publicationLocationId)
|
||||
{
|
||||
string key = GetBookmarkKey(locationId, publicationLocationId);
|
||||
return _bookmarksIndex.Value.TryGetValue(key, out var bookmark) ? bookmark : null;
|
||||
@@ -483,19 +483,19 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
private string GetBookmarkKey(int locationId, int publicationLocationId)
|
||||
private static string GetBookmarkKey(int locationId, int publicationLocationId)
|
||||
{
|
||||
return $"{locationId}-{publicationLocationId}";
|
||||
}
|
||||
|
||||
private string GetLocationByValueKey(Location location)
|
||||
private static string GetLocationByValueKey(Location location)
|
||||
{
|
||||
return $"{location.KeySymbol}|{location.IssueTagNumber}|{location.MepsLanguage}|{location.Type}|{location.BookNumber ?? -1}|{location.ChapterNumber ?? -1}|{location.DocumentId ?? -1}|{location.Track ?? -1}";
|
||||
}
|
||||
|
||||
private string GetLocationByBibleChapterKey(int bibleBookNumber, int chapterNumber, string bibleKeySymbol)
|
||||
private static string GetLocationByBibleChapterKey(int bibleBookNumber, int chapterNumber, string? bibleKeySymbol)
|
||||
{
|
||||
return $"{bibleBookNumber}-{chapterNumber}-{bibleKeySymbol}";
|
||||
return $"{bibleBookNumber}-{chapterNumber}-{bibleKeySymbol ?? string.Empty}";
|
||||
}
|
||||
|
||||
private Dictionary<string, Bookmark> BookmarkIndexValueFactory()
|
||||
@@ -524,12 +524,12 @@
|
||||
return Tags.ToDictionary(tag => tag.TagId);
|
||||
}
|
||||
|
||||
private string GetTagMapNoteKey(int tagId, int noteId)
|
||||
private static string GetTagMapNoteKey(int tagId, int noteId)
|
||||
{
|
||||
return $"{tagId}-{noteId}";
|
||||
}
|
||||
|
||||
private string GetTagMapLocationKey(int tagId, int locationId)
|
||||
private static string GetTagMapLocationKey(int tagId, int locationId)
|
||||
{
|
||||
return $"{tagId}-{locationId}";
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
{
|
||||
public int LocationId { get; set; }
|
||||
|
||||
public string TextTag { get; set; }
|
||||
public string TextTag { get; set; } = null!;
|
||||
|
||||
public string Value { get; set; }
|
||||
public string Value { get; set; } = null!;
|
||||
|
||||
public InputField Clone()
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
/// Time stamp when the database was last modified.
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "LastModified")]
|
||||
public string TimeLastModified { get; set; }
|
||||
public string? TimeLastModified { get; set; }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
/// <summary>
|
||||
/// The JWL publication key symbol (nullable).
|
||||
/// </summary>
|
||||
public string KeySymbol { get; set; }
|
||||
public string? KeySymbol { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The MEPS identifier for the publication language.
|
||||
@@ -57,7 +57,7 @@
|
||||
/// <summary>
|
||||
/// A location title (nullable).
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
public string? Title { get; set; }
|
||||
|
||||
public Location Clone()
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
/// <summary>
|
||||
/// A Guid (that should assist in merging notes).
|
||||
/// </summary>
|
||||
public string Guid { get; set; }
|
||||
public string Guid { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The user mark identifier (if the note is associated with user-highlighting).
|
||||
@@ -28,17 +28,17 @@
|
||||
/// <summary>
|
||||
/// The user-defined note title.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
public string? Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user-defined note content.
|
||||
/// </summary>
|
||||
public string Content { get; set; }
|
||||
public string? Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time stamp when the note was last edited. ISO 8601 format.
|
||||
/// </summary>
|
||||
public string LastModified { get; set; }
|
||||
public string? LastModified { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of block associated with the note.
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
/// <summary>
|
||||
/// The name of the tag.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The optional image file name.
|
||||
/// </summary>
|
||||
/// <remarks>Added in db ver 7 April 2020.</remarks>
|
||||
public string ImageFileName { get; set; }
|
||||
public string? ImageFileName { get; set; }
|
||||
|
||||
public Tag Clone()
|
||||
{
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
/// <summary>
|
||||
/// Playlist Item Id.
|
||||
/// </summary>
|
||||
/// <remarks>added in in db v7, Apr 2020</remarks>
|
||||
/// <remarks>added in db v7, Apr 2020</remarks>
|
||||
public int? PlaylistItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Location Id.
|
||||
/// </summary>
|
||||
/// <remarks>added in in db v7, Apr 2020</remarks>
|
||||
/// <remarks>added in db v7, Apr 2020</remarks>
|
||||
public int? LocationId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Note Id.
|
||||
/// </summary>
|
||||
/// <remarks>added in in db v7, Apr 2020.</remarks>
|
||||
/// <remarks>added in db v7, Apr 2020.</remarks>
|
||||
public int? NoteId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
/// <summary>
|
||||
/// The guid. Useful in merging!
|
||||
/// </summary>
|
||||
public string UserMarkGuid { get; set; }
|
||||
public string UserMarkGuid { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The highlight version. Semantics unknown!
|
||||
|
||||
@@ -9,17 +9,17 @@
|
||||
/// <remarks>We implement INotifyPropertyChanged to prevent the common "WPF binding leak".</remarks>
|
||||
public sealed class Manifest : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the backup file (without the "jwlibrary" extension).
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The local creation date in the form "YYYY-MM-DD"
|
||||
/// </summary>
|
||||
public string CreationDate { get; set; }
|
||||
public string CreationDate { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The manifest schema version.
|
||||
@@ -34,7 +34,7 @@
|
||||
/// <summary>
|
||||
/// Details of the backup database.
|
||||
/// </summary>
|
||||
public UserDataBackup UserDataBackup { get; set; }
|
||||
public UserDataBackup UserDataBackup { get; set; } = null!;
|
||||
|
||||
public Manifest Clone()
|
||||
{
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
#pragma warning disable IDE0051 // Remove unused private members
|
||||
#pragma warning disable S1144 // Remove unused private members
|
||||
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
#pragma warning restore S1144 // Remove unused private members
|
||||
#pragma warning restore IDE0051 // Remove unused private members
|
||||
{
|
||||
|
||||
@@ -10,28 +10,28 @@
|
||||
/// <remarks>We implement INotifyPropertyChanged to prevent the common "WPF binding leak".</remarks>
|
||||
public sealed class UserDataBackup : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The last modified date of the database in ISO 8601, e.g. "2018-01-17T14:37:27+00:00"
|
||||
/// Corresponds to the value in the LastModifiedDate table.
|
||||
/// </summary>
|
||||
public string LastModifiedDate { get; set; }
|
||||
public string LastModifiedDate { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the source device (e.g. the name of the PC).
|
||||
/// </summary>
|
||||
public string DeviceName { get; set; }
|
||||
public string DeviceName { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The database name (always "userData.db"?)
|
||||
/// </summary>
|
||||
public string DatabaseName { get; set; }
|
||||
public string DatabaseName { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// A sha256 hash of the associated database file.
|
||||
/// </summary>
|
||||
public string Hash { get; set; }
|
||||
public string Hash { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The database schema version.
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
#pragma warning disable IDE0051 // Remove unused private members
|
||||
#pragma warning disable S1144 // Remove unused private members
|
||||
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
#pragma warning restore S1144 // Remove unused private members
|
||||
#pragma warning restore IDE0051 // Remove unused private members
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace JWLMerge.BackupFileServices.Models
|
||||
{
|
||||
internal class NoteTitleAndContent
|
||||
internal sealed class NoteTitleAndContent
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string? Title { get; set; }
|
||||
|
||||
public string Content { get; set; }
|
||||
public string? Content { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace JWLMerge.BackupFileServices.Models
|
||||
{
|
||||
internal class TagTypeAndName
|
||||
internal sealed class TagTypeAndName
|
||||
{
|
||||
public TagTypeAndName(int type, string name)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,11 @@ namespace JWLMerge.ExcelServices
|
||||
private const string WorkbookName = "Notes";
|
||||
|
||||
// returns the last row written
|
||||
public int AppendToBibleNotesFile(string excelFilePath, IReadOnlyCollection<BibleNote> notes, int startRow, string backupFilePath)
|
||||
public int AppendToBibleNotesFile(
|
||||
string excelFilePath,
|
||||
IReadOnlyCollection<BibleNote>? notes,
|
||||
int startRow,
|
||||
string backupFilePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(excelFilePath))
|
||||
{
|
||||
@@ -30,73 +34,71 @@ namespace JWLMerge.ExcelServices
|
||||
{
|
||||
return startRow;
|
||||
}
|
||||
|
||||
using (var workbook = new XLWorkbook(excelFilePath))
|
||||
|
||||
using var workbook = new XLWorkbook(excelFilePath);
|
||||
|
||||
if (!workbook.Worksheets.TryGetWorksheet(WorkbookName, out var worksheet))
|
||||
{
|
||||
if (!workbook.Worksheets.TryGetWorksheet(WorkbookName, out var worksheet))
|
||||
{
|
||||
throw new ExcelServicesException("Could not find worksheet!");
|
||||
}
|
||||
|
||||
var row = startRow;
|
||||
foreach (var note in notes)
|
||||
{
|
||||
SetCellStringValue(worksheet, row, 1, note.PubSymbol);
|
||||
SetCellStringValue(worksheet, row, 2, note.BookName);
|
||||
SetCellIntegerValue(worksheet, row, 3, note.BookNumber);
|
||||
SetCellIntegerValue(worksheet, row, 4, note.ChapterNumber);
|
||||
SetCellIntegerValue(worksheet, row, 5, note.VerseNumber);
|
||||
SetCellStringValue(worksheet, row, 6, note.ChapterAndVerseString);
|
||||
SetCellStringValue(worksheet, row, 7, note.BookNameChapterAndVerseString);
|
||||
SetCellIntegerValue(worksheet, row, 8, note.ColorCode);
|
||||
SetCellStringValue(worksheet, row, 9, note.TagsCsv);
|
||||
SetCellStringValue(worksheet, row, 10, note.NoteTitle);
|
||||
SetCellStringValue(worksheet, row, 11, note.NoteContent);
|
||||
|
||||
++row;
|
||||
}
|
||||
|
||||
workbook.Save();
|
||||
|
||||
return row;
|
||||
throw new ExcelServicesException("Could not find worksheet!");
|
||||
}
|
||||
|
||||
var row = startRow;
|
||||
foreach (var note in notes)
|
||||
{
|
||||
SetCellStringValue(worksheet, row, 1, note.PubSymbol);
|
||||
SetCellStringValue(worksheet, row, 2, note.BookName);
|
||||
SetCellIntegerValue(worksheet, row, 3, note.BookNumber);
|
||||
SetCellIntegerValue(worksheet, row, 4, note.ChapterNumber);
|
||||
SetCellIntegerValue(worksheet, row, 5, note.VerseNumber);
|
||||
SetCellStringValue(worksheet, row, 6, note.ChapterAndVerseString);
|
||||
SetCellStringValue(worksheet, row, 7, note.BookNameChapterAndVerseString);
|
||||
SetCellIntegerValue(worksheet, row, 8, note.ColorCode);
|
||||
SetCellStringValue(worksheet, row, 9, note.TagsCsv);
|
||||
SetCellStringValue(worksheet, row, 10, note.NoteTitle);
|
||||
SetCellStringValue(worksheet, row, 11, note.NoteContent);
|
||||
|
||||
++row;
|
||||
}
|
||||
|
||||
workbook.Save();
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
private void SetCellStringValue(IXLWorksheet worksheet, int row, int col, string value)
|
||||
private static void SetCellStringValue(IXLWorksheet worksheet, int row, int col, string? value)
|
||||
{
|
||||
worksheet.Cell(row, col).DataType = XLDataType.Text;
|
||||
worksheet.Cell(row, col).SetValue(value);
|
||||
worksheet.Cell(row, col).SetValue(value ?? string.Empty);
|
||||
}
|
||||
|
||||
private void SetCellIntegerValue(IXLWorksheet worksheet, int row, int col, int? value)
|
||||
private static void SetCellIntegerValue(IXLWorksheet worksheet, int row, int col, int? value)
|
||||
{
|
||||
worksheet.Cell(row, col).DataType = XLDataType.Number;
|
||||
worksheet.Cell(row, col).SetValue(value);
|
||||
}
|
||||
|
||||
private int GenerateHeader(string excelFilePath, string backupFilePath)
|
||||
private static int GenerateHeader(string excelFilePath, string backupFilePath)
|
||||
{
|
||||
using (var workbook = new XLWorkbook())
|
||||
{
|
||||
var worksheet = workbook.Worksheets.Add(WorkbookName);
|
||||
worksheet.Cell("A1").Value = "Bible Notes Extracted from JWL Backup File";
|
||||
worksheet.Cell("A2").Value = $"Backup file: {backupFilePath}";
|
||||
worksheet.Cell("A3").Value = $"Exported: {DateTime.Now.ToShortDateString()}";
|
||||
using var workbook = new XLWorkbook();
|
||||
|
||||
worksheet.Cell("A5").Value = "Symbol";
|
||||
worksheet.Cell("B5").Value = "Book";
|
||||
worksheet.Cell("C5").Value = "BookNumber";
|
||||
worksheet.Cell("D5").Value = "Chapter";
|
||||
worksheet.Cell("E5").Value = "Verse";
|
||||
worksheet.Cell("F5").Value = "ChapterAndVerse";
|
||||
worksheet.Cell("G5").Value = "FullRef";
|
||||
worksheet.Cell("H5").Value = "Color";
|
||||
worksheet.Cell("I5").Value = "Tags";
|
||||
worksheet.Cell("J5").Value = "Title";
|
||||
worksheet.Cell("K5").Value = "Content";
|
||||
var worksheet = workbook.Worksheets.Add(WorkbookName);
|
||||
worksheet.Cell("A1").Value = "Bible Notes Extracted from JWL Backup File";
|
||||
worksheet.Cell("A2").Value = $"Backup file: {backupFilePath}";
|
||||
worksheet.Cell("A3").Value = $"Exported: {DateTime.Now.ToShortDateString()}";
|
||||
|
||||
workbook.SaveAs(excelFilePath);
|
||||
}
|
||||
worksheet.Cell("A5").Value = "Symbol";
|
||||
worksheet.Cell("B5").Value = "Book";
|
||||
worksheet.Cell("C5").Value = "BookNumber";
|
||||
worksheet.Cell("D5").Value = "Chapter";
|
||||
worksheet.Cell("E5").Value = "Verse";
|
||||
worksheet.Cell("F5").Value = "ChapterAndVerse";
|
||||
worksheet.Cell("G5").Value = "FullRef";
|
||||
worksheet.Cell("H5").Value = "Color";
|
||||
worksheet.Cell("I5").Value = "Tags";
|
||||
worksheet.Cell("J5").Value = "Title";
|
||||
worksheet.Cell("K5").Value = "Content";
|
||||
|
||||
workbook.SaveAs(excelFilePath);
|
||||
|
||||
// return last row used.
|
||||
return 4;
|
||||
|
||||
@@ -5,6 +5,10 @@ namespace JWLMerge.ExcelServices
|
||||
{
|
||||
public interface IExcelService
|
||||
{
|
||||
int AppendToBibleNotesFile(string excelFilePath, IReadOnlyCollection<BibleNote> notes, int startRow, string backupFilePath);
|
||||
int AppendToBibleNotesFile(
|
||||
string excelFilePath,
|
||||
IReadOnlyCollection<BibleNote>? notes,
|
||||
int startRow,
|
||||
string backupFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,8 @@
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -2,23 +2,29 @@
|
||||
{
|
||||
public class BibleNote
|
||||
{
|
||||
public int BookNumber { get; set; }
|
||||
public BibleNote(int bookNumber, string bookName)
|
||||
{
|
||||
BookNumber = bookNumber;
|
||||
BookName = bookName;
|
||||
}
|
||||
|
||||
public string BookName { get; set; }
|
||||
public int BookNumber { get; }
|
||||
|
||||
public string BookName { get; }
|
||||
|
||||
public int? ChapterNumber { get; set; }
|
||||
|
||||
public int? VerseNumber { get; set; }
|
||||
|
||||
public string NoteTitle { get; set; }
|
||||
public string? NoteTitle { get; set; }
|
||||
|
||||
public string NoteContent { get; set; }
|
||||
public string? NoteContent { get; set; }
|
||||
|
||||
public string TagsCsv { get; set; }
|
||||
public string? TagsCsv { get; set; }
|
||||
|
||||
public int? ColorCode { get; set; }
|
||||
|
||||
public string PubSymbol { get; set; }
|
||||
public string? PubSymbol { get; set; }
|
||||
|
||||
public string ChapterAndVerseString
|
||||
{
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
|
||||
|
||||
@@ -2,24 +2,24 @@
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JWLMerge.BackupFileServices.Models;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using JWLMerge.BackupFileServices.Models.ManifestFile;
|
||||
using BackupFileServices.Models;
|
||||
using BackupFileServices.Models.DatabaseModels;
|
||||
using BackupFileServices.Models.ManifestFile;
|
||||
|
||||
public class TestBase
|
||||
{
|
||||
private readonly Random _random = new Random();
|
||||
private readonly Random _random = new();
|
||||
|
||||
protected BackupFile CreateMockBackup(int numRecords = 100)
|
||||
{
|
||||
return new BackupFile
|
||||
return new()
|
||||
{
|
||||
Manifest = CreateMockManifest(),
|
||||
Database = CreateMockDatabase(numRecords),
|
||||
};
|
||||
}
|
||||
|
||||
protected Database CreateMockDatabase(int numRecords)
|
||||
private Database CreateMockDatabase(int numRecords)
|
||||
{
|
||||
var result = new Database();
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Manifest CreateMockManifest()
|
||||
private static Manifest CreateMockManifest()
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
string simpleDateString = $"{now.Year}-{now.Month:D2}-{now.Day:D2}";
|
||||
@@ -55,7 +55,7 @@
|
||||
};
|
||||
}
|
||||
|
||||
private List<BlockRange> CreateMockBlockRanges(int numRecords)
|
||||
private static List<BlockRange> CreateMockBlockRanges(int numRecords)
|
||||
{
|
||||
var result = new List<BlockRange>();
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<UserMark> CreateMockUserMarks(int numRecords)
|
||||
private static List<UserMark> CreateMockUserMarks(int numRecords)
|
||||
{
|
||||
var result = new List<UserMark>();
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace JWLMerge.Tests
|
||||
{
|
||||
using JWLMerge.BackupFileServices.Helpers;
|
||||
using JWLMerge.BackupFileServices.Models;
|
||||
using JWLMerge.BackupFileServices.Models.ManifestFile;
|
||||
using BackupFileServices.Helpers;
|
||||
using BackupFileServices.Models.ManifestFile;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
[TestClass]
|
||||
@@ -11,11 +10,11 @@
|
||||
[TestMethod]
|
||||
public void TestAllClean()
|
||||
{
|
||||
BackupFile file = CreateMockBackup();
|
||||
var file = CreateMockBackup();
|
||||
file.Manifest = new Manifest();
|
||||
|
||||
Cleaner cleaner = new Cleaner(file.Database);
|
||||
int removedRows = cleaner.Clean();
|
||||
var cleaner = new Cleaner(file.Database);
|
||||
var removedRows = cleaner.Clean();
|
||||
|
||||
Assert.AreEqual(0, removedRows);
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JWLMerge.BackupFileServices.Helpers;
|
||||
using JWLMerge.BackupFileServices.Models;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using BackupFileServices.Helpers;
|
||||
using BackupFileServices.Models;
|
||||
using BackupFileServices.Models.DatabaseModels;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
[TestClass]
|
||||
@@ -13,13 +13,14 @@
|
||||
[TestMethod]
|
||||
public void TestImport1()
|
||||
{
|
||||
int numRecords = 100;
|
||||
const int numRecords = 100;
|
||||
|
||||
var file1 = CreateMockBackup(numRecords);
|
||||
var notes = CreateMockBibleNotes().ToArray();
|
||||
var mockImportOptions = new ImportBibleNotesParams();
|
||||
|
||||
int mepsLanguageId = 0;
|
||||
const int mepsLanguageId = 0;
|
||||
|
||||
var importer = new NotesImporter(
|
||||
file1.Database,
|
||||
"nwtsty",
|
||||
@@ -41,17 +42,17 @@
|
||||
Assert.IsTrue(result.BibleNotesUpdated == 0);
|
||||
}
|
||||
|
||||
private IEnumerable<BibleNote> CreateMockBibleNotes()
|
||||
private static IEnumerable<BibleNote> CreateMockBibleNotes()
|
||||
{
|
||||
return new List<BibleNote>
|
||||
{
|
||||
new BibleNote
|
||||
new()
|
||||
{
|
||||
BookChapterAndVerse = new BibleBookChapterAndVerse(1, 1, 1),
|
||||
NoteTitle = "A note 1",
|
||||
NoteContent = "My notes go here",
|
||||
},
|
||||
new BibleNote
|
||||
new()
|
||||
{
|
||||
BookChapterAndVerse = new BibleBookChapterAndVerse(2, 2, 2),
|
||||
NoteTitle = "A note 2",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace JWLMerge.Tests
|
||||
{
|
||||
using System;
|
||||
using JWLMerge.BackupFileServices.Helpers;
|
||||
using BackupFileServices.Helpers;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
[TestClass]
|
||||
@@ -10,13 +9,13 @@
|
||||
[TestMethod]
|
||||
public void TestMerge1()
|
||||
{
|
||||
int numRecords = 100;
|
||||
const int numRecords = 100;
|
||||
|
||||
var file1 = CreateMockBackup(numRecords);
|
||||
var file2 = CreateMockBackup(numRecords);
|
||||
var file3 = CreateMockBackup(numRecords);
|
||||
|
||||
Merger merger = new Merger();
|
||||
var merger = new Merger();
|
||||
var mergedDatabase = merger.Merge(new[] { file1.Database, file2.Database, file3.Database });
|
||||
|
||||
mergedDatabase.CheckValidity();
|
||||
|
||||
11
JWLMerge.sln
11
JWLMerge.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29613.14
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWLMerge.BackupFileServices", "JWLMerge.BackupFileServices\JWLMerge.BackupFileServices.csproj", "{83446629-CDBB-43FF-B628-1B8A3A9603C3}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JWLMerge.BackupFileServices", "JWLMerge.BackupFileServices\JWLMerge.BackupFileServices.csproj", "{83446629-CDBB-43FF-B628-1B8A3A9603C3}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "JWL Database Schemas", "JWL Database Schemas", "{DA7BDF58-CFEA-489C-B18C-944D9986758D}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
@@ -13,21 +13,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "JWL Database Schemas", "JWL
|
||||
Version008.txt = Version008.txt
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWLMergeCLI", "JWLMergeCLI\JWLMergeCLI.csproj", "{2CBBA1C2-72C9-4287-A262-EC1D2A2F6E56}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JWLMergeCLI", "JWLMergeCLI\JWLMergeCLI.csproj", "{2CBBA1C2-72C9-4287-A262-EC1D2A2F6E56}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DA506BB2-675E-47BE-BC54-ED6EAE369243}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
JWLMerge\JWLMerge.ruleset = JWLMerge\JWLMerge.ruleset
|
||||
jwlmergecmdline.png = jwlmergecmdline.png
|
||||
SolutionInfo.cs = SolutionInfo.cs
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWLMerge.Tests", "JWLMerge.Tests\JWLMerge.Tests.csproj", "{07B843A0-2DD7-40C1-AFE9-5F1BCA22393E}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JWLMerge.Tests", "JWLMerge.Tests\JWLMerge.Tests.csproj", "{07B843A0-2DD7-40C1-AFE9-5F1BCA22393E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWLMerge", "JWLMerge\JWLMerge.csproj", "{0D88A466-7C90-4C0B-B8BA-E1F5EC91D4A4}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JWLMerge", "JWLMerge\JWLMerge.csproj", "{0D88A466-7C90-4C0B-B8BA-E1F5EC91D4A4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWLMerge.ExcelServices", "JWLMerge.ExcelServices\JWLMerge.ExcelServices.csproj", "{F8D64B6C-C475-4B5E-8B32-D717380F0F36}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JWLMerge.ExcelServices", "JWLMerge.ExcelServices\JWLMerge.ExcelServices.csproj", "{F8D64B6C-C475-4B5E-8B32-D717380F0F36}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=JWLMerge_002EBackupFileServices_002EAnnotations/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Colossians/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=colour/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=colours/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Favourite/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=favourites/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Fixup/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=initialised/@EntryIndexedValue">True</s:Boolean>
|
||||
@@ -10,4 +12,6 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=lorem/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Meps/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Normalise/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=nwtsty/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=playlists/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Snackbar/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -10,10 +10,10 @@ namespace JWLMerge
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using Serilog;
|
||||
using JWLMerge.BackupFileServices;
|
||||
using JWLMerge.ExcelServices;
|
||||
using JWLMerge.Services;
|
||||
using JWLMerge.ViewModel;
|
||||
using BackupFileServices;
|
||||
using ExcelServices;
|
||||
using Services;
|
||||
using ViewModel;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Toolkit.Mvvm.DependencyInjection;
|
||||
|
||||
@@ -23,15 +23,14 @@ namespace JWLMerge
|
||||
public partial class App : Application
|
||||
{
|
||||
private readonly string _appString = "JWLMergeAC";
|
||||
private Mutex _appMutex;
|
||||
private Mutex? _appMutex;
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
_appMutex?.Dispose();
|
||||
Log.Logger.Information("==== Exit ====");
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
ConfigureServices();
|
||||
@@ -60,7 +59,7 @@ namespace JWLMerge
|
||||
Current.Shutdown();
|
||||
}
|
||||
|
||||
private void ConfigureServices()
|
||||
private static void ConfigureServices()
|
||||
{
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
||||
@@ -88,7 +87,7 @@ namespace JWLMerge
|
||||
Ioc.Default.ConfigureServices(serviceProvider);
|
||||
}
|
||||
|
||||
private bool ForceSoftwareRendering()
|
||||
private static bool ForceSoftwareRendering()
|
||||
{
|
||||
// https://blogs.msdn.microsoft.com/jgoldb/2010/06/22/software-rendering-usage-in-wpf/
|
||||
// renderingTier values:
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
namespace JWLMerge.Helpers
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using JWLMerge.Models;
|
||||
using Models;
|
||||
|
||||
internal static class ColourHelper
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace JWLMerge.Helpers
|
||||
{
|
||||
using System;
|
||||
using JWLMerge.BackupFileServices;
|
||||
using BackupFileServices;
|
||||
using JWLMerge.BackupFileServices.Models.ManifestFile;
|
||||
using JWLMerge.Models;
|
||||
using Models;
|
||||
|
||||
internal static class DesignTimeFileCreation
|
||||
{
|
||||
@@ -20,11 +20,9 @@
|
||||
DeviceName = "MYPC",
|
||||
};
|
||||
|
||||
return new JwLibraryFile
|
||||
{
|
||||
FilePath = "c:\\temp\\myfile.jwlibrary",
|
||||
BackupFile = file,
|
||||
};
|
||||
#pragma warning disable S1075 // URIs should not be hardcoded
|
||||
return new JwLibraryFile("c:\\temp\\myfile.jwlibrary", file);
|
||||
#pragma warning restore S1075 // URIs should not be hardcoded
|
||||
}
|
||||
|
||||
private static string GenerateDateString(DateTime dateTime)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
namespace JWLMerge.Helpers
|
||||
{
|
||||
using JWLMerge.BackupFileServices;
|
||||
using BackupFileServices;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using JWLMerge.Models;
|
||||
using Models;
|
||||
|
||||
internal static class MergePreparation
|
||||
{
|
||||
|
||||
@@ -3,29 +3,24 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using JWLMerge.Models;
|
||||
using Models;
|
||||
|
||||
internal static class PublicationHelper
|
||||
{
|
||||
public static PublicationDef[] GetPublications(List<Location> locations, List<UserMark> userMarks, bool includeAllPublicationsItem)
|
||||
public static PublicationDef[] GetPublications(
|
||||
List<Location> locations, List<UserMark> userMarks, bool includeAllPublicationsItem)
|
||||
{
|
||||
var locationsThatAreMarked = userMarks.Select(x => x.LocationId).ToHashSet();
|
||||
|
||||
var result = locations
|
||||
.Where(x => locationsThatAreMarked.Contains(x.LocationId))
|
||||
.Select(x => x.KeySymbol).Distinct().Select(
|
||||
x => new PublicationDef
|
||||
{
|
||||
KeySymbol = x,
|
||||
}).OrderBy(x => x.KeySymbol).ToList();
|
||||
.Where(x => locationsThatAreMarked.Contains(x.LocationId) && !string.IsNullOrEmpty(x.KeySymbol))
|
||||
.Select(x => x.KeySymbol).Distinct()
|
||||
.Select(x => new PublicationDef(x!, false))
|
||||
.OrderBy(x => x.KeySymbol).ToList();
|
||||
|
||||
if (includeAllPublicationsItem)
|
||||
{
|
||||
result.Insert(0, new PublicationDef
|
||||
{
|
||||
IsAllPublicationsSymbol = true,
|
||||
KeySymbol = "All Publications",
|
||||
});
|
||||
result.Insert(0, new PublicationDef("All Publications", true));
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
|
||||
@@ -8,25 +8,26 @@
|
||||
|
||||
internal static class VersionDetection
|
||||
{
|
||||
public static Version GetLatestReleaseVersion(string latestReleaseUrl)
|
||||
public static Version? GetLatestReleaseVersion(string latestReleaseUrl)
|
||||
{
|
||||
string version = null;
|
||||
string? version = null;
|
||||
|
||||
try
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
#pragma warning disable U2U1025 // Avoid instantiating HttpClient
|
||||
using var client = new HttpClient();
|
||||
#pragma warning restore U2U1025 // Avoid instantiating HttpClient
|
||||
|
||||
var response = client.GetAsync(new Uri(latestReleaseUrl)).Result;
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var response = client.GetAsync(new Uri(latestReleaseUrl)).Result;
|
||||
if (response.IsSuccessStatusCode)
|
||||
var latestVersionUri = response.RequestMessage?.RequestUri;
|
||||
if (latestVersionUri != null)
|
||||
{
|
||||
var latestVersionUri = response.RequestMessage.RequestUri;
|
||||
if (latestVersionUri != null)
|
||||
var segments = latestVersionUri.Segments;
|
||||
if (segments.Any())
|
||||
{
|
||||
var segments = latestVersionUri.Segments;
|
||||
if (segments.Any())
|
||||
{
|
||||
version = segments[segments.Length - 1];
|
||||
}
|
||||
version = segments[segments.Length - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +43,9 @@
|
||||
public static Version GetCurrentVersion()
|
||||
{
|
||||
var ver = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
return new Version($"{ver.Major}.{ver.Minor}.{ver.Build}.{ver.Revision}");
|
||||
return ver != null
|
||||
? new Version($"{ver.Major}.{ver.Minor}.{ver.Build}.{ver.Revision}")
|
||||
: new Version();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
<Compile Include="..\SolutionInfo.cs" Link="Properties\SolutionInfo.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MaterialDesignColors" Version="2.0.1" />
|
||||
<PackageReference Include="MaterialDesignThemes" Version="4.1.0" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using JWLMerge.Messages;
|
||||
using Messages;
|
||||
using Microsoft.Toolkit.Mvvm.Messaging;
|
||||
|
||||
/// <summary>
|
||||
@@ -17,17 +17,17 @@
|
||||
|
||||
private void PanelOnDragOver(object sender, DragEventArgs e)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new DragOverMessage { DragEventArgs = e });
|
||||
WeakReferenceMessenger.Default.Send(new DragOverMessage(e));
|
||||
}
|
||||
|
||||
private void PanelOnDrop(object sender, DragEventArgs e)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new DragDropMessage { DragEventArgs = e });
|
||||
WeakReferenceMessenger.Default.Send(new DragDropMessage(e));
|
||||
}
|
||||
|
||||
private void MainWindowOnClosing(object sender, CancelEventArgs e)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new MainWindowClosingMessage { CancelEventArgs = e });
|
||||
WeakReferenceMessenger.Default.Send(new MainWindowClosingMessage(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,13 @@
|
||||
{
|
||||
using System.Windows;
|
||||
|
||||
internal class DragDropMessage
|
||||
internal sealed class DragDropMessage
|
||||
{
|
||||
public DragEventArgs DragEventArgs { get; set; }
|
||||
public DragDropMessage(DragEventArgs args)
|
||||
{
|
||||
DragEventArgs = args;
|
||||
}
|
||||
|
||||
public DragEventArgs DragEventArgs { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,13 @@
|
||||
{
|
||||
using System.Windows;
|
||||
|
||||
internal class DragOverMessage
|
||||
internal sealed class DragOverMessage
|
||||
{
|
||||
public DragEventArgs DragEventArgs { get; set; }
|
||||
public DragOverMessage(DragEventArgs args)
|
||||
{
|
||||
DragEventArgs = args;
|
||||
}
|
||||
|
||||
public DragEventArgs DragEventArgs { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,13 @@
|
||||
{
|
||||
using System.ComponentModel;
|
||||
|
||||
internal class MainWindowClosingMessage
|
||||
internal sealed class MainWindowClosingMessage
|
||||
{
|
||||
public CancelEventArgs CancelEventArgs { get; set; }
|
||||
public MainWindowClosingMessage(CancelEventArgs args)
|
||||
{
|
||||
CancelEventArgs = args;
|
||||
}
|
||||
|
||||
public CancelEventArgs CancelEventArgs { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
namespace JWLMerge.Models
|
||||
{
|
||||
internal class ColorResult
|
||||
internal sealed class ColorResult
|
||||
{
|
||||
public int[] ColourIndexes { get; set; }
|
||||
public int[]? ColourIndexes { get; set; }
|
||||
|
||||
public bool RemoveNotes { get; set; }
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
using System.Windows.Media;
|
||||
|
||||
internal class ColourDef
|
||||
internal sealed class ColourDef
|
||||
{
|
||||
public ColourDef(int colourIndex, string name, string rgb)
|
||||
{
|
||||
@@ -11,11 +11,11 @@
|
||||
RgbString = rgb;
|
||||
}
|
||||
|
||||
public int ColourIndex { get; set; }
|
||||
public int ColourIndex { get; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Name { get; }
|
||||
|
||||
public string RgbString { get; set; }
|
||||
public string RgbString { get; }
|
||||
|
||||
public Color Color => (Color)ColorConverter.ConvertFromString(RgbString);
|
||||
}
|
||||
|
||||
@@ -3,15 +3,22 @@
|
||||
using Microsoft.Toolkit.Mvvm.ComponentModel;
|
||||
using System.Windows.Media;
|
||||
|
||||
internal class ColourListItem : ObservableObject
|
||||
internal sealed class ColourListItem : ObservableObject
|
||||
{
|
||||
private bool _isChecked;
|
||||
|
||||
public string Name { get; set; }
|
||||
public ColourListItem(string name, int id, Color color)
|
||||
{
|
||||
Name = name;
|
||||
Id = id;
|
||||
Color = color;
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public string Name { get; }
|
||||
|
||||
public Color Color { get; set; }
|
||||
public int Id { get; }
|
||||
|
||||
public Color Color { get; }
|
||||
|
||||
public bool IsChecked
|
||||
{
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
namespace JWLMerge.Models
|
||||
{
|
||||
internal class DataTypeListItem
|
||||
internal sealed class DataTypeListItem
|
||||
{
|
||||
// ReSharper disable once UnusedAutoPropertyAccessor.Global
|
||||
public string Caption { get; set; }
|
||||
public DataTypeListItem(string caption, JwLibraryFileDataTypes dataType)
|
||||
{
|
||||
Caption = caption;
|
||||
DataType = dataType;
|
||||
}
|
||||
|
||||
public JwLibraryFileDataTypes DataType { get; set; }
|
||||
public string Caption { get; }
|
||||
|
||||
public JwLibraryFileDataTypes DataType { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
namespace JWLMerge.Models
|
||||
{
|
||||
internal class FileFormatErrorListItem
|
||||
internal sealed class FileFormatErrorListItem
|
||||
{
|
||||
public string Filename { get; set; }
|
||||
public FileFormatErrorListItem(string filename, string errorMsg)
|
||||
{
|
||||
Filename = filename;
|
||||
ErrorMsg = errorMsg;
|
||||
}
|
||||
|
||||
public string ErrorMsg { get; set; }
|
||||
public string Filename { get; }
|
||||
|
||||
public string ErrorMsg { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
namespace JWLMerge.Models
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace JWLMerge.Models
|
||||
{
|
||||
using System.Text;
|
||||
using JWLMerge.BackupFileServices.Models;
|
||||
using Microsoft.Toolkit.Mvvm.ComponentModel;
|
||||
|
||||
internal class JwLibraryFile : ObservableObject
|
||||
internal sealed class JwLibraryFile : ObservableObject
|
||||
{
|
||||
public JwLibraryFile()
|
||||
public JwLibraryFile(string filePath, BackupFile backupFile)
|
||||
{
|
||||
FilePath = filePath;
|
||||
BackupFile = backupFile;
|
||||
|
||||
MergeParameters = new MergeParameters();
|
||||
MergeParameters.PropertyChanged += MergeParametersPropertyChanged;
|
||||
}
|
||||
|
||||
public string FilePath { get; set; }
|
||||
public string FilePath { get; }
|
||||
|
||||
[DisallowNull]
|
||||
public BackupFile BackupFile { get; set; }
|
||||
|
||||
public MergeParameters MergeParameters { get; }
|
||||
@@ -40,7 +46,7 @@
|
||||
OnPropertyChanged(nameof(TooltipSummaryText));
|
||||
}
|
||||
|
||||
private void MergeParametersPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
private void MergeParametersPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(MergeParameters));
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
namespace JWLMerge.Models
|
||||
{
|
||||
internal class PubColourResult
|
||||
internal sealed class PubColourResult
|
||||
{
|
||||
public string PublicationSymbol { get; set; }
|
||||
public string? PublicationSymbol { get; set; }
|
||||
|
||||
public int ColorIndex { get; set; }
|
||||
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
namespace JWLMerge.Models
|
||||
{
|
||||
internal class PublicationDef
|
||||
internal sealed class PublicationDef
|
||||
{
|
||||
public string KeySymbol { get; set; }
|
||||
public PublicationDef(string keySymbol, bool isAllPubSymbol)
|
||||
{
|
||||
KeySymbol = keySymbol;
|
||||
IsAllPublicationsSymbol = isAllPubSymbol;
|
||||
}
|
||||
|
||||
public bool IsAllPublicationsSymbol { get; set; }
|
||||
public string KeySymbol { get; }
|
||||
|
||||
public bool IsAllPublicationsSymbol { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,19 @@
|
||||
{
|
||||
using Microsoft.Toolkit.Mvvm.ComponentModel;
|
||||
|
||||
internal class TagListItem : ObservableObject
|
||||
internal sealed class TagListItem : ObservableObject
|
||||
{
|
||||
private bool _isChecked;
|
||||
|
||||
public string Name { get; set; }
|
||||
public TagListItem(string name, int id)
|
||||
{
|
||||
Name = name;
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public string Name { get; }
|
||||
|
||||
public int Id { get; }
|
||||
|
||||
public bool IsChecked
|
||||
{
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using JWLMerge.BackupFileServices.Exceptions;
|
||||
using BackupFileServices.Exceptions;
|
||||
using JWLMerge.BackupFileServices.Models;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using JWLMerge.Dialogs;
|
||||
using JWLMerge.Models;
|
||||
using JWLMerge.ViewModel;
|
||||
using Dialogs;
|
||||
using Models;
|
||||
using ViewModel;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
internal class DialogService : IDialogService
|
||||
internal sealed class DialogService : IDialogService
|
||||
{
|
||||
public const int UntaggedItemId = -1;
|
||||
private const string NotTaggedString = "** Not Tagged **";
|
||||
@@ -36,16 +36,13 @@
|
||||
switch (e)
|
||||
{
|
||||
case WrongDatabaseVersionException dbVerEx:
|
||||
dc.Errors.Add(new FileFormatErrorListItem
|
||||
{ Filename = dbVerEx.Filename, ErrorMsg = dbVerEx.Message });
|
||||
dc.Errors.Add(new FileFormatErrorListItem(dbVerEx.Filename ?? "Error", dbVerEx.Message));
|
||||
break;
|
||||
case WrongManifestVersionException mftVerEx:
|
||||
dc.Errors.Add(new FileFormatErrorListItem
|
||||
{ Filename = mftVerEx.Filename, ErrorMsg = mftVerEx.Message });
|
||||
dc.Errors.Add(new FileFormatErrorListItem(mftVerEx.Filename ?? "Error", mftVerEx.Message));
|
||||
break;
|
||||
default:
|
||||
dc.Errors.Add(new FileFormatErrorListItem
|
||||
{ Filename = "Error", ErrorMsg = bex.Message });
|
||||
dc.Errors.Add(new FileFormatErrorListItem("Error", bex.Message));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -53,10 +50,7 @@
|
||||
|
||||
await DialogHost.Show(
|
||||
dialog,
|
||||
(object sender, DialogClosingEventArgs args) =>
|
||||
{
|
||||
_isDialogVisible = false;
|
||||
}).ConfigureAwait(false);
|
||||
(object sender, DialogClosingEventArgs args) => _isDialogVisible = false).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<bool> ShouldRemoveFavouritesAsync()
|
||||
@@ -102,20 +96,12 @@
|
||||
|
||||
if (includeUntaggedNotes)
|
||||
{
|
||||
dc.TagItems.Add(new TagListItem
|
||||
{
|
||||
Id = UntaggedItemId,
|
||||
Name = NotTaggedString,
|
||||
});
|
||||
dc.TagItems.Add(new TagListItem(NotTaggedString, UntaggedItemId));
|
||||
}
|
||||
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
dc.TagItems.Add(new TagListItem
|
||||
{
|
||||
Id = tag.TagId,
|
||||
Name = tag.Name,
|
||||
});
|
||||
dc.TagItems.Add(new TagListItem(tag.Name, tag.TagId));
|
||||
}
|
||||
|
||||
await DialogHost.Show(
|
||||
@@ -147,12 +133,7 @@
|
||||
|
||||
foreach (var c in colours)
|
||||
{
|
||||
dc.ColourItems.Add(new ColourListItem
|
||||
{
|
||||
Id = c.ColourIndex,
|
||||
Name = c.Name,
|
||||
Color = c.Color,
|
||||
});
|
||||
dc.ColourItems.Add(new ColourListItem(c.Name, c.ColourIndex, c.Color));
|
||||
}
|
||||
|
||||
await DialogHost.Show(
|
||||
@@ -167,7 +148,7 @@
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<PubColourResult> GetPubAndColourSelectionForUnderlineRemovalAsync(PublicationDef[] pubs, ColourDef[] colors)
|
||||
public async Task<PubColourResult?> GetPubAndColourSelectionForUnderlineRemovalAsync(PublicationDef[] pubs, ColourDef[] colors)
|
||||
{
|
||||
_isDialogVisible = true;
|
||||
|
||||
@@ -180,12 +161,7 @@
|
||||
|
||||
foreach (var c in colors)
|
||||
{
|
||||
dc.ColourItems.Add(new ColourListItem
|
||||
{
|
||||
Id = c.ColourIndex,
|
||||
Name = c.Name,
|
||||
Color = c.Color,
|
||||
});
|
||||
dc.ColourItems.Add(new ColourListItem(c.Name, c.ColourIndex, c.Color));
|
||||
}
|
||||
|
||||
foreach (var p in pubs)
|
||||
@@ -201,7 +177,7 @@
|
||||
return dc.Result;
|
||||
}
|
||||
|
||||
public async Task<ImportBibleNotesParams> GetImportBibleNotesParamsAsync(IReadOnlyCollection<Tag> databaseTags)
|
||||
public async Task<ImportBibleNotesParams?> GetImportBibleNotesParamsAsync(IReadOnlyCollection<Tag> databaseTags)
|
||||
{
|
||||
_isDialogVisible = true;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
using System.Windows;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
internal class DragDropService : IDragDropService
|
||||
internal sealed class DragDropService : IDragDropService
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether we can accept the drag and drop operation
|
||||
@@ -42,7 +42,7 @@
|
||||
{
|
||||
foreach (var filePath in dataObject.GetFileDropList())
|
||||
{
|
||||
if (IsJwLibraryFile(filePath))
|
||||
if (IsJwLibraryFile(filePath) && !string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
result.Add(filePath);
|
||||
}
|
||||
@@ -52,10 +52,15 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool IsJwLibraryFile(string filePath)
|
||||
private static bool IsJwLibraryFile(string? filePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var ext = Path.GetExtension(filePath);
|
||||
return ext != null && ext.Equals(".jwlibrary", StringComparison.OrdinalIgnoreCase);
|
||||
return ext.Equals(".jwlibrary", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
using Microsoft.Win32;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
internal class FileOpenSaveService : IFileOpenSaveService
|
||||
internal sealed class FileOpenSaveService : IFileOpenSaveService
|
||||
{
|
||||
private static string SaveDirectory { get; set; }
|
||||
private static string? SaveDirectory { get; set; }
|
||||
|
||||
private static string ImportDirectory { get; set; }
|
||||
private static string? ImportDirectory { get; set; }
|
||||
|
||||
private static string ExportDirectory { get; set; }
|
||||
private static string? ExportDirectory { get; set; }
|
||||
|
||||
public string GetBibleNotesExportFilePath(string title)
|
||||
public string? GetBibleNotesExportFilePath(string title)
|
||||
{
|
||||
var saveFileDialog = new SaveFileDialog
|
||||
{
|
||||
@@ -32,7 +32,7 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
public string GetBibleNotesImportFilePath(string title)
|
||||
public string? GetBibleNotesImportFilePath(string title)
|
||||
{
|
||||
var openFileDialog = new OpenFileDialog
|
||||
{
|
||||
@@ -53,7 +53,7 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
public string GetSaveFilePath(string title)
|
||||
public string? GetSaveFilePath(string title)
|
||||
{
|
||||
var saveFileDialog = new SaveFileDialog
|
||||
{
|
||||
@@ -72,7 +72,7 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetJWLMergeDocsFolder()
|
||||
private static string GetJWLMergeDocsFolder()
|
||||
{
|
||||
var folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "JWLMerge");
|
||||
if (!Directory.Exists(folder))
|
||||
@@ -83,17 +83,17 @@
|
||||
return folder;
|
||||
}
|
||||
|
||||
private string GetDefaultSaveFolder()
|
||||
private static string GetDefaultSaveFolder()
|
||||
{
|
||||
return GetJWLMergeDocsFolder();
|
||||
}
|
||||
|
||||
private string GetDefaultExportFolder()
|
||||
private static string GetDefaultExportFolder()
|
||||
{
|
||||
return GetJWLMergeDocsFolder();
|
||||
}
|
||||
|
||||
private string GetDefaultImportFolder()
|
||||
private static string GetDefaultImportFolder()
|
||||
{
|
||||
var folder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||
if (!Directory.Exists(folder))
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using JWLMerge.BackupFileServices.Models;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using JWLMerge.Models;
|
||||
using Models;
|
||||
|
||||
internal interface IDialogService
|
||||
{
|
||||
@@ -15,13 +15,13 @@
|
||||
|
||||
Task<bool> ShouldRemoveFavouritesAsync();
|
||||
|
||||
Task<ImportBibleNotesParams> GetImportBibleNotesParamsAsync(IReadOnlyCollection<Tag> databaseTags);
|
||||
Task<ImportBibleNotesParams?> GetImportBibleNotesParamsAsync(IReadOnlyCollection<Tag> databaseTags);
|
||||
|
||||
Task<NotesByTagResult> GetTagSelectionForNotesRemovalAsync(Tag[] tags, bool includeUntaggedNotes);
|
||||
|
||||
Task<ColorResult> GetColourSelectionForUnderlineRemovalAsync(ColourDef[] colours);
|
||||
|
||||
Task<PubColourResult> GetPubAndColourSelectionForUnderlineRemovalAsync(PublicationDef[] pubs, ColourDef[] colors);
|
||||
Task<PubColourResult?> GetPubAndColourSelectionForUnderlineRemovalAsync(PublicationDef[] pubs, ColourDef[] colors);
|
||||
|
||||
bool IsDialogVisible();
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
{
|
||||
internal interface IFileOpenSaveService
|
||||
{
|
||||
string GetSaveFilePath(string title);
|
||||
string? GetSaveFilePath(string title);
|
||||
|
||||
string GetBibleNotesImportFilePath(string title);
|
||||
string? GetBibleNotesImportFilePath(string title);
|
||||
|
||||
string GetBibleNotesExportFilePath(string title);
|
||||
string? GetBibleNotesExportFilePath(string title);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
void Enqueue(
|
||||
object content,
|
||||
object actionContent,
|
||||
Action<object> actionHandler,
|
||||
Action<object?> actionHandler,
|
||||
object actionArgument,
|
||||
bool promote,
|
||||
bool neverConsiderToBeDuplicate);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
namespace JWLMerge.Services
|
||||
{
|
||||
internal class NotesByTagResult
|
||||
internal sealed class NotesByTagResult
|
||||
{
|
||||
public int[] TagIds { get; set; }
|
||||
public int[]? TagIds { get; set; }
|
||||
|
||||
public bool RemoveUntaggedNotes { get; set; }
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
public void Enqueue(
|
||||
object content,
|
||||
object actionContent,
|
||||
Action<object> actionHandler,
|
||||
Action<object?> actionHandler,
|
||||
object actionArgument,
|
||||
bool promote,
|
||||
bool neverConsiderToBeDuplicate)
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
((SnackbarMessageQueue)TheSnackbarMessageQueue)?.Dispose();
|
||||
((SnackbarMessageQueue)TheSnackbarMessageQueue).Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using JWLMerge.BackupFileServices;
|
||||
using JWLMerge.ViewModel;
|
||||
using BackupFileServices;
|
||||
using ViewModel;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
internal class WindowService : IWindowService
|
||||
internal sealed class WindowService : IWindowService
|
||||
{
|
||||
private readonly List<DetailWindow> _detailWindows;
|
||||
|
||||
@@ -67,9 +67,9 @@
|
||||
return window;
|
||||
}
|
||||
|
||||
private void DetailWindowClosed(object sender, EventArgs e)
|
||||
private void DetailWindowClosed(object? sender, EventArgs e)
|
||||
{
|
||||
var window = (DetailWindow)sender;
|
||||
var window = (DetailWindow?)sender;
|
||||
if (window != null)
|
||||
{
|
||||
_detailWindows.Remove(window);
|
||||
@@ -77,12 +77,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
private DetailWindow GetDetailWindow(string filePath)
|
||||
private DetailWindow? GetDetailWindow(string filePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (var window in _detailWindows)
|
||||
{
|
||||
var path = ((DetailViewModel)window.DataContext).FilePath;
|
||||
if (IsSameFile(path, filePath))
|
||||
if (!string.IsNullOrEmpty(path) && IsSameFile(path, filePath))
|
||||
{
|
||||
return window;
|
||||
}
|
||||
@@ -91,7 +96,7 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool IsSameFile(string path1, string path2)
|
||||
private static bool IsSameFile(string path1, string path2)
|
||||
{
|
||||
return Path.GetFullPath(path1).Equals(Path.GetFullPath(path2), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
namespace JWLMerge.ViewModel
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using JWLMerge.Models;
|
||||
using Models;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Microsoft.Toolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.Toolkit.Mvvm.Input;
|
||||
|
||||
internal class BackupFileFormatErrorViewModel : ObservableObject
|
||||
internal sealed class BackupFileFormatErrorViewModel : ObservableObject
|
||||
{
|
||||
public BackupFileFormatErrorViewModel()
|
||||
{
|
||||
OkCommand = new RelayCommand(Ok);
|
||||
}
|
||||
|
||||
public List<FileFormatErrorListItem> Errors { get; } = new List<FileFormatErrorListItem>();
|
||||
public List<FileFormatErrorListItem> Errors { get; } = new();
|
||||
|
||||
public RelayCommand OkCommand { get; }
|
||||
|
||||
|
||||
@@ -5,25 +5,25 @@
|
||||
using JWLMerge.BackupFileServices.Models;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using JWLMerge.BackupFileServices.Models.ManifestFile;
|
||||
using JWLMerge.Models;
|
||||
using Models;
|
||||
using Microsoft.Toolkit.Mvvm.ComponentModel;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
internal class DetailViewModel : ObservableObject
|
||||
internal sealed class DetailViewModel : ObservableObject
|
||||
{
|
||||
private DataTypeListItem _selectedDataType;
|
||||
private DataTypeListItem? _selectedDataType;
|
||||
private bool _notesRedacted;
|
||||
private string _windowTitle;
|
||||
private BackupFile _backupFile;
|
||||
private string? _windowTitle;
|
||||
private BackupFile? _backupFile;
|
||||
|
||||
public DetailViewModel()
|
||||
{
|
||||
ListItems = CreateListItems();
|
||||
}
|
||||
|
||||
public string FilePath { get; set; }
|
||||
public string? FilePath { get; set; }
|
||||
|
||||
public BackupFile BackupFile
|
||||
public BackupFile? BackupFile
|
||||
{
|
||||
get => _backupFile;
|
||||
set
|
||||
@@ -36,13 +36,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<DataTypeListItem> ListItems { get; }
|
||||
|
||||
public string WindowTitle
|
||||
{
|
||||
get => _windowTitle ?? string.Empty;
|
||||
set => SetProperty(ref _windowTitle, value);
|
||||
private set => SetProperty(ref _windowTitle, value);
|
||||
}
|
||||
|
||||
public bool NotesRedacted
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
public bool NotesNotRedacted => !NotesRedacted;
|
||||
|
||||
public DataTypeListItem SelectedDataType
|
||||
public DataTypeListItem? SelectedDataType
|
||||
{
|
||||
get => _selectedDataType;
|
||||
set
|
||||
@@ -76,7 +76,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable DataItemsSource
|
||||
#pragma warning disable U2U1200 // Prefer generic collections over non-generic ones
|
||||
public IEnumerable? DataItemsSource
|
||||
#pragma warning restore U2U1200 // Prefer generic collections over non-generic ones
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -118,13 +120,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable S1168 // Empty arrays and collections should be returned instead of null
|
||||
return null;
|
||||
#pragma warning restore S1168 // Empty arrays and collections should be returned instead of null
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsNotesItemSelected => SelectedDataType.DataType == JwLibraryFileDataTypes.Note;
|
||||
|
||||
private IEnumerable ManifestAsItemsSource(Manifest manifest)
|
||||
public bool IsNotesItemSelected => SelectedDataType?.DataType == JwLibraryFileDataTypes.Note;
|
||||
|
||||
#pragma warning disable U2U1011 // Return types should be specific
|
||||
private static IEnumerable ManifestAsItemsSource(Manifest? manifest)
|
||||
#pragma warning restore U2U1011 // Return types should be specific
|
||||
{
|
||||
var result = new List<KeyValuePair<string, string>>();
|
||||
|
||||
@@ -144,20 +150,20 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<DataTypeListItem> CreateListItems()
|
||||
private static List<DataTypeListItem> CreateListItems()
|
||||
{
|
||||
return new List<DataTypeListItem>
|
||||
return new()
|
||||
{
|
||||
new DataTypeListItem { Caption = "Manifest", DataType = JwLibraryFileDataTypes.Manifest },
|
||||
new DataTypeListItem { Caption = "Block Range", DataType = JwLibraryFileDataTypes.BlockRange },
|
||||
new DataTypeListItem { Caption = "Bookmark", DataType = JwLibraryFileDataTypes.Bookmark },
|
||||
new DataTypeListItem { Caption = "InputField", DataType = JwLibraryFileDataTypes.InputField },
|
||||
new DataTypeListItem { Caption = "Last Modified", DataType = JwLibraryFileDataTypes.LastModified },
|
||||
new DataTypeListItem { Caption = "Location", DataType = JwLibraryFileDataTypes.Location },
|
||||
new DataTypeListItem { Caption = "Note", DataType = JwLibraryFileDataTypes.Note },
|
||||
new DataTypeListItem { Caption = "Tag", DataType = JwLibraryFileDataTypes.Tag },
|
||||
new DataTypeListItem { Caption = "Tag Map", DataType = JwLibraryFileDataTypes.TagMap },
|
||||
new DataTypeListItem { Caption = "User Mark", DataType = JwLibraryFileDataTypes.UserMark },
|
||||
new("Manifest", JwLibraryFileDataTypes.Manifest),
|
||||
new("Block Range", JwLibraryFileDataTypes.BlockRange),
|
||||
new("Bookmark", JwLibraryFileDataTypes.Bookmark),
|
||||
new("InputField", JwLibraryFileDataTypes.InputField),
|
||||
new("Last Modified", JwLibraryFileDataTypes.LastModified),
|
||||
new("Location", JwLibraryFileDataTypes.Location),
|
||||
new("Note", JwLibraryFileDataTypes.Note),
|
||||
new("Tag", JwLibraryFileDataTypes.Tag),
|
||||
new("Tag Map", JwLibraryFileDataTypes.TagMap),
|
||||
new("User Mark", JwLibraryFileDataTypes.UserMark),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
using Microsoft.Toolkit.Mvvm.Input;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
internal class ImportBibleNotesViewModel : ObservableObject
|
||||
internal sealed class ImportBibleNotesViewModel : ObservableObject
|
||||
{
|
||||
private IReadOnlyCollection<Tag> _tags;
|
||||
private IReadOnlyCollection<Tag>? _tags;
|
||||
|
||||
public ImportBibleNotesViewModel()
|
||||
{
|
||||
@@ -18,13 +18,13 @@
|
||||
CancelCommand = new RelayCommand(Cancel);
|
||||
}
|
||||
|
||||
public ImportBibleNotesParams Result { get; private set; }
|
||||
public ImportBibleNotesParams? Result { get; private set; }
|
||||
|
||||
public RelayCommand OkCommand { get; set; }
|
||||
|
||||
public RelayCommand CancelCommand { get; set; }
|
||||
|
||||
public IReadOnlyCollection<Tag> Tags
|
||||
public IReadOnlyCollection<Tag>? Tags
|
||||
{
|
||||
get => _tags;
|
||||
set
|
||||
|
||||
@@ -9,14 +9,14 @@ namespace JWLMerge.ViewModel
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using JWLMerge.BackupFileServices;
|
||||
using BackupFileServices;
|
||||
using JWLMerge.BackupFileServices.Helpers;
|
||||
using JWLMerge.BackupFileServices.Models.DatabaseModels;
|
||||
using JWLMerge.ExcelServices;
|
||||
using JWLMerge.Helpers;
|
||||
using JWLMerge.Messages;
|
||||
using JWLMerge.Models;
|
||||
using JWLMerge.Services;
|
||||
using ExcelServices;
|
||||
using Helpers;
|
||||
using Messages;
|
||||
using Models;
|
||||
using Services;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Microsoft.Toolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.Toolkit.Mvvm.Input;
|
||||
@@ -24,7 +24,7 @@ namespace JWLMerge.ViewModel
|
||||
using Serilog;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
internal class MainViewModel : ObservableObject
|
||||
internal sealed class MainViewModel : ObservableObject
|
||||
{
|
||||
private readonly string _latestReleaseUrl = Properties.Resources.LATEST_RELEASE_URL;
|
||||
private readonly IDragDropService _dragDropService;
|
||||
@@ -69,9 +69,9 @@ namespace JWLMerge.ViewModel
|
||||
GetVersionData();
|
||||
}
|
||||
|
||||
public ObservableCollection<JwLibraryFile> Files { get; } = new ObservableCollection<JwLibraryFile>();
|
||||
public ObservableCollection<JwLibraryFile> Files { get; } = new();
|
||||
|
||||
public string Title { get; set; }
|
||||
public string Title { get; private set; } = null!;
|
||||
|
||||
public bool FileListEmpty => Files.Count == 0;
|
||||
|
||||
@@ -86,8 +86,8 @@ namespace JWLMerge.ViewModel
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(IsNotBusy));
|
||||
|
||||
MergeCommand?.NotifyCanExecuteChanged();
|
||||
CloseCardCommand?.NotifyCanExecuteChanged();
|
||||
MergeCommand.NotifyCanExecuteChanged();
|
||||
CloseCardCommand.NotifyCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,31 +113,31 @@ namespace JWLMerge.ViewModel
|
||||
public ISnackbarMessageQueue TheSnackbarMessageQueue => _snackbarService.TheSnackbarMessageQueue;
|
||||
|
||||
// commands...
|
||||
public RelayCommand<string> CloseCardCommand { get; set; }
|
||||
public RelayCommand<string> CloseCardCommand { get; private set; } = null!;
|
||||
|
||||
public RelayCommand<string> ShowDetailsCommand { get; set; }
|
||||
public RelayCommand<string> ShowDetailsCommand { get; private set; } = null!;
|
||||
|
||||
public RelayCommand MergeCommand { get; set; }
|
||||
public RelayCommand MergeCommand { get; private set; } = null!;
|
||||
|
||||
public RelayCommand HomepageCommand { get; set; }
|
||||
public RelayCommand HomepageCommand { get; private set; } = null!;
|
||||
|
||||
public RelayCommand UpdateCommand { get; set; }
|
||||
public RelayCommand UpdateCommand { get; private set; } = null!;
|
||||
|
||||
public RelayCommand<string> RemoveFavouritesCommand { get; set; }
|
||||
public RelayCommand<string> RemoveFavouritesCommand { get; private set; } = null!;
|
||||
|
||||
public RelayCommand<string> RedactNotesCommand { get; set; }
|
||||
public RelayCommand<string> RedactNotesCommand { get; private set; } = null!;
|
||||
|
||||
public RelayCommand<string> ImportBibleNotesCommand { get; set; }
|
||||
public RelayCommand<string> ImportBibleNotesCommand { get; private set; } = null!;
|
||||
|
||||
public RelayCommand<string> ExportBibleNotesCommand { get; set; }
|
||||
public RelayCommand<string> ExportBibleNotesCommand { get; private set; } = null!;
|
||||
|
||||
public RelayCommand<string> RemoveNotesByTagCommand { get; set; }
|
||||
public RelayCommand<string> RemoveNotesByTagCommand { get; private set; } = null!;
|
||||
|
||||
public RelayCommand<string> RemoveUnderliningByColourCommand { get; set; }
|
||||
public RelayCommand<string> RemoveUnderliningByColourCommand { get; private set; } = null!;
|
||||
|
||||
public RelayCommand<string> RemoveUnderliningByPubAndColourCommand { get; set; }
|
||||
public RelayCommand<string> RemoveUnderliningByPubAndColourCommand { get; private set; } = null!;
|
||||
|
||||
private JwLibraryFile GetFile(string filePath)
|
||||
private JwLibraryFile? GetFile(string? filePath)
|
||||
{
|
||||
var file = Files.SingleOrDefault(x => x.FilePath.Equals(filePath));
|
||||
if (file == null)
|
||||
@@ -158,34 +158,38 @@ namespace JWLMerge.ViewModel
|
||||
}
|
||||
|
||||
private void FilesCollectionChanged(
|
||||
object sender,
|
||||
object? sender,
|
||||
System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(FileListEmpty));
|
||||
OnPropertyChanged(nameof(MergeCommandCaption));
|
||||
MergeCommand?.NotifyCanExecuteChanged();
|
||||
MergeCommand.NotifyCanExecuteChanged();
|
||||
}
|
||||
|
||||
private void InitCommands()
|
||||
{
|
||||
CloseCardCommand = new RelayCommand<string>(RemoveCard, filePath => !IsBusy && !_dialogService.IsDialogVisible());
|
||||
ShowDetailsCommand = new RelayCommand<string>(ShowDetails, filePath => !IsBusy);
|
||||
CloseCardCommand = new RelayCommand<string>(RemoveCard, _ => !IsBusy && !_dialogService.IsDialogVisible());
|
||||
ShowDetailsCommand = new RelayCommand<string>(ShowDetails, _ => !IsBusy);
|
||||
MergeCommand = new RelayCommand(MergeFiles, () => GetMergeableFileCount() > 0 && !IsBusy && !_dialogService.IsDialogVisible());
|
||||
HomepageCommand = new RelayCommand(LaunchHomepage);
|
||||
UpdateCommand = new RelayCommand(LaunchLatestReleasePage);
|
||||
|
||||
RemoveFavouritesCommand = new RelayCommand<string>(async (filePath) => await RemoveFavouritesAsync(filePath), filePath => !IsBusy);
|
||||
RedactNotesCommand = new RelayCommand<string>(async (filePath) => await RedactNotesAsync(filePath), filePath => !IsBusy);
|
||||
ImportBibleNotesCommand = new RelayCommand<string>(async (filePath) => await ImportBibleNotesAsync(filePath), filePath => !IsBusy);
|
||||
ExportBibleNotesCommand = new RelayCommand<string>(async (filePath) => await ExportBibleNotesAsync(filePath), filePath => !IsBusy);
|
||||
RemoveNotesByTagCommand = new RelayCommand<string>(async (filePath) => await RemoveNotesByTagAsync(filePath), filePath => !IsBusy);
|
||||
RemoveUnderliningByColourCommand = new RelayCommand<string>(async (filePath) => await RemoveUnderliningByColourAsync(filePath), filePath => !IsBusy);
|
||||
RemoveUnderliningByPubAndColourCommand = new RelayCommand<string>(async (filePath) => await RemoveUnderliningByPubAndColourAsync(filePath), filePath => !IsBusy);
|
||||
RemoveFavouritesCommand = new RelayCommand<string>(async filePath => await RemoveFavouritesAsync(filePath), _ => !IsBusy);
|
||||
RedactNotesCommand = new RelayCommand<string>(async filePath => await RedactNotesAsync(filePath), _ => !IsBusy);
|
||||
ImportBibleNotesCommand = new RelayCommand<string>(async filePath => await ImportBibleNotesAsync(filePath), _ => !IsBusy);
|
||||
ExportBibleNotesCommand = new RelayCommand<string>(async filePath => await ExportBibleNotesAsync(filePath), _ => !IsBusy);
|
||||
RemoveNotesByTagCommand = new RelayCommand<string>(async filePath => await RemoveNotesByTagAsync(filePath), _ => !IsBusy);
|
||||
RemoveUnderliningByColourCommand = new RelayCommand<string>(async filePath => await RemoveUnderliningByColourAsync(filePath), _ => !IsBusy);
|
||||
RemoveUnderliningByPubAndColourCommand = new RelayCommand<string>(async filePath => await RemoveUnderliningByPubAndColourAsync(filePath), _ => !IsBusy);
|
||||
}
|
||||
|
||||
private async Task ExportBibleNotesAsync(string filePath)
|
||||
private async Task ExportBibleNotesAsync(string? filePath)
|
||||
{
|
||||
var file = GetFile(filePath);
|
||||
if (file == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var bibleNotesExportFilePath = _fileOpenSaveService.GetBibleNotesExportFilePath("Bible Notes File");
|
||||
if (string.IsNullOrWhiteSpace(bibleNotesExportFilePath))
|
||||
@@ -217,9 +221,13 @@ namespace JWLMerge.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ImportBibleNotesAsync(string filePath)
|
||||
private async Task ImportBibleNotesAsync(string? filePath)
|
||||
{
|
||||
var file = GetFile(filePath);
|
||||
if (file == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var bibleNotesImportFilePath = _fileOpenSaveService.GetBibleNotesImportFilePath("Bible Notes File");
|
||||
if (string.IsNullOrWhiteSpace(bibleNotesImportFilePath))
|
||||
@@ -227,7 +235,7 @@ namespace JWLMerge.ViewModel
|
||||
return;
|
||||
}
|
||||
|
||||
var userDefinedTags = file.BackupFile.Database.Tags.Where(x => x.Type != 0)
|
||||
var userDefinedTags = file!.BackupFile.Database.Tags.Where(x => x.Type != 0)
|
||||
.OrderBy(x => x.Name)
|
||||
.ToList();
|
||||
|
||||
@@ -256,7 +264,7 @@ namespace JWLMerge.ViewModel
|
||||
_backupFileService.WriteNewDatabaseWithClean(file.BackupFile, file.FilePath, file.FilePath);
|
||||
});
|
||||
|
||||
_windowService.Close(filePath);
|
||||
_windowService.Close(filePath!);
|
||||
_snackbarService.Enqueue("Bible notes imported successfully");
|
||||
|
||||
file.RefreshTooltipSummary();
|
||||
@@ -272,9 +280,13 @@ namespace JWLMerge.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RemoveUnderliningByPubAndColourAsync(string filePath)
|
||||
private async Task RemoveUnderliningByPubAndColourAsync(string? filePath)
|
||||
{
|
||||
var file = GetFile(filePath);
|
||||
if (file == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var colors = ColourHelper.GetHighlighterColoursInUse(file.BackupFile.Database.UserMarks, true);
|
||||
var pubs = PublicationHelper.GetPublications(file.BackupFile.Database.Locations, file.BackupFile.Database.UserMarks, true);
|
||||
@@ -296,11 +308,11 @@ namespace JWLMerge.ViewModel
|
||||
|
||||
if (underliningRemoved > 0)
|
||||
{
|
||||
_backupFileService.WriteNewDatabaseWithClean(file.BackupFile, filePath, filePath);
|
||||
_backupFileService.WriteNewDatabaseWithClean(file.BackupFile, filePath!, filePath!);
|
||||
}
|
||||
});
|
||||
|
||||
_windowService.Close(filePath);
|
||||
_windowService.Close(filePath!);
|
||||
|
||||
_snackbarService.Enqueue(underliningRemoved == 0
|
||||
? "There was no underlining to remove!"
|
||||
@@ -319,9 +331,13 @@ namespace JWLMerge.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RemoveUnderliningByColourAsync(string filePath)
|
||||
private async Task RemoveUnderliningByColourAsync(string? filePath)
|
||||
{
|
||||
var file = GetFile(filePath);
|
||||
if (file == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.BackupFile.Database.UserMarks.Any())
|
||||
{
|
||||
@@ -349,11 +365,11 @@ namespace JWLMerge.ViewModel
|
||||
|
||||
if (underliningRemoved > 0)
|
||||
{
|
||||
_backupFileService.WriteNewDatabaseWithClean(file.BackupFile, filePath, filePath);
|
||||
_backupFileService.WriteNewDatabaseWithClean(file.BackupFile, filePath!, filePath!);
|
||||
}
|
||||
});
|
||||
|
||||
_windowService.Close(filePath);
|
||||
_windowService.Close(filePath!);
|
||||
|
||||
_snackbarService.Enqueue(underliningRemoved == 0
|
||||
? "There was no underlining to remove!"
|
||||
@@ -372,9 +388,13 @@ namespace JWLMerge.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RemoveNotesByTagAsync(string filePath)
|
||||
private async Task RemoveNotesByTagAsync(string? filePath)
|
||||
{
|
||||
var file = GetFile(filePath);
|
||||
if (file == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tags = TagHelper.GetTagsInUseByNotes(file.BackupFile.Database);
|
||||
|
||||
@@ -403,11 +423,11 @@ namespace JWLMerge.ViewModel
|
||||
|
||||
if (notesRemovedCount > 0)
|
||||
{
|
||||
_backupFileService.WriteNewDatabaseWithClean(file.BackupFile, filePath, filePath);
|
||||
_backupFileService.WriteNewDatabaseWithClean(file.BackupFile, filePath!, filePath!);
|
||||
}
|
||||
});
|
||||
|
||||
_windowService.Close(filePath);
|
||||
_windowService.Close(filePath!);
|
||||
|
||||
_snackbarService.Enqueue(notesRemovedCount == 0
|
||||
? "There were no notes to remove!"
|
||||
@@ -426,18 +446,18 @@ namespace JWLMerge.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RedactNotesAsync(string filePath)
|
||||
private async Task RedactNotesAsync(string? filePath)
|
||||
{
|
||||
var file = GetFile(filePath);
|
||||
|
||||
var notes = file.BackupFile?.Database.Notes;
|
||||
var notes = file?.BackupFile.Database.Notes;
|
||||
if (notes == null || !notes.Any())
|
||||
{
|
||||
_snackbarService.Enqueue("No notes found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.NotesRedacted)
|
||||
if (file!.NotesRedacted)
|
||||
{
|
||||
_snackbarService.Enqueue("Notes already obfuscated");
|
||||
return;
|
||||
@@ -452,10 +472,10 @@ namespace JWLMerge.ViewModel
|
||||
await Task.Run(() =>
|
||||
{
|
||||
count = _backupFileService.RedactNotes(file.BackupFile);
|
||||
_backupFileService.WriteNewDatabase(file.BackupFile, filePath, filePath);
|
||||
_backupFileService.WriteNewDatabase(file.BackupFile, filePath!, filePath!);
|
||||
});
|
||||
|
||||
_windowService.Close(filePath);
|
||||
_windowService.Close(filePath!);
|
||||
file.NotesRedacted = true;
|
||||
_snackbarService.Enqueue($"{count} Notes obfuscated successfully");
|
||||
}
|
||||
@@ -471,11 +491,11 @@ namespace JWLMerge.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RemoveFavouritesAsync(string filePath)
|
||||
private async Task RemoveFavouritesAsync(string? filePath)
|
||||
{
|
||||
var file = GetFile(filePath);
|
||||
|
||||
var favourites = file.BackupFile?.Database.TagMaps.Where(x => x.TagId == 1);
|
||||
var favourites = file?.BackupFile.Database.TagMaps.Where(x => x.TagId == 1);
|
||||
if (favourites == null || !favourites.Any())
|
||||
{
|
||||
_snackbarService.Enqueue("No favourites found");
|
||||
@@ -489,14 +509,14 @@ namespace JWLMerge.ViewModel
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
_backupFileService.RemoveFavourites(file.BackupFile);
|
||||
_backupFileService.WriteNewDatabase(file.BackupFile, filePath, filePath);
|
||||
_backupFileService.RemoveFavourites(file!.BackupFile);
|
||||
_backupFileService.WriteNewDatabase(file.BackupFile, filePath!, filePath!);
|
||||
});
|
||||
|
||||
_snackbarService.Enqueue("Favourites removed successfully");
|
||||
_windowService.Close(filePath);
|
||||
_windowService.Close(filePath!);
|
||||
|
||||
file.RefreshTooltipSummary();
|
||||
file!.RefreshTooltipSummary();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -568,13 +588,7 @@ namespace JWLMerge.ViewModel
|
||||
// applying any merge parameters.
|
||||
ReloadFiles();
|
||||
}
|
||||
}).ContinueWith(previousTask =>
|
||||
{
|
||||
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
IsBusy = false;
|
||||
}));
|
||||
});
|
||||
}).ContinueWith(_ => Application.Current.Dispatcher.BeginInvoke(new Action(() => IsBusy = false)));
|
||||
}
|
||||
|
||||
private void ApplyMergeParameters()
|
||||
@@ -606,7 +620,7 @@ namespace JWLMerge.ViewModel
|
||||
});
|
||||
}
|
||||
|
||||
private string GetSuitableFilePathForSchema()
|
||||
private string? GetSuitableFilePathForSchema()
|
||||
{
|
||||
foreach (var file in Files)
|
||||
{
|
||||
@@ -619,8 +633,13 @@ namespace JWLMerge.ViewModel
|
||||
return null;
|
||||
}
|
||||
|
||||
private void RemoveCard(string filePath)
|
||||
private void RemoveCard(string? filePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var file in Files)
|
||||
{
|
||||
if (IsSameFile(file.FilePath, filePath))
|
||||
@@ -632,8 +651,13 @@ namespace JWLMerge.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowDetails(string filePath)
|
||||
private void ShowDetails(string? filePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var file = GetFile(filePath);
|
||||
if (file != null)
|
||||
{
|
||||
@@ -704,11 +728,7 @@ namespace JWLMerge.ViewModel
|
||||
{
|
||||
var backupFile = _backupFileService.Load(file);
|
||||
|
||||
tmpFilesCollection.Add(new JwLibraryFile
|
||||
{
|
||||
BackupFile = backupFile,
|
||||
FilePath = file,
|
||||
});
|
||||
tmpFilesCollection.Add(new JwLibraryFile(file, backupFile));
|
||||
});
|
||||
|
||||
foreach (var file in tmpFilesCollection)
|
||||
@@ -721,14 +741,14 @@ namespace JWLMerge.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private void FilePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
private void FilePropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
// when the merge params are modified it can leave the number of mergeable items at less than 2.
|
||||
MergeCommand?.NotifyCanExecuteChanged();
|
||||
MergeCommand.NotifyCanExecuteChanged();
|
||||
OnPropertyChanged(nameof(MergeCommandCaption));
|
||||
}
|
||||
|
||||
private bool IsSameFile(string path1, string path2)
|
||||
private static bool IsSameFile(string path1, string path2)
|
||||
{
|
||||
return Path.GetFullPath(path1).Equals(Path.GetFullPath(path2), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
@@ -767,7 +787,7 @@ namespace JWLMerge.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsInDesignMode()
|
||||
private static bool IsInDesignMode()
|
||||
{
|
||||
#if DEBUG
|
||||
DependencyObject dep = new();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
using Microsoft.Toolkit.Mvvm.Input;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
internal class RedactNotesPromptViewModel : ObservableObject
|
||||
internal sealed class RedactNotesPromptViewModel : ObservableObject
|
||||
{
|
||||
public RedactNotesPromptViewModel()
|
||||
{
|
||||
@@ -13,9 +13,9 @@
|
||||
NoCommand = new RelayCommand(No);
|
||||
}
|
||||
|
||||
public RelayCommand YesCommand { get; set; }
|
||||
public RelayCommand YesCommand { get; }
|
||||
|
||||
public RelayCommand NoCommand { get; set; }
|
||||
public RelayCommand NoCommand { get; }
|
||||
|
||||
public bool Result { get; private set; }
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
using Microsoft.Toolkit.Mvvm.Input;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
internal class RemoveFavouritesPromptViewModel : ObservableObject
|
||||
internal sealed class RemoveFavouritesPromptViewModel : ObservableObject
|
||||
{
|
||||
public RemoveFavouritesPromptViewModel()
|
||||
{
|
||||
@@ -13,9 +13,9 @@
|
||||
NoCommand = new RelayCommand(No);
|
||||
}
|
||||
|
||||
public RelayCommand YesCommand { get; set; }
|
||||
public RelayCommand YesCommand { get; }
|
||||
|
||||
public RelayCommand NoCommand { get; set; }
|
||||
public RelayCommand NoCommand { get; }
|
||||
|
||||
public bool Result { get; private set; }
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using JWLMerge.Models;
|
||||
using JWLMerge.Services;
|
||||
using Models;
|
||||
using Services;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Microsoft.Toolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.Toolkit.Mvvm.Input;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
internal class RemoveNotesByTagViewModel : ObservableObject
|
||||
internal sealed class RemoveNotesByTagViewModel : ObservableObject
|
||||
{
|
||||
private bool _removeAssociatedUnderlining;
|
||||
private bool _removeAssociatedTags;
|
||||
@@ -23,13 +23,13 @@
|
||||
TagItems.CollectionChanged += TagItemsCollectionChanged;
|
||||
}
|
||||
|
||||
public RelayCommand OkCommand { get; set; }
|
||||
public RelayCommand OkCommand { get; }
|
||||
|
||||
public RelayCommand CancelCommand { get; set; }
|
||||
public RelayCommand CancelCommand { get; }
|
||||
|
||||
public int[] Result { get; private set; }
|
||||
public int[]? Result { get; private set; }
|
||||
|
||||
public ObservableCollection<TagListItem> TagItems { get; } = new ObservableCollection<TagListItem>();
|
||||
public ObservableCollection<TagListItem> TagItems { get; } = new();
|
||||
|
||||
public bool SelectionMade => TagItems.Any(x => x.IsChecked);
|
||||
|
||||
@@ -49,9 +49,9 @@
|
||||
? "Remove associated Tags"
|
||||
: "Remove associated Tag";
|
||||
|
||||
private void TagItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
private void TagItemsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.Action == NotifyCollectionChangedAction.Add)
|
||||
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems != null)
|
||||
{
|
||||
foreach (TagListItem item in e.NewItems)
|
||||
{
|
||||
@@ -65,7 +65,7 @@
|
||||
return TagItems.Count(x => x.IsChecked && x.Id != DialogService.UntaggedItemId);
|
||||
}
|
||||
|
||||
private void ItemPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
private void ItemPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(SelectionMade));
|
||||
OnPropertyChanged(nameof(RemoveTagsCaption));
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using JWLMerge.Models;
|
||||
using Models;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Microsoft.Toolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.Toolkit.Mvvm.Input;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
internal class RemoveUnderliningByColourViewModel : ObservableObject
|
||||
internal sealed class RemoveUnderliningByColourViewModel : ObservableObject
|
||||
{
|
||||
private bool _removeAssociatedNotes;
|
||||
|
||||
@@ -21,15 +21,15 @@
|
||||
ColourItems.CollectionChanged += ItemsCollectionChanged;
|
||||
}
|
||||
|
||||
public RelayCommand OkCommand { get; set; }
|
||||
public RelayCommand OkCommand { get; }
|
||||
|
||||
public RelayCommand CancelCommand { get; set; }
|
||||
public RelayCommand CancelCommand { get; }
|
||||
|
||||
public ObservableCollection<ColourListItem> ColourItems { get; } = new ObservableCollection<ColourListItem>();
|
||||
public ObservableCollection<ColourListItem> ColourItems { get; } = new();
|
||||
|
||||
public bool SelectionMade => ColourItems.Any(x => x.IsChecked);
|
||||
|
||||
public int[] Result { get; private set; }
|
||||
public int[]? Result { get; private set; }
|
||||
|
||||
public bool RemoveAssociatedNotes
|
||||
{
|
||||
@@ -37,9 +37,9 @@
|
||||
set => SetProperty(ref _removeAssociatedNotes, value);
|
||||
}
|
||||
|
||||
private void ItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
private void ItemsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.Action == NotifyCollectionChangedAction.Add)
|
||||
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems != null)
|
||||
{
|
||||
foreach (ColourListItem item in e.NewItems)
|
||||
{
|
||||
@@ -48,7 +48,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
private void ItemPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
private void ItemPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(SelectionMade));
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
namespace JWLMerge.ViewModel
|
||||
{
|
||||
using System.Collections.ObjectModel;
|
||||
using JWLMerge.Models;
|
||||
using Models;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Microsoft.Toolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.Toolkit.Mvvm.Input;
|
||||
|
||||
internal class RemoveUnderliningByPubAndColourViewModel : ObservableObject
|
||||
internal sealed class RemoveUnderliningByPubAndColourViewModel : ObservableObject
|
||||
{
|
||||
private bool _removeAssociatedNotes;
|
||||
private PublicationDef _selectedPublication;
|
||||
private ColourListItem _selectedColour;
|
||||
private PublicationDef? _selectedPublication;
|
||||
private ColourListItem? _selectedColour;
|
||||
|
||||
public RemoveUnderliningByPubAndColourViewModel()
|
||||
{
|
||||
@@ -18,15 +18,15 @@
|
||||
CancelCommand = new RelayCommand(Cancel);
|
||||
}
|
||||
|
||||
public RelayCommand OkCommand { get; set; }
|
||||
public RelayCommand OkCommand { get; }
|
||||
|
||||
public RelayCommand CancelCommand { get; set; }
|
||||
public RelayCommand CancelCommand { get; }
|
||||
|
||||
public ObservableCollection<PublicationDef> PublicationList { get; } = new ObservableCollection<PublicationDef>();
|
||||
public ObservableCollection<PublicationDef> PublicationList { get; } = new();
|
||||
|
||||
public ObservableCollection<ColourListItem> ColourItems { get; } = new ObservableCollection<ColourListItem>();
|
||||
public ObservableCollection<ColourListItem> ColourItems { get; } = new();
|
||||
|
||||
public PublicationDef SelectedPublication
|
||||
public PublicationDef? SelectedPublication
|
||||
{
|
||||
get => _selectedPublication;
|
||||
set
|
||||
@@ -40,7 +40,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
public ColourListItem SelectedColour
|
||||
public ColourListItem? SelectedColour
|
||||
{
|
||||
get => _selectedColour;
|
||||
set
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
public bool SelectionMade => SelectedPublication != null && SelectedColour != null;
|
||||
|
||||
public PubColourResult Result { get; private set; }
|
||||
public PubColourResult? Result { get; private set; }
|
||||
|
||||
public bool RemoveAssociatedNotes
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace JWLMerge.ViewModel
|
||||
/// This class contains static references to all the view models in the
|
||||
/// application and provides an entry point for the bindings.
|
||||
/// </summary>
|
||||
internal class ViewModelLocator
|
||||
internal sealed class ViewModelLocator
|
||||
{
|
||||
public static MainViewModel Main => Ioc.Default.GetService<MainViewModel>()!;
|
||||
|
||||
|
||||
7
JWLMergeCLI/.editorconfig
Normal file
7
JWLMergeCLI/.editorconfig
Normal file
@@ -0,0 +1,7 @@
|
||||
[*.cs]
|
||||
|
||||
# S112: General exceptions should never be thrown
|
||||
dotnet_diagnostic.S112.severity = silent
|
||||
|
||||
# U2U1202: Use LINQ Count methods efficiently
|
||||
dotnet_diagnostic.U2U1202.severity = silent
|
||||
@@ -12,7 +12,7 @@
|
||||
AwaitingOutput,
|
||||
}
|
||||
|
||||
public static CommandLineArgs Parse(string[] args)
|
||||
public static CommandLineArgs? Parse(string[]? args)
|
||||
{
|
||||
if (args == null || args.Length < 2)
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace JWLMergeCLI.Args
|
||||
{
|
||||
internal class CommandLineArgs
|
||||
internal sealed class CommandLineArgs
|
||||
{
|
||||
public string[] BackupFiles { get; set; }
|
||||
public string[] BackupFiles { get; set; } = null!;
|
||||
|
||||
public string OutputFilePath { get; set; }
|
||||
public string? OutputFilePath { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
<ApplicationIcon>JWLMerge.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SolutionInfo.cs" Link="Properties\SolutionInfo.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using System.Linq;
|
||||
using JWLMerge.BackupFileServices;
|
||||
using JWLMerge.BackupFileServices.Events;
|
||||
using JWLMergeCLI.Args;
|
||||
using Args;
|
||||
using Serilog;
|
||||
|
||||
/// <summary>
|
||||
@@ -12,7 +12,7 @@
|
||||
/// </summary>
|
||||
internal sealed class MainApp
|
||||
{
|
||||
public event EventHandler<ProgressEventArgs> ProgressEvent;
|
||||
public event EventHandler<ProgressEventArgs>? ProgressEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Runs the app.
|
||||
@@ -20,7 +20,7 @@
|
||||
/// <param name="args">Program arguments</param>
|
||||
public void Run(CommandLineArgs args)
|
||||
{
|
||||
IBackupFileService backupFileService = new BackupFileService();
|
||||
var backupFileService = new BackupFileService();
|
||||
backupFileService.ProgressEvent += BackupFileServiceProgress;
|
||||
|
||||
var backup = backupFileService.Merge(args.BackupFiles);
|
||||
@@ -32,7 +32,7 @@
|
||||
OnProgressEvent(logMessage);
|
||||
}
|
||||
|
||||
private void BackupFileServiceProgress(object sender, ProgressEventArgs e)
|
||||
private void BackupFileServiceProgress(object? sender, ProgressEventArgs e)
|
||||
{
|
||||
OnProgressEvent(e);
|
||||
}
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
private void OnProgressEvent(string message)
|
||||
{
|
||||
OnProgressEvent(new ProgressEventArgs { Message = message });
|
||||
OnProgressEvent(new ProgressEventArgs(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using JWLMergeCLI.Args;
|
||||
using Args;
|
||||
using Serilog;
|
||||
|
||||
public static class Program
|
||||
@@ -71,7 +71,7 @@
|
||||
{
|
||||
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
|
||||
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
|
||||
return fvi.FileVersion;
|
||||
return fvi.FileVersion ?? "Unknown";
|
||||
}
|
||||
|
||||
private static void ShowUsage()
|
||||
@@ -79,36 +79,36 @@
|
||||
Console.ForegroundColor = ConsoleColor.DarkBlue;
|
||||
Console.BackgroundColor = ConsoleColor.White;
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($" JWLMergeCLI version {GetVersion()} ");
|
||||
Console.WriteLine($@" JWLMergeCLI version {GetVersion()} ");
|
||||
Console.WriteLine();
|
||||
Console.ResetColor();
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
Console.WriteLine(" Description:");
|
||||
Console.WriteLine(@" Description:");
|
||||
Console.ResetColor();
|
||||
Console.WriteLine(" JWLMergeCLI is used to merge the contents of 2 or more jwlibrary backup");
|
||||
Console.WriteLine(" files. These files are produced by the JW Library backup command and");
|
||||
Console.WriteLine(" contain your personal study notes and highlighting.");
|
||||
Console.WriteLine(@" JWLMergeCLI is used to merge the contents of 2 or more jwlibrary backup");
|
||||
Console.WriteLine(@" files. These files are produced by the JW Library backup command and");
|
||||
Console.WriteLine(@" contain your personal study notes and highlighting.");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
Console.WriteLine(" Usage:");
|
||||
Console.WriteLine(@" Usage:");
|
||||
Console.ResetColor();
|
||||
Console.WriteLine(" JWLMergeCLI <jwlibrary file 1> <jwlibrary file 2>... [-o output file]");
|
||||
Console.WriteLine(@" JWLMergeCLI <jwlibrary file 1> <jwlibrary file 2>... [-o output file]");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Note that you can optionally specify the full path and name of the merged");
|
||||
Console.WriteLine(" file using the -o (or --output directive). If you omit it, the merged");
|
||||
Console.WriteLine(" file is stored in the current folder.");
|
||||
Console.WriteLine(@" Note that you can optionally specify the full path and name of the merged");
|
||||
Console.WriteLine(@" file using the -o (or --output directive). If you omit it, the merged");
|
||||
Console.WriteLine(@" file is stored in the current folder.");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
Console.WriteLine(" An example:");
|
||||
Console.WriteLine(@" An example:");
|
||||
Console.ResetColor();
|
||||
Console.WriteLine(" JWLMergeCLI \"C:\\Backup_PC16.jwlibrary\" \"C:\\Backup_iPad.jwlibrary\"");
|
||||
Console.WriteLine(@" JWLMergeCLI ""C:\Backup_PC16.jwlibrary"" ""C:\Backup_iPad.jwlibrary""");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private static void AppProgress(object sender, JWLMerge.BackupFileServices.Events.ProgressEventArgs e)
|
||||
private static void AppProgress(object? sender, JWLMerge.BackupFileServices.Events.ProgressEventArgs e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user