Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DistFiles/aboutBox.htm
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<base target="_blank" rel="noopener noreferrer"><!-- Links should open in new window -->
</head>
<body>
<h1 style="margin-top:8px">Copyright © 2011-2025 <a href="https://www.sil.org/">SIL Global</a></h1>
<h1 style="margin-top:8px">Copyright © 2011-2026 <a href="https://www.sil.org/">SIL Global</a></h1>

<h1>License</h1>
<p>Open source (<a href="https://sil.mit-license.org/">MIT</a>).</p>
Expand Down
2 changes: 2 additions & 0 deletions SayMore.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<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:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HTML/@EntryIndexedValue">HTML</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IE/@EntryIndexedValue">IE</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IMDI/@EntryIndexedValue">IMDI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ISO/@EntryIndexedValue">ISO</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MRU/@EntryIndexedValue">MRU</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OK/@EntryIndexedValue">OK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RAMP/@EntryIndexedValue">RAMP</s:String>
Expand Down
2 changes: 1 addition & 1 deletion build/SayMore.proj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<LocalPackagesRoot Condition="'$(LocalPackagesRoot)'==''">$(RootDir)/packages/</LocalPackagesRoot>
<PalasoL10nsVersion>16.2.0</PalasoL10nsVersion>
<PalasoL10nsRootDir>$(NuGetPackageRoot)SIL.libpalaso.l10ns/$(PalasoL10nsVersion)/</PalasoL10nsRootDir>
<SILReleaseTasksProps>$(NuGetPackageRoot)SIL.ReleaseTasks/3.1.1/build/SIL.ReleaseTasks.props</SILReleaseTasksProps>
<SILReleaseTasksProps>$(NuGetPackageRoot)SIL.ReleaseTasks/3.2.0/build/SIL.ReleaseTasks.props</SILReleaseTasksProps>
<BuildTasksVersionFolder Condition="'$(BuildTasksVersionFolder)' == ''">$(LocalPackagesRoot)SIL.BuildTasks/</BuildTasksVersionFolder>
<BuildTasksDll>$(BuildTasksVersionFolder)tools/SIL.BuildTasks.dll</BuildTasksDll>
<SILBuildTasksProps>$(BuildTasksVersionFolder)build/SIL.BuildTasks.props</SILBuildTasksProps>
Expand Down
2 changes: 1 addition & 1 deletion build/TestInstallerBuild.bat
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ GOTO pauseforusertoseeoutput
REM :unexpectedsystemvariableinuse
REM @ECHO Unexpected system variable msbuildpath is in use. Value: %msbuildpath%
:pauseforusertoseeoutput
ECHO %CMDCMDLINE% | findstr /i "/c" >nul
ECHO %CMDCMDLINE% | findstr /i /c:"/c" >nul
IF NOT errorlevel 1 PAUSE
18 changes: 12 additions & 6 deletions src/Installer/Installer.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<?define Property_UpgradeCode = "{CBCDEE93-B8EF-445e-98A9-B8CAF9502F0D}" ?>

<?define OutputDir = "..\..\output\x64\$(var.Configuration)\net48\" ?>
<?define NativeAssetsDir = "$(var.OutputDir)lib\win-x64\" ?>

<!-- good intro to the component vs. file thing, and why each file here is a separate component:
http://blogs.msdn.com/robmen/archive/2003/10/04/56479.aspx -->
Expand Down Expand Up @@ -200,6 +201,10 @@ are trying to support, you're better off using non-advertised shortcuts. "-->
<File Id="MediaInfo.dll" Name="MediaInfo.dll" KeyPath="yes" Source="$(var.OutputDir)MediaInfo.dll"/>
</Component>

<Component Id="MediaInfoDLL.dll" Guid="{370327F7-D3D9-4673-87C6-6EFE3ED7DB8E}" Win64="yes">
<File Id="MediaInfoDLL.dll" Name="MediaInfoDLL.dll" KeyPath="yes" Source="$(var.OutputDir)MediaInfoDLL.dll"/>
</Component>

<Component Id="NetSparkle.Net40.dll" Guid="{36870B13-214E-4F3E-8226-2FE689C7EEDE}" Win64="yes">
<File Id="NetSparkle.Net40.dll" Name="NetSparkle.Net40.dll" KeyPath="yes" Source="$(var.OutputDir)NetSparkle.Net40.dll"/>
</Component>
Expand Down Expand Up @@ -341,22 +346,22 @@ are trying to support, you're better off using non-advertised shortcuts. "-->
</Component>

<Component Id="icudt59.x64" Guid="{F0CAECD1-8D7E-4D4F-9147-A4E8ED2B741B}" Win64="yes">
<File Id="icudt59.x64" Name="icudt59.dll" KeyPath="yes" Source="$(var.OutputDir)lib\win-x64\icudt59.dll" />
<File Id="icudt59.x64" Name="icudt59.dll" KeyPath="yes" Source="$(var.NativeAssetsDir)icudt59.dll" />
</Component>
<Component Id="icuin59.x64" Guid="{F0CAECD1-8D7E-4D4F-9147-A4E8ED2B741C}" Win64="yes">
<File Id="icuin59.x64" Name="icuin59.dll" KeyPath="yes" Source="$(var.OutputDir)lib\win-x64\icuin59.dll" />
<File Id="icuin59.x64" Name="icuin59.dll" KeyPath="yes" Source="$(var.NativeAssetsDir)icuin59.dll" />
</Component>
<Component Id="icuuc59.x64" Guid="{F0CAECD1-8D7E-4D4F-9147-A4E8ED2B741D}" Win64="yes">
<File Id="icuuc59.x64" Name="icuuc59.dll" KeyPath="yes" Source="$(var.OutputDir)lib\win-x64\icuuc59.dll" />
<File Id="icuuc59.x64" Name="icuuc59.dll" KeyPath="yes" Source="$(var.NativeAssetsDir)icuuc59.dll" />
</Component>
<Component Id="ikpFlac.x64" Guid="{F0CAECD1-8D7E-4D4F-9147-A4E8ED2B741E}" Win64="yes">
<File Id="ikpFlac.x64" Name="ikpFlac.dll" KeyPath="yes" Source="$(var.OutputDir)lib\win-x64\ikpFlac.dll" />
<File Id="ikpFlac.x64" Name="ikpFlac.dll" KeyPath="yes" Source="$(var.NativeAssetsDir)ikpFlac.dll" />
</Component>
<Component Id="ikpMP3.x64" Guid="{F0CAECD1-8D7E-4D4F-9147-A4E8ED2B742A}" Win64="yes">
<File Id="ikpMP3.x64" Name="ikpMP3.dll" KeyPath="yes" Source="$(var.OutputDir)lib\win-x64\ikpMP3.dll" />
<File Id="ikpMP3.x64" Name="ikpMP3.dll" KeyPath="yes" Source="$(var.NativeAssetsDir)ikpMP3.dll" />
</Component>
<Component Id="irrKlang.NET4.x64" Guid="{F0CAECD1-8D7E-4D4F-9147-A4E8ED2B742B}" Win64="yes">
<File Id="irrKlang.NET4.x64" Name="irrKlang.NET4.dll" KeyPath="yes" Source="$(var.OutputDir)lib\win-x64\irrKlang.NET4.dll" />
<File Id="irrKlang.NET4.x64" Name="irrKlang.NET4.dll" KeyPath="yes" Source="$(var.NativeAssetsDir)irrKlang.NET4.dll" />
</Component>
</Directory>
</Directory>
Expand All @@ -378,6 +383,7 @@ are trying to support, you're better off using non-advertised shortcuts. "-->
<ComponentRef Id="L10NSharp.dll"/>
<ComponentRef Id="Markdig.Signed.dll"/>
<ComponentRef Id="MediaInfo.dll"/>
<ComponentRef Id="MediaInfoDLL.dll"/>
<ComponentRef Id="NetSparkle.Net40.dll"/>
<ComponentRef Id="Microsoft.Bcl.AsyncInterfaces.dll"/>
<ComponentRef Id="Microsoft.Extensions.DependencyModel.dll"/>
Expand Down
84 changes: 31 additions & 53 deletions src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,6 @@

namespace SayMore.Model.Files.DataGathering
{
/// ----------------------------------------------------------------------------------------
public interface ISingleListDataGatherer
{
event EventHandler NewDataAvailable;
event EventHandler FinishedProcessingAllFiles;
IEnumerable<string> GetValues();
}

/// ----------------------------------------------------------------------------------------
/// <summary>
/// Gives lists of data, indexed by a key into a dictionary
Expand All @@ -27,15 +19,14 @@ public interface ISingleListDataGatherer
public interface IMultiListDataProvider
{
event EventHandler NewDataAvailable;
event EventHandler FinishedProcessingAllFiles;
Dictionary<string, IEnumerable<string>> GetValueLists(bool includeUnattestedFactoryChoices);
}

/// ----------------------------------------------------------------------------------------
/// <summary>
/// This is the base class for processes which live in the background,
/// gathering data about the files in the collection so that this data
/// is quickly accesible when needed.
/// is quickly accessible when needed.
/// </summary>
/// ----------------------------------------------------------------------------------------
public abstract class BackgroundFileProcessor<T> : IDisposable where T : class
Expand All @@ -49,17 +40,17 @@ public abstract class BackgroundFileProcessor<T> : IDisposable where T : class
protected readonly IEnumerable<FileType> _typesOfFilesToProcess;
protected readonly Func<string, T> _fileDataFactory;
protected bool _restartRequested = true;
protected Dictionary<string, T> _fileToDataDictionary = new Dictionary<string, T>();
protected Dictionary<string, T> _fileToDataDictionary = new();
private readonly Queue<FileSystemEventArgs> _pendingFileEvents;
private volatile int _suspendEventProcessingCount;
private readonly object _lockObj = new object();
private readonly object _lockSuspendObj = new object();
private readonly object _lockObj = new();
private readonly object _lockSuspendObj = new();

public event EventHandler NewDataAvailable;
public event EventHandler FinishedProcessingAllFiles;

/// ------------------------------------------------------------------------------------
public BackgroundFileProcessor(string rootDirectoryPath,
protected BackgroundFileProcessor(string rootDirectoryPath,
IEnumerable<FileType> typesOfFilesToProcess, Func<string, T> fileDataFactory)
{
RootDirectoryPath = rootDirectoryPath;
Expand All @@ -72,8 +63,7 @@ public BackgroundFileProcessor(string rootDirectoryPath,
/// ------------------------------------------------------------------------------------
public void Dispose()
{
if (_workerThread != null)
_workerThread.Abort(); //will eventually lead to it stopping
_workerThread?.Abort(); //will eventually lead to it stopping
_workerThread = null;
}

Expand Down Expand Up @@ -122,39 +112,37 @@ public virtual void ResumeProcessing(bool processAllPendingEventsNow)
protected virtual bool GetDoIncludeFile(string path)
{
var fileName = Path.GetFileName(path);
return (fileName != null && !fileName.StartsWith(".") &&
(_typesOfFilesToProcess.Any(t => t.IsMatch(path))));
return fileName != null && !fileName.StartsWith(".") &&
_typesOfFilesToProcess.Any(t => t.IsMatch(path));
}

/// ------------------------------------------------------------------------------------
protected virtual ThreadPriority ThreadPriority
{
get { return ThreadPriority.Lowest; }
}
protected virtual ThreadPriority ThreadPriority => ThreadPriority.Lowest;

/// ------------------------------------------------------------------------------------
public virtual void Start()
{
_workerThread = new Thread(StartWorking);
_workerThread.Name = GetType().Name;
_workerThread.Priority = ThreadPriority;
_workerThread = new Thread(StartWorking)
{
Name = GetType().Name,
Priority = ThreadPriority
};
_workerThread.TrySetApartmentState(ApartmentState.STA);//needed in case we eventually show an error & need to talk to email.
_workerThread.Start();
}

/// ------------------------------------------------------------------------------------
protected virtual void OnNewDataAvailable(T fileData)
{
if (NewDataAvailable != null)
NewDataAvailable(this, EventArgs.Empty);
NewDataAvailable?.Invoke(this, EventArgs.Empty);
}

/// ------------------------------------------------------------------------------------
private void StartWorking()
{
try
{
Status = kWorkingStatus; //NB: this helps simplify unit tests, if go to the busy state before returning
Status = kWorkingStatus; //NB: this helps simplify unit tests, if we go to the busy state before returning

using (var watcher = new FileSystemWatcher(RootDirectoryPath))
{
Expand Down Expand Up @@ -189,11 +177,11 @@ private void StartWorking()
}
catch (ThreadAbortException)
{
//this is fine, it happens when we quit
// This is fine, it happens when we quit
}
catch (Exception error)
{
SIL.Reporting.ErrorReport.NotifyUserOfProblem(error, "Background file watching failed.");
ErrorReport.NotifyUserOfProblem(error, "Background file watching failed.");
}
}

Expand All @@ -216,13 +204,11 @@ private void ProcessFileEvent(FileSystemEventArgs fileEvent)
{
try
{
if (fileEvent is RenamedEventArgs)
if (fileEvent is RenamedEventArgs e)
{
var e = fileEvent as RenamedEventArgs;
lock (((ICollection)_fileToDataDictionary).SyncRoot)
{
T fileData;
if (_fileToDataDictionary.TryGetValue(e.OldFullPath, out fileData))
if (_fileToDataDictionary.TryGetValue(e.OldFullPath, out var fileData))
{
_fileToDataDictionary.Remove(e.OldFullPath);
_fileToDataDictionary[e.FullPath] = fileData;
Expand All @@ -244,7 +230,7 @@ private void ProcessFileEvent(FileSystemEventArgs fileEvent)
Debug.WriteLine(e.Message);
Logger.WriteEvent("Handled Exception in {0}.ProcessingFileEvent:\r\n{1}", GetType().Name, e.ToString());
#if DEBUG
SIL.Reporting.ErrorReport.NotifyUserOfProblem(e, "Error gathering data");
ErrorReport.NotifyUserOfProblem(e, "Error gathering data");
#endif
//nothing here is worth crashing over
}
Expand All @@ -255,14 +241,13 @@ public T GetFileData(string filePath)
{
lock (((ICollection)_fileToDataDictionary).SyncRoot)
{
T stats;
if (_fileToDataDictionary.TryGetValue(filePath, out stats))
if (_fileToDataDictionary.TryGetValue(filePath, out var stats))
return stats;

if (GetDoIncludeFile(filePath))
{
CollectDataForFile(filePath);
return (_fileToDataDictionary.TryGetValue(filePath, out stats) ? stats : null);
return _fileToDataDictionary.TryGetValue(filePath, out stats) ? stats : null;
}
return null;
}
Expand Down Expand Up @@ -310,7 +295,7 @@ protected virtual void CollectDataForFile(string path)
{
ErrorReport.NotifyUserOfProblem(new ShowOncePerSessionBasedOnExactMessagePolicy(), e,
string.Format(LocalizationManager.GetString("MainWindow.AutoCompleteValueGathererError",
"An error of type {0} ocurred trying to gather information from file: {1}",
"An error of type {0} occurred trying to gather information from file: {1}",
"Parameter 0 is an exception type; parameter 1 is a file name"), e.GetType(), path));
}
else
Expand Down Expand Up @@ -356,7 +341,7 @@ public virtual void ProcessAllFilesInFolder(string folder)
/// ------------------------------------------------------------------------------------
public virtual void ProcessAllFiles()
{
//now that the watcher is up and running, gather up all existing files
// Now that the watcher is up and running, gather all existing files
lock (((ICollection)_fileToDataDictionary).SyncRoot)
{
_fileToDataDictionary.Clear();
Expand Down Expand Up @@ -405,8 +390,7 @@ protected virtual void ProcessAllFiles(string topLevelFolder, bool searchSubFold

Status = kUpToDataStatus;

if (FinishedProcessingAllFiles != null)
FinishedProcessingAllFiles(this, EventArgs.Empty);
FinishedProcessingAllFiles?.Invoke(this, EventArgs.Empty);
}

private static List<string> WalkDirectoryTree(string topLevelFolder, SearchOption searchOption)
Expand All @@ -416,7 +400,7 @@ private static List<string> WalkDirectoryTree(string topLevelFolder, SearchOptio
// First, process all the files directly under this folder
try
{
// SP-879: Crash reading .DS_Store file on MacOS
// SP-879: Crash reading .DS_Store file on macOS
files = Directory.GetFiles(topLevelFolder, "*.*").Where(name =>
{
var fileName = Path.GetFileName(name);
Expand All @@ -435,13 +419,13 @@ private static List<string> WalkDirectoryTree(string topLevelFolder, SearchOptio
Debug.Print("Directory not found: " + topLevelFolder);
}

if ((files != null) && (searchOption == SearchOption.AllDirectories))
if (files != null && searchOption == SearchOption.AllDirectories)
{
// Now find all the subdirectories under this directory.
var dirs = Directory.GetDirectories(topLevelFolder);
foreach (var dir in dirs)
{
// Resursive call for each subdirectory.
// Recursive call for each subdirectory.
returnVal.AddRange(WalkDirectoryTree(dir, searchOption));
}
}
Expand All @@ -468,16 +452,10 @@ protected bool ShouldStop
}

/// ------------------------------------------------------------------------------------
public bool Busy
{
get { return Status.StartsWith(kWorkingStatus); }
}
public bool Busy => Status.StartsWith(kWorkingStatus);

/// ------------------------------------------------------------------------------------
public bool DataUpToDate
{
get { return Status == kUpToDataStatus; }
}
public bool DataUpToDate => Status == kUpToDataStatus;

/// ------------------------------------------------------------------------------------
public string Status
Expand Down
3 changes: 1 addition & 2 deletions src/SayMore/Model/Files/FieldUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ private void FindAndUpdateFiles(ComponentFile file, string idOfFieldToFind,

var matchingFiles = GetMatchingFiles(file.FileType);

if (_fieldGatherer != null)
_fieldGatherer.SuspendProcessing();
_fieldGatherer?.SuspendProcessing();

foreach (var path in matchingFiles)
{
Expand Down
Loading
Loading