From 54b5fc448af16e389517df38b80e48336f992376 Mon Sep 17 00:00:00 2001 From: tombogle Date: Fri, 12 Dec 2025 12:20:57 -0500 Subject: [PATCH 01/29] Added information about projects and events to track creating and opening them. --- src/SayMore/Model/Project.cs | 45 ++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/SayMore/Model/Project.cs b/src/SayMore/Model/Project.cs index 5d71ed92..374691a2 100644 --- a/src/SayMore/Model/Project.cs +++ b/src/SayMore/Model/Project.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Drawing; +using System.IO; using System.IO.Compression; using System.Linq; using System.Text; @@ -13,20 +13,21 @@ using System.Xml.Serialization; using DesktopAnalytics; using L10NSharp; -using SIL.Extensions; -using SIL.Reporting; -using SIL.Windows.Forms; +using SayMore.Model.Files; +using SayMore.Properties; +using SayMore.Transcription.Model; using SayMore.UI.ComponentEditors; using SayMore.UI.Overview; +using SayMore.Utilities; using SIL.Archiving; using SIL.Archiving.Generic; using SIL.Archiving.IMDI; -using SayMore.Properties; -using SayMore.Transcription.Model; -using SayMore.Model.Files; -using SayMore.Utilities; +using SIL.Archiving.IMDI.Schema; using SIL.Core.ClearShare; +using SIL.Extensions; using SIL.IO; +using SIL.Reporting; +using SIL.Windows.Forms; using static System.IO.Path; namespace SayMore.Model @@ -105,30 +106,40 @@ public Project(string desiredOrExistingSettingsFilePath, throw new ArgumentException("Invalid project path specified", nameof(desiredOrExistingSettingsFilePath)); var saveNeeded = false; + var projectInfo = new Dictionary {{"projectName", Name}}; + if (File.Exists(desiredOrExistingSettingsFilePath)) { RenameEventsToSessions(projectDirectory); Load(); + projectInfo["vernacularISO3CodeAndName"] = VernacularISO3CodeAndName; + projectInfo["analysisISO3CodeAndName"] = AnalysisISO3CodeAndName; + projectInfo["projectLocation"] = Location; + projectInfo["projectRegion"] = Region; + projectInfo["projectCountry"] = Country; + projectInfo["projectContinent"] = Continent; } else { + Analytics.Track("Project Created", projectInfo); Directory.CreateDirectory(projectDirectory); Title = Name; saveNeeded = true; } - if (TranscriptionFont == null) - TranscriptionFont = Program.DialogFont; + TranscriptionFont ??= Program.DialogFont; + projectInfo["transcriptionFont"] = TranscriptionFont.Name; + FreeTranslationFont ??= Program.DialogFont; + projectInfo["freeTranslationFont"] = FreeTranslationFont.Name; - if (FreeTranslationFont == null) - FreeTranslationFont = Program.DialogFont; + Analytics.Track("Project Opened", projectInfo); if (AutoSegmenterMinimumSegmentLengthInMilliseconds < Settings.Default.MinimumSegmentLengthInMilliseconds || - AutoSegmenterMaximumSegmentLengthInMilliseconds <= 0 || - AutoSegmenterMinimumSegmentLengthInMilliseconds >= AutoSegmenterMaximumSegmentLengthInMilliseconds || - AutoSegmenterPreferredPauseLengthInMilliseconds <= 0 || - AutoSegmenterPreferredPauseLengthInMilliseconds > AutoSegmenterMaximumSegmentLengthInMilliseconds || - AutoSegmenterOptimumLengthClampingFactor <= 0) + AutoSegmenterMaximumSegmentLengthInMilliseconds <= 0 || + AutoSegmenterMinimumSegmentLengthInMilliseconds >= AutoSegmenterMaximumSegmentLengthInMilliseconds || + AutoSegmenterPreferredPauseLengthInMilliseconds <= 0 || + AutoSegmenterPreferredPauseLengthInMilliseconds > AutoSegmenterMaximumSegmentLengthInMilliseconds || + AutoSegmenterOptimumLengthClampingFactor <= 0) { saveNeeded = AutoSegmenterMinimumSegmentLengthInMilliseconds != 0 || AutoSegmenterMaximumSegmentLengthInMilliseconds != 0 || AutoSegmenterPreferredPauseLengthInMilliseconds != 0 || !AutoSegmenterOptimumLengthClampingFactor.Equals(0) || saveNeeded; From 393b97bac4d346f3c86fe28789be9c8cc6d33851 Mon Sep 17 00:00:00 2001 From: tombogle Date: Tue, 6 Jan 2026 09:02:02 -0500 Subject: [PATCH 02/29] Added an event to note details of significant progress. Included some minor refactoring and code cleanup --- SayMore.sln.DotSettings | 2 + .../DataGathering/BackgroundFileProcessor.cs | 67 ++++-------- src/SayMore/Model/Project.cs | 100 +++++++++++++++++- src/SayMore/Model/SessionWorkflowInformant.cs | 7 +- src/SayMore/ProjectContext.cs | 30 ++---- src/SayMore/UI/Charts/ChartBarInfo.cs | 2 +- src/SayMore/UI/Charts/HTMLChartBuilder.cs | 17 +-- .../UI/Overview/Statistics/StatisticsView.cs | 5 +- .../Statistics/StatisticsViewModel.cs | 59 ++++------- 9 files changed, 170 insertions(+), 119 deletions(-) diff --git a/SayMore.sln.DotSettings b/SayMore.sln.DotSettings index 95865b2c..2b0d594d 100644 --- a/SayMore.sln.DotSettings +++ b/SayMore.sln.DotSettings @@ -1,6 +1,8 @@  + HTML IE IMDI + ISO MRU OK RAMP diff --git a/src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs b/src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs index 8010fe6d..6793371e 100644 --- a/src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs +++ b/src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs @@ -11,14 +11,6 @@ namespace SayMore.Model.Files.DataGathering { - /// ---------------------------------------------------------------------------------------- - public interface ISingleListDataGatherer - { - event EventHandler NewDataAvailable; - event EventHandler FinishedProcessingAllFiles; - IEnumerable GetValues(); - } - /// ---------------------------------------------------------------------------------------- /// /// Gives lists of data, indexed by a key into a dictionary @@ -27,7 +19,6 @@ public interface ISingleListDataGatherer public interface IMultiListDataProvider { event EventHandler NewDataAvailable; - event EventHandler FinishedProcessingAllFiles; Dictionary> GetValueLists(bool includeUnattestedFactoryChoices); } @@ -35,7 +26,7 @@ public interface IMultiListDataProvider /// /// 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. /// /// ---------------------------------------------------------------------------------------- public abstract class BackgroundFileProcessor : IDisposable where T : class @@ -49,17 +40,17 @@ public abstract class BackgroundFileProcessor : IDisposable where T : class protected readonly IEnumerable _typesOfFilesToProcess; protected readonly Func _fileDataFactory; protected bool _restartRequested = true; - protected Dictionary _fileToDataDictionary = new Dictionary(); + protected Dictionary _fileToDataDictionary = new(); private readonly Queue _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 typesOfFilesToProcess, Func fileDataFactory) { RootDirectoryPath = rootDirectoryPath; @@ -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; } @@ -122,15 +112,12 @@ 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() @@ -145,8 +132,7 @@ public virtual void Start() /// ------------------------------------------------------------------------------------ protected virtual void OnNewDataAvailable(T fileData) { - if (NewDataAvailable != null) - NewDataAvailable(this, EventArgs.Empty); + NewDataAvailable?.Invoke(this, EventArgs.Empty); } /// ------------------------------------------------------------------------------------ @@ -193,7 +179,7 @@ private void StartWorking() } catch (Exception error) { - SIL.Reporting.ErrorReport.NotifyUserOfProblem(error, "Background file watching failed."); + ErrorReport.NotifyUserOfProblem(error, "Background file watching failed."); } } @@ -216,13 +202,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; @@ -244,7 +228,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 } @@ -255,14 +239,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; } @@ -310,7 +293,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 @@ -356,7 +339,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 up all existing files lock (((ICollection)_fileToDataDictionary).SyncRoot) { _fileToDataDictionary.Clear(); @@ -416,7 +399,7 @@ private static List 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); @@ -441,7 +424,7 @@ private static List WalkDirectoryTree(string topLevelFolder, SearchOptio 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)); } } @@ -468,16 +451,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 diff --git a/src/SayMore/Model/Project.cs b/src/SayMore/Model/Project.cs index 374691a2..7512d4d0 100644 --- a/src/SayMore/Model/Project.cs +++ b/src/SayMore/Model/Project.cs @@ -18,11 +18,11 @@ using SayMore.Transcription.Model; using SayMore.UI.ComponentEditors; using SayMore.UI.Overview; +using SayMore.UI.Overview.Statistics; using SayMore.Utilities; using SIL.Archiving; using SIL.Archiving.Generic; using SIL.Archiving.IMDI; -using SIL.Archiving.IMDI.Schema; using SIL.Core.ClearShare; using SIL.Extensions; using SIL.IO; @@ -64,6 +64,21 @@ public class Project : IAutoSegmenterSettings, IRAMPArchivable, IDisposable private bool _needToDisposeFreeTranslationFont; private Font _workingLanguageFont; private bool _needToDisposeWorkingLanguageFont; + + private StatisticsViewModel _statisticsViewModel; + private int _initialNumberOfSessions; + private int _finalNumberOfSessions; + private int _initialNumberOfPersons; + private int _finalNumberOfPersons; + private sealed class MediaDurationStats(TimeSpan initial) + { + public TimeSpan Initial { get; } = initial; + public TimeSpan Current { get; set; } = initial; + + public TimeSpan Delta => Current - Initial; + } + + private Dictionary _mediaDurationStats; public delegate Project Factory(string desiredOrExistingFilePath); @@ -157,6 +172,43 @@ public Project(string desiredOrExistingSettingsFilePath, /// ------------------------------------------------------------------------------------ public void Dispose() { + if (_statisticsViewModel != null) + { + _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; + _statisticsViewModel.NewStatisticsAvailable -= UpdateStatistics; + + var sessionDelta = _finalNumberOfSessions - _initialNumberOfSessions; + var personDelta = _finalNumberOfPersons - _initialNumberOfPersons; + + bool hasProgress = + sessionDelta > 0 || + personDelta > 0 || + _mediaDurationStats.Values.Any(s => s.Delta > TimeSpan.Zero); + + if (hasProgress) + { + var properties = new Dictionary(); + + if (sessionDelta > 0) + properties["SessionsAdded"] = sessionDelta.ToString(); + + if (personDelta > 0) + properties["PersonsAdded"] = personDelta.ToString(); + + foreach (var kvp in _mediaDurationStats) + { + var delta = kvp.Value.Delta; + if (delta > TimeSpan.Zero) + { + properties[$"MediaDurationAdded.{kvp.Key}"] = + delta.TotalSeconds.ToString("F0"); + } + } + + Analytics.Track("ProjectProgress", properties); + } + } + _sessionsRepoFactory = null; if (_needToDisposeTranscriptionFont) TranscriptionFont.Dispose(); @@ -810,5 +862,51 @@ public IEnumerable GetSessionFilesToArchive(Type typeOfArchive, Settings.Default.SessionFileExtension, CancellationToken.None)); } #endregion + + public void TrackStatistics(StatisticsViewModel statisticsViewModel) + { + if (_statisticsViewModel != null) + { + _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; + _statisticsViewModel.NewStatisticsAvailable -= UpdateStatistics; + } + + _statisticsViewModel = statisticsViewModel; + _statisticsViewModel.FinishedGatheringStatisticsForAllFiles += FinishedGatheringStatistics; + } + + private void FinishedGatheringStatistics(object sender, EventArgs e) + { + _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; + _initialNumberOfSessions = _statisticsViewModel.SessionInformant.NumberOfSessions; + _initialNumberOfPersons = _statisticsViewModel.PersonInformant.NumberOfPeople; + _mediaDurationStats = + _statisticsViewModel.GetComponentRoleStatisticsPairs() + .ToDictionary( + s => s.Name, + s => new MediaDurationStats(s.Length)); + + _statisticsViewModel.NewStatisticsAvailable += UpdateStatistics; + } + + private void UpdateStatistics(object sender, EventArgs e) + { + _finalNumberOfSessions = _statisticsViewModel.SessionInformant.NumberOfSessions; + _finalNumberOfPersons = _statisticsViewModel.PersonInformant.NumberOfPeople; + + foreach (var stat in _statisticsViewModel.GetComponentRoleStatisticsPairs()) + { + if (_mediaDurationStats.TryGetValue(stat.Name, out var entry)) + entry.Current = stat.Length; + else + { + _mediaDurationStats[stat.Name] = + new MediaDurationStats(TimeSpan.Zero) + { + Current = stat.Length + }; + } + } + } } } diff --git a/src/SayMore/Model/SessionWorkflowInformant.cs b/src/SayMore/Model/SessionWorkflowInformant.cs index 7a1d9ca2..1973df83 100644 --- a/src/SayMore/Model/SessionWorkflowInformant.cs +++ b/src/SayMore/Model/SessionWorkflowInformant.cs @@ -14,7 +14,7 @@ namespace SayMore.Model public class SessionWorkflowInformant { private readonly ElementRepository _sessionRepository; - private IEnumerable _componentRoles; + private readonly IEnumerable _componentRoles; [Obsolete("For mocking only")] public SessionWorkflowInformant(){} @@ -28,10 +28,7 @@ public SessionWorkflowInformant(ElementRepository sessionRepository, } /// ------------------------------------------------------------------------------------ - public int NumberOfSessions - { - get { return _sessionRepository.AllItems.Count(); } - } + public int NumberOfSessions => _sessionRepository.AllItems.Count(); /// ------------------------------------------------------------------------------------ /// diff --git a/src/SayMore/ProjectContext.cs b/src/SayMore/ProjectContext.cs index 31973d0a..7e20c5ab 100644 --- a/src/SayMore/ProjectContext.cs +++ b/src/SayMore/ProjectContext.cs @@ -369,47 +369,37 @@ public void Dispose() /// ------------------------------------------------------------------------------------ public void SuspendAudioVideoBackgroundProcesses() { - if (_audioVideoDataGatherer != null) - _audioVideoDataGatherer.SuspendProcessing(); + _audioVideoDataGatherer?.SuspendProcessing(); } /// ------------------------------------------------------------------------------------ public void ResumeAudioVideoBackgroundProcesses(bool processAllPendingEventsNow) { - if (_audioVideoDataGatherer != null) - _audioVideoDataGatherer.ResumeProcessing(processAllPendingEventsNow); + _audioVideoDataGatherer?.ResumeProcessing(processAllPendingEventsNow); } /// ------------------------------------------------------------------------------------ public void SuspendBackgroundProcesses() { - if (_audioVideoDataGatherer != null) - _audioVideoDataGatherer.SuspendProcessing(); + _audioVideoDataGatherer?.SuspendProcessing(); - if (_autoCompleteValueGatherer != null) - _autoCompleteValueGatherer.SuspendProcessing(); + _autoCompleteValueGatherer?.SuspendProcessing(); - if (_fieldGatherer != null) - _fieldGatherer.SuspendProcessing(); + _fieldGatherer?.SuspendProcessing(); - if (_presetGatherer != null) - _presetGatherer.SuspendProcessing(); + _presetGatherer?.SuspendProcessing(); } /// ------------------------------------------------------------------------------------ public void ResumeBackgroundProcesses(bool processAllPendingEventsNow) { - if (_audioVideoDataGatherer != null) - _audioVideoDataGatherer.ResumeProcessing(processAllPendingEventsNow); + _audioVideoDataGatherer?.ResumeProcessing(processAllPendingEventsNow); - if (_autoCompleteValueGatherer != null) - _autoCompleteValueGatherer.ResumeProcessing(processAllPendingEventsNow); + _autoCompleteValueGatherer?.ResumeProcessing(processAllPendingEventsNow); - if (_fieldGatherer != null) - _fieldGatherer.ResumeProcessing(processAllPendingEventsNow); + _fieldGatherer?.ResumeProcessing(processAllPendingEventsNow); - if (_presetGatherer != null) - _presetGatherer.ResumeProcessing(processAllPendingEventsNow); + _presetGatherer?.ResumeProcessing(processAllPendingEventsNow); } /// ------------------------------------------------------------------------------------ diff --git a/src/SayMore/UI/Charts/ChartBarInfo.cs b/src/SayMore/UI/Charts/ChartBarInfo.cs index 196820c6..7cc957df 100644 --- a/src/SayMore/UI/Charts/ChartBarInfo.cs +++ b/src/SayMore/UI/Charts/ChartBarInfo.cs @@ -130,7 +130,7 @@ public ChartBarSegmentInfo(string fieldName, string fieldValue, } catch (InvalidOperationException) { - // SP-854: This can happen if the the list is still loading, "Collection was modified; enumeration operation may not execute." + // SP-854: This can happen if the list is still loading, "Collection was modified; enumeration operation may not execute." // Let the other thread continue and try again. Application.DoEvents(); Thread.Sleep(0); diff --git a/src/SayMore/UI/Charts/HTMLChartBuilder.cs b/src/SayMore/UI/Charts/HTMLChartBuilder.cs index 273a0f44..f24ce6c4 100644 --- a/src/SayMore/UI/Charts/HTMLChartBuilder.cs +++ b/src/SayMore/UI/Charts/HTMLChartBuilder.cs @@ -18,7 +18,7 @@ public class HTMLChartBuilder public const string kNonBreakingSpace = " "; private readonly StatisticsViewModel _statsViewModel; - protected readonly StringBuilder _htmlText = new StringBuilder(6000); + protected readonly StringBuilder _htmlText = new(6000); /// ------------------------------------------------------------------------------------ public HTMLChartBuilder(StatisticsViewModel statsViewModel) @@ -61,7 +61,7 @@ public string GetStatisticsCharts() WriteStageChart(); var backColors = GetStatusSegmentColors(); - var textColors = backColors.ToDictionary(kvp => kvp.Key, kvp => Color.Empty); + var textColors = backColors.ToDictionary(kvp => kvp.Key, _ => Color.Empty); text = LocalizationManager.GetString("ProgressView.ByGenreHeadingText", "By Genre"); WriteChartByFieldPair(text, SessionFileType.kGenreFieldName, SessionFileType.kStatusFieldName, backColors, textColors); @@ -91,8 +91,8 @@ private void WriteStageChart() var sessionsByStage = _statsViewModel.SessionInformant.GetSessionsCategorizedByStage() .Where(r => r.Key.Id != ComponentRole.kConsentComponentRoleId); - var barInfoList = (sessionsByStage.Select( - x => new ChartBarInfo(x.Key.Name, x.Value, x.Key.Color, x.Key.TextColor))).ToList(); + var barInfoList = sessionsByStage.Select( + x => new ChartBarInfo(x.Key.Name, x.Value, x.Key.Color, x.Key.TextColor)).ToList(); ChartBarInfo.CalculateBarSizes(barInfoList); var text = LocalizationManager.GetString("ProgressView.ByStagesHeadingText", "Completed Stages"); @@ -104,7 +104,7 @@ private IDictionary GetStatusSegmentColors() { var statusColors = new Dictionary(); - foreach (var statusName in Enum.GetNames(typeof(Session.Status)).Where(x => x != Session.Status.Skipped.ToString())) + foreach (var statusName in Enum.GetNames(typeof(Session.Status)).Where(x => x != nameof(Session.Status.Skipped))) { statusColors[Session.GetLocalizedStatus(statusName)] = (Color)Properties.Settings.Default[statusName + "StatusColor"]; @@ -135,9 +135,10 @@ private void WriteOverviewSection() foreach (var stats in _statsViewModel.GetComponentRoleStatisticsPairs()) { OpenTableRow(); - WriteTableRowHead(string.Format("{0}:", stats.Name)); - WriteTableCell(stats.Length); - WriteTableCell(stats.Size); + WriteTableRowHead($"{stats.Name}:"); + WriteTableCell(stats.Length.ToString()); + var size = stats.Size == 0 ? "---" : ComponentFile.GetDisplayableFileSize(stats.Size, false); + WriteTableCell(size); CloseTableRow(); } diff --git a/src/SayMore/UI/Overview/Statistics/StatisticsView.cs b/src/SayMore/UI/Overview/Statistics/StatisticsView.cs index 24285be1..83bb1d58 100644 --- a/src/SayMore/UI/Overview/Statistics/StatisticsView.cs +++ b/src/SayMore/UI/Overview/Statistics/StatisticsView.cs @@ -60,7 +60,7 @@ private void UpdateDisplay(ILocalizationManager lm = null) _webBrowser.DocumentStream?.Dispose(); UpdateStatusDisplay(true); - Thread updateDisplayThread = new Thread(() => + var updateDisplayThread = new Thread(() => { var htmlData = new MemoryStream(Encoding.UTF8.GetBytes(_model.HTMLString)); @@ -179,8 +179,7 @@ void HandleNewDataAvailable(object sender, EventArgs e) { // Can't actually call UpdateDisplay from here because this event is fired from // a background (data gathering) thread and updating the browser control on the - // background thread is a no-no. UpdateDisplay will be called when the timer - // tick fires. + // background thread is a no-no. BeginInvoke(new Action(() => UpdateDisplay())); } diff --git a/src/SayMore/UI/Overview/Statistics/StatisticsViewModel.cs b/src/SayMore/UI/Overview/Statistics/StatisticsViewModel.cs index 56961419..44ce0b61 100644 --- a/src/SayMore/UI/Overview/Statistics/StatisticsViewModel.cs +++ b/src/SayMore/UI/Overview/Statistics/StatisticsViewModel.cs @@ -17,7 +17,7 @@ public class StatisticsViewModel : IDisposable public event EventHandler FinishedGatheringStatisticsForAllFiles; private readonly IEnumerable _componentRoles; - private readonly AudioVideoDataGatherer _backgroundStatisticsGather; + private readonly AudioVideoDataGatherer _backgroundStatisticsGatherer; protected HTMLChartBuilder _chartBuilder; public PersonInformant PersonInformant { get; protected set; } @@ -28,16 +28,18 @@ public class StatisticsViewModel : IDisposable /// ------------------------------------------------------------------------------------ public StatisticsViewModel(Project project, PersonInformant personInformant, SessionWorkflowInformant sessionInformant, IEnumerable componentRoles, - AudioVideoDataGatherer backgroundStatisticsMananager) + AudioVideoDataGatherer backgroundStatisticsManager) { - ProjectName = (project == null ? string.Empty : project.Name); - ProjectPath = (project == null ? string.Empty : project.FolderPath); + ProjectName = project?.Name ?? string.Empty; + ProjectPath = project?.FolderPath ?? string.Empty; PersonInformant = personInformant; SessionInformant = sessionInformant; _componentRoles = componentRoles; - _backgroundStatisticsGather = backgroundStatisticsMananager; - _backgroundStatisticsGather.NewDataAvailable += HandleNewStatistics; - _backgroundStatisticsGather.FinishedProcessingAllFiles += HandleFinishedGatheringStatisticsForAllFiles; + _backgroundStatisticsGatherer = backgroundStatisticsManager; + _backgroundStatisticsGatherer.NewDataAvailable += HandleNewStatistics; + _backgroundStatisticsGatherer.FinishedProcessingAllFiles += HandleFinishedGatheringStatisticsForAllFiles; + + project?.TrackStatistics(this); _chartBuilder = new HTMLChartBuilder(this); } @@ -45,33 +47,21 @@ public StatisticsViewModel(Project project, PersonInformant personInformant, /// ------------------------------------------------------------------------------------ public void Dispose() { - _backgroundStatisticsGather.NewDataAvailable -= HandleNewStatistics; - _backgroundStatisticsGather.FinishedProcessingAllFiles -= HandleFinishedGatheringStatisticsForAllFiles; + _backgroundStatisticsGatherer.NewDataAvailable -= HandleNewStatistics; + _backgroundStatisticsGatherer.FinishedProcessingAllFiles -= HandleFinishedGatheringStatisticsForAllFiles; } /// ------------------------------------------------------------------------------------ - public string Status - { - get { return _backgroundStatisticsGather.Status; } - } + public string Status => _backgroundStatisticsGatherer.Status; /// ------------------------------------------------------------------------------------ - public bool IsDataUpToDate - { - get { return _backgroundStatisticsGather.DataUpToDate; } - } + public bool IsDataUpToDate => _backgroundStatisticsGatherer.DataUpToDate; /// ------------------------------------------------------------------------------------ - public bool IsBusy - { - get { return _backgroundStatisticsGather.Busy; } - } + public bool IsBusy => _backgroundStatisticsGatherer.Busy; /// ------------------------------------------------------------------------------------ - public string HTMLString - { - get { return _chartBuilder.GetStatisticsCharts(); } - } + public string HTMLString => _chartBuilder.GetStatisticsCharts(); /// ------------------------------------------------------------------------------------ public IEnumerable> GetElementStatisticsPairs() @@ -89,13 +79,12 @@ public IEnumerable GetComponentRoleStatisticsPairs() foreach (var role in _componentRoles.Where(def => def.MeasurementType == ComponentRole.MeasurementTypes.Time)) { long bytes = GetTotalComponentRoleFileSizes(role); - var size = (bytes == 0 ? "---" : ComponentFile.GetDisplayableFileSize(bytes, false)); yield return new ComponentRoleStatistics { Name = role.Name, - Length = GetRecordingDurations(role).ToString(), - Size = size + Length = GetRecordingDurations(role), + Size = bytes }; } } @@ -121,7 +110,7 @@ private IEnumerable GetFilteredFileData(ComponentRole role) { var comparer = new SourceAndStandardAudioCoalescingComparer(); // SP-2171: i.MediaFilePath will be empty if the file is zero length (see MediaFileInfo.GetInfo()). This happens often with the generated oral annotation file. - return _backgroundStatisticsGather.GetAllFileData() + return _backgroundStatisticsGatherer.GetAllFileData() .Where(i => !string.IsNullOrEmpty(i.MediaFilePath) && !i.MediaFilePath.EndsWith(Settings.Default.OralAnnotationGeneratedFileSuffix) && role.IsMatch(i.MediaFilePath)) .Distinct(comparer); @@ -130,28 +119,26 @@ private IEnumerable GetFilteredFileData(ComponentRole role) /// ------------------------------------------------------------------------------------ public void Refresh() { - _backgroundStatisticsGather.Restart(); + _backgroundStatisticsGatherer.Restart(); } /// ------------------------------------------------------------------------------------ void HandleNewStatistics(object sender, EventArgs e) { - if (NewStatisticsAvailable != null) - NewStatisticsAvailable(this, EventArgs.Empty); + NewStatisticsAvailable?.Invoke(this, EventArgs.Empty); } /// ------------------------------------------------------------------------------------ void HandleFinishedGatheringStatisticsForAllFiles(object sender, EventArgs e) { - if (FinishedGatheringStatisticsForAllFiles != null) - FinishedGatheringStatisticsForAllFiles(this, EventArgs.Empty); + FinishedGatheringStatisticsForAllFiles?.Invoke(this, EventArgs.Empty); } } public class ComponentRoleStatistics { public string Name { get; set; } - public string Length { get; set; } - public string Size { get; set; } + public TimeSpan Length { get; set; } + public long Size { get; set; } } } \ No newline at end of file From bbdb5e1e962cdb4c941001d01c9260bf0ac6db5e Mon Sep 17 00:00:00 2001 From: tombogle Date: Tue, 6 Jan 2026 09:50:03 -0500 Subject: [PATCH 03/29] Updated copyright to 2026 --- DistFiles/aboutBox.htm | 2 +- src/SayMore/Properties/AssemblyInfo.cs | 2 +- src/SayMore/UI/SplashScreenForm.Designer.cs | 2 +- src/SayMoreTests/Properties/AssemblyInfo.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DistFiles/aboutBox.htm b/DistFiles/aboutBox.htm index 718f9034..d251279a 100644 --- a/DistFiles/aboutBox.htm +++ b/DistFiles/aboutBox.htm @@ -7,7 +7,7 @@ -

Copyright © 2011-2025 SIL Global

+

Copyright © 2011-2026 SIL Global

License

Open source (MIT).

diff --git a/src/SayMore/Properties/AssemblyInfo.cs b/src/SayMore/Properties/AssemblyInfo.cs index dd2e5029..59b87d0a 100644 --- a/src/SayMore/Properties/AssemblyInfo.cs +++ b/src/SayMore/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("SIL Global")] [assembly: AssemblyProduct("SayMore")] -[assembly: AssemblyCopyright("Copyright © 2011-2025 SIL Global")] +[assembly: AssemblyCopyright("Copyright © 2011-2026 SIL Global")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/src/SayMore/UI/SplashScreenForm.Designer.cs b/src/SayMore/UI/SplashScreenForm.Designer.cs index eaae9199..d7c0771f 100644 --- a/src/SayMore/UI/SplashScreenForm.Designer.cs +++ b/src/SayMore/UI/SplashScreenForm.Designer.cs @@ -188,7 +188,7 @@ private void InitializeComponent() this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(126, 13); this.label1.TabIndex = 7; - this.label1.Text = "© 2011-2025 SIL Global"; + this.label1.Text = "© 2011-2026 SIL Global"; // // SplashScreenForm // diff --git a/src/SayMoreTests/Properties/AssemblyInfo.cs b/src/SayMoreTests/Properties/AssemblyInfo.cs index 0207a0b4..d890f930 100644 --- a/src/SayMoreTests/Properties/AssemblyInfo.cs +++ b/src/SayMoreTests/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SayMoreTests")] -[assembly: AssemblyCopyright("Copyright © 2025")] +[assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] From 57680240b862ecafa94aa178fc898a7b713439ae Mon Sep 17 00:00:00 2001 From: tombogle Date: Tue, 6 Jan 2026 10:07:53 -0500 Subject: [PATCH 04/29] Fixed problems when stats are not fully initialized --- src/SayMore/Model/Project.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/SayMore/Model/Project.cs b/src/SayMore/Model/Project.cs index 7512d4d0..8752271c 100644 --- a/src/SayMore/Model/Project.cs +++ b/src/SayMore/Model/Project.cs @@ -183,6 +183,7 @@ public void Dispose() bool hasProgress = sessionDelta > 0 || personDelta > 0 || + _mediaDurationStats != null && _mediaDurationStats.Values.Any(s => s.Delta > TimeSpan.Zero); if (hasProgress) @@ -195,13 +196,16 @@ public void Dispose() if (personDelta > 0) properties["PersonsAdded"] = personDelta.ToString(); - foreach (var kvp in _mediaDurationStats) + if (_mediaDurationStats != null) { - var delta = kvp.Value.Delta; - if (delta > TimeSpan.Zero) + foreach (var kvp in _mediaDurationStats) { - properties[$"MediaDurationAdded.{kvp.Key}"] = - delta.TotalSeconds.ToString("F0"); + var delta = kvp.Value.Delta; + if (delta > TimeSpan.Zero) + { + properties[$"MediaDurationAdded.{kvp.Key}"] = + delta.TotalSeconds.ToString("F0"); + } } } @@ -878,8 +882,8 @@ public void TrackStatistics(StatisticsViewModel statisticsViewModel) private void FinishedGatheringStatistics(object sender, EventArgs e) { _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; - _initialNumberOfSessions = _statisticsViewModel.SessionInformant.NumberOfSessions; - _initialNumberOfPersons = _statisticsViewModel.PersonInformant.NumberOfPeople; + _initialNumberOfSessions = _finalNumberOfSessions = _statisticsViewModel.SessionInformant.NumberOfSessions; + _initialNumberOfPersons = _finalNumberOfPersons = _statisticsViewModel.PersonInformant.NumberOfPeople; _mediaDurationStats = _statisticsViewModel.GetComponentRoleStatisticsPairs() .ToDictionary( From edbca9f03c546035eac0cdcaf5fcad61e146b7c3 Mon Sep 17 00:00:00 2001 From: tombogle Date: Mon, 12 Jan 2026 17:00:28 -0500 Subject: [PATCH 05/29] Upgraded SIL.DesktopAnalytics Also, added missing DLL to Installer --- build/SayMore.proj | 2 +- build/TestInstallerBuild.bat | 2 +- src/Installer/Installer.wxs | 5 +++++ src/SayMore/SayMore.csproj | 10 ++++++---- src/SayMoreTests/SayMoreTests.csproj | 8 ++++---- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/build/SayMore.proj b/build/SayMore.proj index 41f09ed1..67dd4937 100644 --- a/build/SayMore.proj +++ b/build/SayMore.proj @@ -14,7 +14,7 @@ $(RootDir)/packages/ 16.2.0 $(NuGetPackageRoot)SIL.libpalaso.l10ns/$(PalasoL10nsVersion)/ - $(NuGetPackageRoot)SIL.ReleaseTasks/3.1.1/build/SIL.ReleaseTasks.props + $(NuGetPackageRoot)SIL.ReleaseTasks/3.2.0/build/SIL.ReleaseTasks.props $(LocalPackagesRoot)SIL.BuildTasks/ $(BuildTasksVersionFolder)tools/SIL.BuildTasks.dll $(BuildTasksVersionFolder)build/SIL.BuildTasks.props diff --git a/build/TestInstallerBuild.bat b/build/TestInstallerBuild.bat index c78ef84d..f92a4bfb 100644 --- a/build/TestInstallerBuild.bat +++ b/build/TestInstallerBuild.bat @@ -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 \ No newline at end of file diff --git a/src/Installer/Installer.wxs b/src/Installer/Installer.wxs index 01071197..b2a7137e 100644 --- a/src/Installer/Installer.wxs +++ b/src/Installer/Installer.wxs @@ -200,6 +200,10 @@ are trying to support, you're better off using non-advertised shortcuts. "--> + + + + @@ -378,6 +382,7 @@ are trying to support, you're better off using non-advertised shortcuts. "--> + diff --git a/src/SayMore/SayMore.csproj b/src/SayMore/SayMore.csproj index 10bcf972..a380f6ae 100644 --- a/src/SayMore/SayMore.csproj +++ b/src/SayMore/SayMore.csproj @@ -40,7 +40,7 @@ - + @@ -51,10 +51,10 @@ - + - + All @@ -62,11 +62,13 @@ + + - + diff --git a/src/SayMoreTests/SayMoreTests.csproj b/src/SayMoreTests/SayMoreTests.csproj index 2799d699..93fb5024 100644 --- a/src/SayMoreTests/SayMoreTests.csproj +++ b/src/SayMoreTests/SayMoreTests.csproj @@ -67,7 +67,7 @@ - + @@ -78,13 +78,13 @@ - + - - + + From 016fab77497744ccdae1fbb28fd16a255f59b790 Mon Sep 17 00:00:00 2001 From: tombogle Date: Mon, 12 Jan 2026 23:07:57 -0500 Subject: [PATCH 06/29] Unified on System.Text.Json 9.0.0 to prevent runtime failure: Could not load file or assembly 'System.Text.Json, Version=9.0.0.0' --- src/SayMore/SayMore.csproj | 1 + src/SayMoreTests/SayMoreTests.csproj | 1 + 2 files changed, 2 insertions(+) diff --git a/src/SayMore/SayMore.csproj b/src/SayMore/SayMore.csproj index a380f6ae..c5a58b90 100644 --- a/src/SayMore/SayMore.csproj +++ b/src/SayMore/SayMore.csproj @@ -69,6 +69,7 @@ + diff --git a/src/SayMoreTests/SayMoreTests.csproj b/src/SayMoreTests/SayMoreTests.csproj index 93fb5024..b2b02d7b 100644 --- a/src/SayMoreTests/SayMoreTests.csproj +++ b/src/SayMoreTests/SayMoreTests.csproj @@ -86,6 +86,7 @@ + From c71c5fd0cd283e53300ac3b689a877ff8b305f15 Mon Sep 17 00:00:00 2001 From: tombogle Date: Tue, 13 Jan 2026 01:12:04 -0500 Subject: [PATCH 07/29] Improved installer to avoid picking up older DLL versions referenced by tests Added explicit method to call to report project progress. Included advances in completed stages in project progress analytics --- src/Installer/Installer.wxs | 15 +++--- .../DataGathering/BackgroundFileProcessor.cs | 5 +- src/SayMore/Model/Files/FieldUpdater.cs | 3 +- src/SayMore/Model/Project.cs | 53 +++++++++++++++++-- src/SayMore/Program.cs | 6 ++- 5 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/Installer/Installer.wxs b/src/Installer/Installer.wxs index b2a7137e..3ebcb56b 100644 --- a/src/Installer/Installer.wxs +++ b/src/Installer/Installer.wxs @@ -6,7 +6,8 @@ - + + @@ -345,22 +346,22 @@ are trying to support, you're better off using non-advertised shortcuts. "--> - + - + - + - + - + - + diff --git a/src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs b/src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs index 6793371e..1fd0cbff 100644 --- a/src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs +++ b/src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs @@ -388,8 +388,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 WalkDirectoryTree(string topLevelFolder, SearchOption searchOption) @@ -418,7 +417,7 @@ private static List 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); diff --git a/src/SayMore/Model/Files/FieldUpdater.cs b/src/SayMore/Model/Files/FieldUpdater.cs index 2aa949b5..976b610c 100644 --- a/src/SayMore/Model/Files/FieldUpdater.cs +++ b/src/SayMore/Model/Files/FieldUpdater.cs @@ -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) { diff --git a/src/SayMore/Model/Project.cs b/src/SayMore/Model/Project.cs index 8752271c..731fb012 100644 --- a/src/SayMore/Model/Project.cs +++ b/src/SayMore/Model/Project.cs @@ -29,6 +29,7 @@ using SIL.Reporting; using SIL.Windows.Forms; using static System.IO.Path; +using static SayMore.Model.Files.ComponentRole.MeasurementTypes; namespace SayMore.Model { @@ -77,8 +78,16 @@ private sealed class MediaDurationStats(TimeSpan initial) public TimeSpan Delta => Current - Initial; } - + private sealed class RoleCountStats(int initial) + { + public int Initial { get; } = initial; + public int Current { get; set; } = initial; + + public int Delta => Current - Initial; + } + private Dictionary _mediaDurationStats; + private Dictionary _sessionRoleStats; public delegate Project Factory(string desiredOrExistingFilePath); @@ -170,7 +179,7 @@ public Project(string desiredOrExistingSettingsFilePath, } /// ------------------------------------------------------------------------------------ - public void Dispose() + public void ReportProgressIfNeeded() { if (_statisticsViewModel != null) { @@ -184,7 +193,9 @@ public void Dispose() sessionDelta > 0 || personDelta > 0 || _mediaDurationStats != null && - _mediaDurationStats.Values.Any(s => s.Delta > TimeSpan.Zero); + _mediaDurationStats.Values.Any(s => s.Delta > TimeSpan.Zero) || + _sessionRoleStats != null && + _sessionRoleStats.Values.Any(s => s.Delta > 0); ; if (hasProgress) { @@ -208,11 +219,28 @@ public void Dispose() } } } + + if (_sessionRoleStats != null) + { + foreach (var kvp in _sessionRoleStats) + { + var delta = kvp.Value.Delta; + if (delta > 0) + { + properties[$"CompletedStages.{kvp.Key}"] = + delta.ToString(); + } + } + } Analytics.Track("ProjectProgress", properties); } } + } + /// ------------------------------------------------------------------------------------ + public void Dispose() + { _sessionsRepoFactory = null; if (_needToDisposeTranscriptionFont) TranscriptionFont.Dispose(); @@ -890,6 +918,10 @@ private void FinishedGatheringStatistics(object sender, EventArgs e) s => s.Name, s => new MediaDurationStats(s.Length)); + _sessionRoleStats = _statisticsViewModel.SessionInformant.GetSessionsCategorizedByStage() + .Where(s => s.Key.MeasurementType != Time) + .ToDictionary(s => s.Key.Id, s => new RoleCountStats(s.Value.Count())); + _statisticsViewModel.NewStatisticsAvailable += UpdateStatistics; } @@ -911,6 +943,21 @@ private void UpdateStatistics(object sender, EventArgs e) }; } } + + foreach (var stat in _statisticsViewModel.SessionInformant.GetSessionsCategorizedByStage() + .Where(s => s.Key.MeasurementType != Time)) + { + if (_sessionRoleStats.TryGetValue(stat.Key.Id, out var entry)) + entry.Current = stat.Value.Count(); + else + { + _sessionRoleStats[stat.Key.Id] = + new RoleCountStats(0) + { + Current = stat.Value.Count() + }; + } + } } } } diff --git a/src/SayMore/Program.cs b/src/SayMore/Program.cs index af639de5..680a8d22 100644 --- a/src/SayMore/Program.cs +++ b/src/SayMore/Program.cs @@ -235,6 +235,8 @@ static void Main() { Application.Run(); Settings.Default.Save(); + _projectContext?.Project.ReportProgressIfNeeded(); + Analytics.FlushClient(); Logger.WriteEvent("SayMore shutting down"); if (s_countOfContiguousFirstChanceOutOfMemoryExceptions > 1) Logger.WriteEvent("Total number of contiguous OutOfMemoryExceptions: {0}", s_countOfContiguousFirstChanceOutOfMemoryExceptions); @@ -596,8 +598,10 @@ static void ChooseAnotherProject(object sender, EventArgs e) } /// ------------------------------------------------------------------------------------ - static void HandleProjectWindowClosed(object sender, EventArgs e) + private static void HandleProjectWindowClosed(object sender, EventArgs e) { + _projectContext?.Project.ReportProgressIfNeeded(); + SafelyDisposeProjectContext(); ReleaseMutexForThisProject(); From ff5e8632ac5202459c8fa0cd3612f3a1f4b4d9d0 Mon Sep 17 00:00:00 2001 From: tombogle Date: Tue, 13 Jan 2026 10:49:12 -0500 Subject: [PATCH 08/29] Revert errant installer change Deal with race condition to be able to track progress reliably. Remove unnecessary tracking of intermediate updates. --- src/Installer/Installer.wxs | 4 +- .../DataGathering/BackgroundFileProcessor.cs | 14 +- src/SayMore/Model/Project.cs | 360 +++++++++--------- src/SayMore/Program.cs | 4 +- .../Statistics/StatisticsViewModel.cs | 2 +- 5 files changed, 200 insertions(+), 184 deletions(-) diff --git a/src/Installer/Installer.wxs b/src/Installer/Installer.wxs index 3ebcb56b..d0bf3ed8 100644 --- a/src/Installer/Installer.wxs +++ b/src/Installer/Installer.wxs @@ -6,8 +6,8 @@ - - + + diff --git a/src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs b/src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs index 1fd0cbff..c3e984d6 100644 --- a/src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs +++ b/src/SayMore/Model/Files/DataGathering/BackgroundFileProcessor.cs @@ -122,9 +122,11 @@ protected virtual bool GetDoIncludeFile(string path) /// ------------------------------------------------------------------------------------ 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(); } @@ -140,7 +142,7 @@ 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)) { @@ -175,7 +177,7 @@ private void StartWorking() } catch (ThreadAbortException) { - //this is fine, it happens when we quit + // This is fine, it happens when we quit } catch (Exception error) { @@ -339,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(); diff --git a/src/SayMore/Model/Project.cs b/src/SayMore/Model/Project.cs index 731fb012..f191b18e 100644 --- a/src/SayMore/Model/Project.cs +++ b/src/SayMore/Model/Project.cs @@ -66,28 +66,117 @@ public class Project : IAutoSegmenterSettings, IRAMPArchivable, IDisposable private Font _workingLanguageFont; private bool _needToDisposeWorkingLanguageFont; - private StatisticsViewModel _statisticsViewModel; - private int _initialNumberOfSessions; - private int _finalNumberOfSessions; - private int _initialNumberOfPersons; - private int _finalNumberOfPersons; - private sealed class MediaDurationStats(TimeSpan initial) + private sealed class ProgressStats { - public TimeSpan Initial { get; } = initial; - public TimeSpan Current { get; set; } = initial; + private readonly StatisticsViewModel _model; + + private readonly int _initialNumberOfSessions; + private readonly int _initialNumberOfPersons; - public TimeSpan Delta => Current - Initial; - } - private sealed class RoleCountStats(int initial) - { - public int Initial { get; } = initial; - public int Current { get; set; } = initial; + private sealed class MediaDurationStats(TimeSpan initial) + { + private TimeSpan Initial { get; } = initial; + public TimeSpan Current { get; set; } = initial; + + public TimeSpan Delta => Current - Initial; + } + + private sealed class RoleCountStats(int initial) + { + private int Initial { get; } = initial; + public int Current { get; set; } = initial; + + public int Delta => Current - Initial; + } + + private readonly Dictionary _mediaDurationStats; + private readonly Dictionary _sessionRoleStats; + + internal ProgressStats(StatisticsViewModel model) + { + _model = model; + + _initialNumberOfSessions = _model.SessionInformant.NumberOfSessions; + _initialNumberOfPersons = _model.PersonInformant.NumberOfPeople; + _mediaDurationStats = _model.GetComponentRoleStatisticsPairs() + .ToDictionary(s => s.Name, s => new MediaDurationStats(s.Length)); + + _sessionRoleStats = _model.SessionInformant.GetSessionsCategorizedByStage() + .Where(s => s.Key.MeasurementType != Time) + .ToDictionary(s => s.Key.Id, s => new RoleCountStats(s.Value.Count())); + } + + internal void ReportUpdatedStatistics() + { + if (_model.IsBusy) + Thread.Sleep(200); // Give it a fighting chance to finish. + + var sessionDelta = _model.SessionInformant.NumberOfSessions - _initialNumberOfSessions; + var personDelta = _model.PersonInformant.NumberOfPeople - _initialNumberOfPersons; + + foreach (var stat in _model.GetComponentRoleStatisticsPairs()) + { + if (_mediaDurationStats.TryGetValue(stat.Name, out var entry)) + entry.Current = stat.Length; + else + { + _mediaDurationStats[stat.Name] = + new MediaDurationStats(TimeSpan.Zero) + { + Current = stat.Length + }; + } + } + + foreach (var stat in _model.SessionInformant.GetSessionsCategorizedByStage() + .Where(s => s.Key.MeasurementType != Time)) + { + if (_sessionRoleStats.TryGetValue(stat.Key.Id, out var entry)) + entry.Current = stat.Value.Count(); + else + { + _sessionRoleStats[stat.Key.Id] = new RoleCountStats(0) + { + Current = stat.Value.Count() + }; + } + } + + var properties = new Dictionary(); + + if (sessionDelta > 0) + properties["SessionsAdded"] = sessionDelta.ToString(); + + if (personDelta > 0) + properties["PersonsAdded"] = personDelta.ToString(); + + foreach (var kvp in _mediaDurationStats) + { + var delta = kvp.Value.Delta; + if (delta > TimeSpan.Zero) + { + properties[$"MediaDurationAdded.{kvp.Key}"] = + delta.TotalSeconds.ToString("F0"); + } + } + + foreach (var kvp in _sessionRoleStats) + { + var delta = kvp.Value.Delta; + if (delta > 0) + { + properties[$"CompletedStages.{kvp.Key}"] = + delta.ToString(); + } + } - public int Delta => Current - Initial; + if (properties.Any()) + Analytics.Track("ProjectProgress", properties); + } } - private Dictionary _mediaDurationStats; - private Dictionary _sessionRoleStats; + private StatisticsViewModel _statisticsViewModel; + private ProgressStats _progressStats; public delegate Project Factory(string desiredOrExistingFilePath); @@ -179,68 +268,35 @@ public Project(string desiredOrExistingSettingsFilePath, } /// ------------------------------------------------------------------------------------ - public void ReportProgressIfNeeded() + public void ReportProgressIfAny() { - if (_statisticsViewModel != null) - { - _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; - _statisticsViewModel.NewStatisticsAvailable -= UpdateStatistics; - - var sessionDelta = _finalNumberOfSessions - _initialNumberOfSessions; - var personDelta = _finalNumberOfPersons - _initialNumberOfPersons; - - bool hasProgress = - sessionDelta > 0 || - personDelta > 0 || - _mediaDurationStats != null && - _mediaDurationStats.Values.Any(s => s.Delta > TimeSpan.Zero) || - _sessionRoleStats != null && - _sessionRoleStats.Values.Any(s => s.Delta > 0); ; - - if (hasProgress) - { - var properties = new Dictionary(); - - if (sessionDelta > 0) - properties["SessionsAdded"] = sessionDelta.ToString(); - - if (personDelta > 0) - properties["PersonsAdded"] = personDelta.ToString(); + if (_statisticsViewModel == null) + return; + + _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; - if (_mediaDurationStats != null) - { - foreach (var kvp in _mediaDurationStats) - { - var delta = kvp.Value.Delta; - if (delta > TimeSpan.Zero) - { - properties[$"MediaDurationAdded.{kvp.Key}"] = - delta.TotalSeconds.ToString("F0"); - } - } - } - - if (_sessionRoleStats != null) - { - foreach (var kvp in _sessionRoleStats) - { - var delta = kvp.Value.Delta; - if (delta > 0) - { - properties[$"CompletedStages.{kvp.Key}"] = - delta.ToString(); - } - } - } + // Really unlikely, but if we get here before the initial gathering is done, we can't do anything. + if (_progressStats == null) + return; - Analytics.Track("ProjectProgress", properties); - } + try + { + _progressStats.ReportUpdatedStatistics(); } + catch (ObjectDisposedException e) + { + // This probably should be impossible, but just in case, we don't want reporting stats to + // crash the program. + Logger.WriteError(e); + } + _progressStats = null; // This ensures we only report once per project open. } /// ------------------------------------------------------------------------------------ public void Dispose() { + _progressStats = null; // Probably already done, but it also had a copy of _statisticsViewModel. + _statisticsViewModel?.Dispose(); _sessionsRepoFactory = null; if (_needToDisposeTranscriptionFont) TranscriptionFont.Dispose(); @@ -423,54 +479,6 @@ public void Save() _accessProtocolChanged = false; } - /// ------------------------------------------------------------------------------------ - public string GetFileDescription(string key, string file) - { - var description = (key == string.Empty ? "SayMore Session File" : "SayMore Contributor File"); - - if (file.ToLower().EndsWith(Settings.Default.SessionFileExtension)) - description = "SayMore Session Metadata (XML)"; - else if (file.ToLower().EndsWith(Settings.Default.PersonFileExtension)) - description = "SayMore Contributor Metadata (XML)"; - else if (file.ToLower().EndsWith(Settings.Default.MetadataFileExtension)) - description = "SayMore File Metadata (XML)"; - - return description; - } - - /// ------------------------------------------------------------------------------------ - public void SetAdditionalMetsData(RampArchivingDlgViewModel model) - { - foreach (var session in GetAllSessions(CancellationToken.None)) - { - model.SetScholarlyWorkType(ScholarlyWorkType.PrimaryData); - model.SetDomains(SilDomain.Ling_LanguageDocumentation); - - var value = session.MetaDataFile.GetStringValue(SessionFileType.kDateFieldName, null); - if (!string.IsNullOrEmpty(value)) - model.SetCreationDate(value); - - // Return the session's note as the abstract portion of the package's description. - value = session.MetaDataFile.GetStringValue(SessionFileType.kSynopsisFieldName, null); - if (!string.IsNullOrEmpty(value)) - model.SetAbstract(value, string.Empty); - - // Set contributors - var contribsVal = session.MetaDataFile.GetValue(SessionFileType.kContributionsFieldName, null); - if (contribsVal is ContributionCollection contributions && contributions.Count > 0) - model.SetContributors(contributions); - - // Return total duration of source audio/video recordings. - TimeSpan totalDuration = session.GetTotalDurationOfSourceMedia(); - if (totalDuration.Ticks > 0) - model.SetAudioVideoExtent($"Total Length of Source Recordings: {totalDuration}"); - - //First session details are enough for "Archive RAMP (SIL)..." from Project menu - break; - } - } - - /// ------------------------------------------------------------------------------------ public void Load() { @@ -578,26 +586,26 @@ private static string GetFontErrorMessage(string description, string settingValu } /// ------------------------------------------------------------------------------------ - private string GetStringSettingValue(XElement project, string elementName, string defaultValue) + private static string GetStringSettingValue(XElement project, string elementName, string defaultValue) { var element = project.Element(elementName); return element == null ? defaultValue : element.Value; } /// ------------------------------------------------------------------------------------ - private int GetIntAttributeValue(XElement project, string attribName, string fallbackAttribName = null) + private static int GetIntAttributeValue(XElement project, string attribName, string fallbackAttribName = null) { var attrib = project.Attribute(attribName); if (attrib == null && fallbackAttribName != null) attrib = project.Attribute(fallbackAttribName); - return (attrib != null && Int32.TryParse(attrib.Value, out var val)) ? val : default; + return attrib != null && Int32.TryParse(attrib.Value, out var val) ? val : 0; } /// ------------------------------------------------------------------------------------ - private double GetDoubleAttributeValue(XElement project, string attribName) + private static double GetDoubleAttributeValue(XElement project, string attribName) { var attrib = project.Attribute(attribName); - return (attrib != null && Double.TryParse(attrib.Value, out var val)) ? val : default; + return attrib != null && Double.TryParse(attrib.Value, out var val) ? val : 0; } /// ------------------------------------------------------------------------------------ @@ -653,6 +661,53 @@ internal IEnumerable GetAllSessions(CancellationToken cancellationToken } #region Archiving + /// ------------------------------------------------------------------------------------ + public string GetFileDescription(string key, string file) + { + var description = key == string.Empty ? "SayMore Session File" : "SayMore Contributor File"; + + if (file.ToLower().EndsWith(Settings.Default.SessionFileExtension)) + description = "SayMore Session Metadata (XML)"; + else if (file.ToLower().EndsWith(Settings.Default.PersonFileExtension)) + description = "SayMore Contributor Metadata (XML)"; + else if (file.ToLower().EndsWith(Settings.Default.MetadataFileExtension)) + description = "SayMore File Metadata (XML)"; + + return description; + } + + /// ------------------------------------------------------------------------------------ + public void SetAdditionalMetsData(RampArchivingDlgViewModel model) + { + foreach (var session in GetAllSessions(CancellationToken.None)) + { + model.SetScholarlyWorkType(ScholarlyWorkType.PrimaryData); + model.SetDomains(SilDomain.Ling_LanguageDocumentation); + + var value = session.MetaDataFile.GetStringValue(SessionFileType.kDateFieldName, null); + if (!string.IsNullOrEmpty(value)) + model.SetCreationDate(value); + + // Return the session's note as the abstract portion of the package's description. + value = session.MetaDataFile.GetStringValue(SessionFileType.kSynopsisFieldName, null); + if (!string.IsNullOrEmpty(value)) + model.SetAbstract(value, string.Empty); + + // Set contributors + var contribsVal = session.MetaDataFile.GetValue(SessionFileType.kContributionsFieldName, null); + if (contribsVal is ContributionCollection contributions && contributions.Count > 0) + model.SetContributors(contributions); + + // Return total duration of source audio/video recordings. + TimeSpan totalDuration = session.GetTotalDurationOfSourceMedia(); + if (totalDuration.Ticks > 0) + model.SetAudioVideoExtent($"Total Length of Source Recordings: {totalDuration}"); + + //First session details are enough for "Archive RAMP (SIL)..." from Project menu + break; + } + } + /// ------------------------------------------------------------------------------------ public string ArchiveInfoDetails => LocalizationManager.GetString("DialogBoxes.ArchivingDlg.ProjectArchivingInfoDetails", @@ -898,66 +953,25 @@ public IEnumerable GetSessionFilesToArchive(Type typeOfArchive, public void TrackStatistics(StatisticsViewModel statisticsViewModel) { if (_statisticsViewModel != null) - { _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; - _statisticsViewModel.NewStatisticsAvailable -= UpdateStatistics; - } _statisticsViewModel = statisticsViewModel; _statisticsViewModel.FinishedGatheringStatisticsForAllFiles += FinishedGatheringStatistics; + if (_statisticsViewModel.IsDataUpToDate) + { + // It either finished before we could hook the event, or we hit the race condition. + FinishedGatheringStatistics(_statisticsViewModel, null); + } } private void FinishedGatheringStatistics(object sender, EventArgs e) { _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; - _initialNumberOfSessions = _finalNumberOfSessions = _statisticsViewModel.SessionInformant.NumberOfSessions; - _initialNumberOfPersons = _finalNumberOfPersons = _statisticsViewModel.PersonInformant.NumberOfPeople; - _mediaDurationStats = - _statisticsViewModel.GetComponentRoleStatisticsPairs() - .ToDictionary( - s => s.Name, - s => new MediaDurationStats(s.Length)); - - _sessionRoleStats = _statisticsViewModel.SessionInformant.GetSessionsCategorizedByStage() - .Where(s => s.Key.MeasurementType != Time) - .ToDictionary(s => s.Key.Id, s => new RoleCountStats(s.Value.Count())); + // Check for race condition (see above). + if (_progressStats != null) + return; - _statisticsViewModel.NewStatisticsAvailable += UpdateStatistics; - } - - private void UpdateStatistics(object sender, EventArgs e) - { - _finalNumberOfSessions = _statisticsViewModel.SessionInformant.NumberOfSessions; - _finalNumberOfPersons = _statisticsViewModel.PersonInformant.NumberOfPeople; - - foreach (var stat in _statisticsViewModel.GetComponentRoleStatisticsPairs()) - { - if (_mediaDurationStats.TryGetValue(stat.Name, out var entry)) - entry.Current = stat.Length; - else - { - _mediaDurationStats[stat.Name] = - new MediaDurationStats(TimeSpan.Zero) - { - Current = stat.Length - }; - } - } - - foreach (var stat in _statisticsViewModel.SessionInformant.GetSessionsCategorizedByStage() - .Where(s => s.Key.MeasurementType != Time)) - { - if (_sessionRoleStats.TryGetValue(stat.Key.Id, out var entry)) - entry.Current = stat.Value.Count(); - else - { - _sessionRoleStats[stat.Key.Id] = - new RoleCountStats(0) - { - Current = stat.Value.Count() - }; - } - } + _progressStats = new ProgressStats(_statisticsViewModel); } } } diff --git a/src/SayMore/Program.cs b/src/SayMore/Program.cs index 680a8d22..7f2a60dd 100644 --- a/src/SayMore/Program.cs +++ b/src/SayMore/Program.cs @@ -235,7 +235,7 @@ static void Main() { Application.Run(); Settings.Default.Save(); - _projectContext?.Project.ReportProgressIfNeeded(); + _projectContext?.Project.ReportProgressIfAny(); Analytics.FlushClient(); Logger.WriteEvent("SayMore shutting down"); if (s_countOfContiguousFirstChanceOutOfMemoryExceptions > 1) @@ -600,7 +600,7 @@ static void ChooseAnotherProject(object sender, EventArgs e) /// ------------------------------------------------------------------------------------ private static void HandleProjectWindowClosed(object sender, EventArgs e) { - _projectContext?.Project.ReportProgressIfNeeded(); + _projectContext?.Project.ReportProgressIfAny(); SafelyDisposeProjectContext(); ReleaseMutexForThisProject(); diff --git a/src/SayMore/UI/Overview/Statistics/StatisticsViewModel.cs b/src/SayMore/UI/Overview/Statistics/StatisticsViewModel.cs index 44ce0b61..80205b8b 100644 --- a/src/SayMore/UI/Overview/Statistics/StatisticsViewModel.cs +++ b/src/SayMore/UI/Overview/Statistics/StatisticsViewModel.cs @@ -36,8 +36,8 @@ public StatisticsViewModel(Project project, PersonInformant personInformant, SessionInformant = sessionInformant; _componentRoles = componentRoles; _backgroundStatisticsGatherer = backgroundStatisticsManager; - _backgroundStatisticsGatherer.NewDataAvailable += HandleNewStatistics; _backgroundStatisticsGatherer.FinishedProcessingAllFiles += HandleFinishedGatheringStatisticsForAllFiles; + _backgroundStatisticsGatherer.NewDataAvailable += HandleNewStatistics; project?.TrackStatistics(this); From ba0118120ec76814db240aa01ff447d72e3084b8 Mon Sep 17 00:00:00 2001 From: tombogle Date: Tue, 13 Jan 2026 16:02:03 -0500 Subject: [PATCH 09/29] Used locking to prevent race conditions in statistics reporting. --- src/SayMore/Model/Project.cs | 97 ++++++++++++------- .../UI/Overview/Statistics/StatisticsView.cs | 2 +- 2 files changed, 63 insertions(+), 36 deletions(-) diff --git a/src/SayMore/Model/Project.cs b/src/SayMore/Model/Project.cs index f191b18e..0565c585 100644 --- a/src/SayMore/Model/Project.cs +++ b/src/SayMore/Model/Project.cs @@ -65,7 +65,8 @@ public class Project : IAutoSegmenterSettings, IRAMPArchivable, IDisposable private bool _needToDisposeFreeTranslationFont; private Font _workingLanguageFont; private bool _needToDisposeWorkingLanguageFont; - + private bool _disposed = false; + private sealed class ProgressStats { private readonly StatisticsViewModel _model; @@ -175,6 +176,7 @@ internal void ReportUpdatedStatistics() } } + private readonly object _statisticsLock = new(); private StatisticsViewModel _statisticsViewModel; private ProgressStats _progressStats; @@ -270,33 +272,54 @@ public Project(string desiredOrExistingSettingsFilePath, /// ------------------------------------------------------------------------------------ public void ReportProgressIfAny() { - if (_statisticsViewModel == null) - return; - - _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; + if (Monitor.TryEnter(_statisticsLock, TimeSpan.FromMilliseconds(200))) + { + try + { + if (_statisticsViewModel == null) + return; - // Really unlikely, but if we get here before the initial gathering is done, we can't do anything. - if (_progressStats == null) - return; + _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; - try - { - _progressStats.ReportUpdatedStatistics(); - } - catch (ObjectDisposedException e) - { - // This probably should be impossible, but just in case, we don't want reporting stats to - // crash the program. - Logger.WriteError(e); + // Really unlikely, but if we get here before the initial gathering is done, we can't do anything. + if (_progressStats == null) + return; + + try + { + _progressStats.ReportUpdatedStatistics(); + } + catch (ObjectDisposedException e) + { + // This probably should be impossible, but just in case, we don't want reporting stats to + // crash the program. + Logger.WriteError(e); + } + _progressStats = null; // This ensures we only report once per project open. + } + finally + { + Monitor.Exit(_statisticsLock); + } } - _progressStats = null; // This ensures we only report once per project open. } /// ------------------------------------------------------------------------------------ public void Dispose() { - _progressStats = null; // Probably already done, but it also had a copy of _statisticsViewModel. - _statisticsViewModel?.Dispose(); + lock (_statisticsLock) + { + if (_disposed) + return; + + _disposed = true; + + _progressStats = null; + _progressStats = null; // Probably already done, but it also had a copy of _statisticsViewModel. + _statisticsViewModel?.Dispose(); + _statisticsViewModel = null; + } + _sessionsRepoFactory = null; if (_needToDisposeTranscriptionFont) TranscriptionFont.Dispose(); @@ -951,27 +974,31 @@ public IEnumerable GetSessionFilesToArchive(Type typeOfArchive, #endregion public void TrackStatistics(StatisticsViewModel statisticsViewModel) - { - if (_statisticsViewModel != null) - _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; - - _statisticsViewModel = statisticsViewModel; - _statisticsViewModel.FinishedGatheringStatisticsForAllFiles += FinishedGatheringStatistics; - if (_statisticsViewModel.IsDataUpToDate) + { + lock (_statisticsLock) { - // It either finished before we could hook the event, or we hit the race condition. - FinishedGatheringStatistics(_statisticsViewModel, null); + if (_statisticsViewModel != null) + _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; + + _statisticsViewModel = statisticsViewModel; + _statisticsViewModel.FinishedGatheringStatisticsForAllFiles += FinishedGatheringStatistics; + if (_statisticsViewModel.IsDataUpToDate) + { + // It finished before we could hook the event. + FinishedGatheringStatistics(_statisticsViewModel, null); + } } } private void FinishedGatheringStatistics(object sender, EventArgs e) { - _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; - // Check for race condition (see above). - if (_progressStats != null) - return; - - _progressStats = new ProgressStats(_statisticsViewModel); + lock (_statisticsLock) + { + _statisticsViewModel.FinishedGatheringStatisticsForAllFiles -= FinishedGatheringStatistics; + Debug.Assert(_progressStats == null); + + _progressStats = new ProgressStats(_statisticsViewModel); + } } } } diff --git a/src/SayMore/UI/Overview/Statistics/StatisticsView.cs b/src/SayMore/UI/Overview/Statistics/StatisticsView.cs index 83bb1d58..7869ac8a 100644 --- a/src/SayMore/UI/Overview/Statistics/StatisticsView.cs +++ b/src/SayMore/UI/Overview/Statistics/StatisticsView.cs @@ -130,7 +130,7 @@ public void HandlePrintButtonClicked(object sender, EventArgs e) regKey != null && ((string)regKey.GetValue("Print_Background", "no")).ToLowerInvariant() == "yes"; if (!isIEPageSetupSetToPrintingBkgndColor) - if (regKey != null) regKey.SetValue("Print_Background", "yes", RegistryValueKind.String); + regKey?.SetValue("Print_Background", "yes", RegistryValueKind.String); #endif _webBrowser.ShowPrintDialog(); From ede66945e1ae915ff8fe36965711c25042c4bf88 Mon Sep 17 00:00:00 2001 From: tombogle Date: Thu, 26 Feb 2026 11:38:12 -0500 Subject: [PATCH 10/29] Cleaned up some long-standing compiler warnings Updated copyright date in license file Added Crowdin to acknowledgments in aboutBox.htm --- DistFiles/aboutBox.htm | 2 +- DistFiles/license.rtf | Bin 1773 -> 1773 bytes .../UI/ElementListScreen/ElementListScreen.cs | 8 ----- src/SayMore/UI/LowLevelControls/ListPanel.cs | 31 ++++++++---------- .../model/ElementRepositoryTests.cs | 4 ++- .../model/Files/ComponentFileTests.cs | 4 ++- 6 files changed, 20 insertions(+), 29 deletions(-) diff --git a/DistFiles/aboutBox.htm b/DistFiles/aboutBox.htm index d251279a..59732553 100644 --- a/DistFiles/aboutBox.htm +++ b/DistFiles/aboutBox.htm @@ -38,7 +38,7 @@

Thanks

JetBrains for Resharper, which helps keep our C# code clean and agile, and TeamCity, which we use for continuous integration and builds.

Microsoft for Github, the repository where our open-source code is hosted for free, and also for free use of Visual Studio Community, our preferred IDE.

Atlassian, for a free open-source license for Jira, where we keep bug reports.

- +

Crowdin, for great on-line localization tools.

GitHub, for free hosting of our source code repository.

Open Source Components/Libraries

diff --git a/DistFiles/license.rtf b/DistFiles/license.rtf index 66edba3e1daa24c7c0d58709f260b5b2ddf8c8c6..060221cc01f11ef0462938efe15c34f7ab3a553f 100644 GIT binary patch delta 14 VcmaFM`<8dZ4kkvk%{!S)SO6~I1v~%% delta 14 VcmaFM`<8dZ4kkv^%{!S)SO6~C1v>x$ diff --git a/src/SayMore/UI/ElementListScreen/ElementListScreen.cs b/src/SayMore/UI/ElementListScreen/ElementListScreen.cs index 363580ab..2864fb01 100644 --- a/src/SayMore/UI/ElementListScreen/ElementListScreen.cs +++ b/src/SayMore/UI/ElementListScreen/ElementListScreen.cs @@ -79,7 +79,6 @@ protected void Initialize(Control tabControlHostControl, _elementsListPanel = elementsListPanel; _elementsListPanel.NewButtonClicked += HandleAddingNewElement; - _elementsListPanel.DeleteButtonClicked += HandleDeletingSelectedElements; _elementsListPanel.ListControl = _elementsGrid; _componentFilesControl = componentGrid; @@ -440,12 +439,6 @@ protected virtual bool DoesUserConfirmDeletingSelectedElements() return ConfirmRecycleDialog.JustConfirm(msg, itemCount > 1, kSayMoreLocalizationId); } - /// ------------------------------------------------------------------------------------ - protected virtual void HandleDeletingSelectedElements(object sender, EventArgs e) - { - DeleteSelectedElements(); - } - /// ------------------------------------------------------------------------------------ private void DeleteSelectedElements() { @@ -559,7 +552,6 @@ protected override void Dispose(bool disposing) _elementsGrid.SelectedElementChanged -= HandleSelectedElementChanged; _elementsListPanel.NewButtonClicked -= HandleAddingNewElement; - _elementsListPanel.DeleteButtonClicked -= HandleDeletingSelectedElements; var frm = FindForm(); if (frm != null) diff --git a/src/SayMore/UI/LowLevelControls/ListPanel.cs b/src/SayMore/UI/LowLevelControls/ListPanel.cs index 0883e475..d45b2ed3 100644 --- a/src/SayMore/UI/LowLevelControls/ListPanel.cs +++ b/src/SayMore/UI/LowLevelControls/ListPanel.cs @@ -11,15 +11,14 @@ namespace SayMore.UI.LowLevelControls { /// ---------------------------------------------------------------------------------------- /// - /// Control encapsulating a heading, list view and 'New'/'Delete' buttons. + /// Control encapsulating a heading, list view and 'New' button. /// /// ---------------------------------------------------------------------------------------- public partial class ListPanel : UserControl { public event EventHandler NewButtonClicked; - public event EventHandler DeleteButtonClicked; - private readonly List
/// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { TabText = LocalizationManager.GetString( @@ -277,7 +279,7 @@ protected override void HandleStringsLocalized(ILocalizationManager lm) "Generated Audio"); } - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } } } diff --git a/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.Designer.cs b/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.Designer.cs index d3cf53fe..75c9a2f2 100644 --- a/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.Designer.cs +++ b/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.Designer.cs @@ -48,7 +48,7 @@ private void InitializeComponent() this._buttonAutoSegmenterHelp = new System.Windows.Forms.Button(); this._cboAudacityLabelTier = new System.Windows.Forms.ComboBox(); this._labelAudacityLabelTier = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._tableLayoutGetStarted.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); this.SuspendLayout(); @@ -411,7 +411,7 @@ private void InitializeComponent() #endregion private System.Windows.Forms.TableLayoutPanel _tableLayoutGetStarted; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Label _labelSegmentationMethodQuestion; private System.Windows.Forms.Label _labelSegmentationMethod; private System.Windows.Forms.Label _labelIntroduction; diff --git a/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.cs b/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.cs index 35e07ddd..8c08ac6b 100644 --- a/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.cs +++ b/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.cs @@ -78,7 +78,7 @@ public override bool IsOKToShow } /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { @@ -93,7 +93,7 @@ protected override void HandleStringsLocalized(ILocalizationManager lm) } } - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } private void PopulateAudacityLabelTierItems() diff --git a/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.Designer.cs b/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.Designer.cs index 76bd6f71..54dce190 100644 --- a/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.Designer.cs +++ b/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.Designer.cs @@ -36,7 +36,7 @@ private void InitializeComponent() this._buttonCarefulSpeech = new System.Windows.Forms.ToolStripMenuItem(); this._buttonOralTranslation = new System.Windows.Forms.ToolStripMenuItem(); this._comboPlaybackSpeed = new System.Windows.Forms.ToolStripComboBox(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._splitter = new System.Windows.Forms.SplitContainer(); this._toolStrip.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); @@ -340,7 +340,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem _buttonOralTranslation; private System.Windows.Forms.ToolStripButton _buttonHelp; private System.Windows.Forms.ToolStripButton _buttonResegment; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.ToolStripDropDownButton _exportMenu; private System.Windows.Forms.ToolStripMenuItem _plainTextExportMenuItem; private System.Windows.Forms.ToolStripMenuItem _flexInterlinearExportMenuItem; diff --git a/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.cs b/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.cs index be222a49..bfb7fef3 100644 --- a/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.cs +++ b/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.cs @@ -7,7 +7,7 @@ using System.Linq; using DesktopAnalytics; using L10NSharp; -using L10NSharp.UI; +using L10NSharp.Windows.Forms; using SIL.Reporting; using SIL.Windows.Forms.Extensions; using SayMore.Media.Audio; @@ -19,6 +19,7 @@ using SayMore.Media.MPlayer; using SayMore.Model; using SayMore.Utilities; +using SIL.Windows.Forms; // ReSharper disable once CheckNamespace namespace SayMore.Transcription.UI @@ -454,7 +455,7 @@ private void HandleResegmentButtonClick(object sender, EventArgs e) /// Update the tab text in case it was localized. ///
/// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { @@ -462,7 +463,7 @@ protected override void HandleStringsLocalized(ILocalizationManager lm) "SessionsView.Transcription.TextAnnotationEditor.TabText", "Annotations"); } - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } private void OnExportElanMenuItem_Click(object sender, EventArgs e) diff --git a/src/SayMore/Transcription/UI/ExportToFieldWorksInterlinearDlg.Designer.cs b/src/SayMore/Transcription/UI/ExportToFieldWorksInterlinearDlg.Designer.cs index 6159516d..48b9be2b 100644 --- a/src/SayMore/Transcription/UI/ExportToFieldWorksInterlinearDlg.Designer.cs +++ b/src/SayMore/Transcription/UI/ExportToFieldWorksInterlinearDlg.Designer.cs @@ -1,4 +1,4 @@ -using L10NSharp.UI; +using L10NSharp.Windows.Forms.UIComponents; using L10NSharp.XLiffUtils; namespace SayMore.Transcription.UI @@ -17,11 +17,7 @@ partial class ExportToFieldWorksInterlinearDlg protected override void Dispose(bool disposing) { if (disposing && (components != null)) - { components.Dispose(); - - LocalizeItemDlg.StringsLocalized -= HandleStringsLocalized; - } base.Dispose(disposing); } @@ -43,7 +39,7 @@ private void InitializeComponent() this._comboTranslationWs = new System.Windows.Forms.ComboBox(); this._labelOverview = new System.Windows.Forms.Label(); this._labelImportInstructions = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._tableLayout.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); this.SuspendLayout(); @@ -249,7 +245,7 @@ private void InitializeComponent() private System.Windows.Forms.Label _labelFreeTranslationColumnHeadingText; private System.Windows.Forms.ComboBox _comboTranslationWs; private System.Windows.Forms.Label _labelOverview; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Label _labelImportInstructions; } } \ No newline at end of file diff --git a/src/SayMore/Transcription/UI/ExportToFieldWorksInterlinearDlg.cs b/src/SayMore/Transcription/UI/ExportToFieldWorksInterlinearDlg.cs index 11c68347..dc8ec4e7 100644 --- a/src/SayMore/Transcription/UI/ExportToFieldWorksInterlinearDlg.cs +++ b/src/SayMore/Transcription/UI/ExportToFieldWorksInterlinearDlg.cs @@ -1,6 +1,4 @@ using L10NSharp; -using L10NSharp.UI; -using L10NSharp.XLiffUtils; using SayMore.Properties; using SIL.Reporting; using SIL.WritingSystems; @@ -31,7 +29,7 @@ public class DisplayFriendlyWritingSystem #endregion - private string _intructionsFmt; + private string _instructionsFmt; public string FileName { get; private set; } public DisplayFriendlyWritingSystem TranscriptionWs { get; private set; } @@ -62,17 +60,13 @@ public ExportToFieldWorksInterlinearDlg() _comboTranslationWs.Font = Program.DialogFont; HandleStringsLocalized(); - LocalizeItemDlg.StringsLocalized += HandleStringsLocalized; } /// ------------------------------------------------------------------------------------ - protected void HandleStringsLocalized(ILocalizationManager lm = null) + protected void HandleStringsLocalized() { - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - _intructionsFmt = _labelImportInstructions.Text; - FormatImportInstructions(); - } + _instructionsFmt = _labelImportInstructions.Text; + FormatImportInstructions(); } /// ------------------------------------------------------------------------------------ @@ -80,7 +74,7 @@ private void FormatImportInstructions() { if (_comboTranslationWs.SelectedIndex >= 0) { - _labelImportInstructions.Text = Format(_intructionsFmt, kFlexProgramName, + _labelImportInstructions.Text = Format(_instructionsFmt, kFlexProgramName, (DisplayFriendlyWritingSystem)_comboTranslationWs.SelectedItem); } } @@ -139,7 +133,7 @@ protected override void OnShown(EventArgs e) /// ------------------------------------------------------------------------------------ /// Select the desired writing system in the given combo. /// The writing system combo box (whose items are expected to be of - /// type . + /// type ). /// An array of BCP-47 writing system locale identifiers. If more /// than one is provided, they should be given in order of descending preference; the first /// one that corresponds to an existing writing system in the combo box will be selected. @@ -161,44 +155,41 @@ private static void InitializeWritingSystemCombo(ComboBox combo, params string[] } } - if (combo.SelectedItem == null) - combo.SelectedItem = combo.Items[0]; + combo.SelectedItem ??= combo.Items[0]; } /// ------------------------------------------------------------------------------------ private void HandleExportButtonClick(object sender, EventArgs e) { var folder = TextAnnotationEditor.GetDefaultExportFolder("LastFlexInterlinearExportDestinationFolder"); - using (var dlg = new SaveFileDialog()) + using var dlg = new SaveFileDialog(); + dlg.Title = LocalizationManager.GetString( + "DialogBoxes.Transcription.ExportToFieldWorksInterlinearDlg.ExportSaveFileDlg.Caption", + "Export to File"); + + var flexInterlinearFilesDesc = LocalizationManager.GetString( + "DialogBoxes.Transcription.ExportToFieldWorksInterlinearDlg.ExportSaveFileDlg.InterlinearFilesDesc", + "FLEx Interlinear ({0})", "Parameter is a file-matching pattern: \"*.flextext\""); + + dlg.Filter = Format("{0}|{1}|{2}|{3}", + Format(flexInterlinearFilesDesc, "*" + kFlexTextExt), + "*" + kFlexTextExt, + Format(LocalizedVersionOfAllFilesDescriptor, kAllFilesFilter), + kAllFilesFilter); + + dlg.FileName = FileName; + dlg.OverwritePrompt = true; + dlg.CheckPathExists = true; + dlg.AutoUpgradeEnabled = true; + dlg.RestoreDirectory = true; + dlg.InitialDirectory = folder ?? Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + + if (dlg.ShowDialog() == DialogResult.OK) { - dlg.Title = LocalizationManager.GetString( - "DialogBoxes.Transcription.ExportToFieldWorksInterlinearDlg.ExportSaveFileDlg.Caption", - "Export to File"); - - var flexInterlinearFilesDesc = LocalizationManager.GetString( - "DialogBoxes.Transcription.ExportToFieldWorksInterlinearDlg.ExportSaveFileDlg.InterlinearFilesDesc", - "FLEx Interlinear ({0})", "Parameter is a file-matching pattern: \"*.flextext\""); - - dlg.Filter = Format("{0}|{1}|{2}|{3}", - Format(flexInterlinearFilesDesc, "*" + kFlexTextExt), - "*" + kFlexTextExt, - Format(LocalizedVersionOfAllFilesDescriptor, kAllFilesFilter), - kAllFilesFilter); - - dlg.FileName = FileName; - dlg.OverwritePrompt = true; - dlg.CheckPathExists = true; - dlg.AutoUpgradeEnabled = true; - dlg.RestoreDirectory = true; - dlg.InitialDirectory = folder ?? Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); - - if (dlg.ShowDialog() == DialogResult.OK) - { - FileName = dlg.FileName; - Settings.Default.LastFlexInterlinearExportDestinationFolder = Path.GetDirectoryName(FileName); - DialogResult = DialogResult.OK; - Close(); - } + FileName = dlg.FileName; + Settings.Default.LastFlexInterlinearExportDestinationFolder = Path.GetDirectoryName(FileName); + DialogResult = DialogResult.OK; + Close(); } } diff --git a/src/SayMore/Transcription/UI/OralAnnotationWaveViewer.Designer.cs b/src/SayMore/Transcription/UI/OralAnnotationWaveViewer.Designer.cs index 592dba67..6c18122e 100644 --- a/src/SayMore/Transcription/UI/OralAnnotationWaveViewer.Designer.cs +++ b/src/SayMore/Transcription/UI/OralAnnotationWaveViewer.Designer.cs @@ -22,7 +22,7 @@ private void InitializeComponent() this._labelCareful = new System.Windows.Forms.Label(); this._labelSource = new System.Windows.Forms.Label(); this._waveControl = new SayMore.Media.Audio.WaveControlBasic(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._tableLayout.SuspendLayout(); this._panelLabels.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); @@ -153,7 +153,7 @@ private void InitializeComponent() private System.Windows.Forms.Label _labelSource; private System.Windows.Forms.Label _labelTranslation; private System.Windows.Forms.Label _labelCareful; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Panel _panelLabels; } } diff --git a/src/SayMore/Transcription/UI/SegmentingAndRecording/CarefulSpeechRecorderDlg.designer.cs b/src/SayMore/Transcription/UI/SegmentingAndRecording/CarefulSpeechRecorderDlg.designer.cs index 5ab78c54..cc7d677c 100644 --- a/src/SayMore/Transcription/UI/SegmentingAndRecording/CarefulSpeechRecorderDlg.designer.cs +++ b/src/SayMore/Transcription/UI/SegmentingAndRecording/CarefulSpeechRecorderDlg.designer.cs @@ -26,7 +26,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._labelCarefulSpeech = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); this.SuspendLayout(); @@ -70,7 +70,7 @@ private void InitializeComponent() #endregion - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Label _labelCarefulSpeech; } } diff --git a/src/SayMore/Transcription/UI/SegmentingAndRecording/ManualSegmenterDlg.cs b/src/SayMore/Transcription/UI/SegmentingAndRecording/ManualSegmenterDlg.cs index efa2c8e9..732eaec3 100644 --- a/src/SayMore/Transcription/UI/SegmentingAndRecording/ManualSegmenterDlg.cs +++ b/src/SayMore/Transcription/UI/SegmentingAndRecording/ManualSegmenterDlg.cs @@ -395,11 +395,10 @@ private void ResetAddSegmentButton(object sender, EventArgs e) } /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized() { - base.HandleStringsLocalized(lm); - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - UpdateDisplay(); + base.HandleStringsLocalized(); + UpdateDisplay(); } /// ------------------------------------------------------------------------------------ diff --git a/src/SayMore/Transcription/UI/SegmentingAndRecording/ManualSegmenterDlg.designer.cs b/src/SayMore/Transcription/UI/SegmentingAndRecording/ManualSegmenterDlg.designer.cs index f12af9f5..ecf561c3 100644 --- a/src/SayMore/Transcription/UI/SegmentingAndRecording/ManualSegmenterDlg.designer.cs +++ b/src/SayMore/Transcription/UI/SegmentingAndRecording/ManualSegmenterDlg.designer.cs @@ -27,7 +27,7 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this._buttonAddSegmentBoundary = new System.Windows.Forms.ToolStripButton(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this.toolStripButtons = new System.Windows.Forms.ToolStrip(); this._buttonListenToOriginal = new System.Windows.Forms.ToolStripButton(); this._buttonStopOriginal = new System.Windows.Forms.ToolStripButton(); @@ -200,7 +200,7 @@ private void InitializeComponent() #endregion private System.Windows.Forms.ToolStripButton _buttonAddSegmentBoundary; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.ToolStrip toolStripButtons; private System.Windows.Forms.ToolStripButton _buttonListenToOriginal; private System.Windows.Forms.ToolStripButton _buttonStopOriginal; diff --git a/src/SayMore/Transcription/UI/SegmentingAndRecording/OralAnnotationRecorderDlgBase.cs b/src/SayMore/Transcription/UI/SegmentingAndRecording/OralAnnotationRecorderDlgBase.cs index 7f3395ff..5f4a36fb 100644 --- a/src/SayMore/Transcription/UI/SegmentingAndRecording/OralAnnotationRecorderDlgBase.cs +++ b/src/SayMore/Transcription/UI/SegmentingAndRecording/OralAnnotationRecorderDlgBase.cs @@ -6,8 +6,6 @@ using System.Linq; using DesktopAnalytics; using L10NSharp; -using L10NSharp.XLiffUtils; -using L10NSharp.UI; using SIL.Media.Naudio.UI; using SIL.Reporting; using SIL.Windows.Forms; @@ -72,9 +70,9 @@ private enum AdvanceOptionsAfterRecording public static OralAnnotationRecorderBaseDlg Create( OralAnnotationRecorderDlgViewModel viewModel, AudioRecordingType annotationType) { - return (annotationType == AudioRecordingType.Careful ? - new CarefulSpeechRecorderDlg(viewModel) as OralAnnotationRecorderBaseDlg : - new OralTranslationRecorderDlg(viewModel)); + return annotationType == AudioRecordingType.Careful ? + new CarefulSpeechRecorderDlg(viewModel) : + new OralTranslationRecorderDlg(viewModel); } /// ------------------------------------------------------------------------------------ @@ -177,8 +175,6 @@ protected override void Dispose(bool disposing) _hotPlaySourceButton.Dispose(); _hotRecordAnnotationButton.Dispose(); _waveControl?.Dispose(); - - LocalizeItemDlg.StringsLocalized -= HandleStringsLocalized; } base.Dispose(disposing); @@ -363,8 +359,6 @@ private void InitializeHintLabelsAndButtonFonts() _videoHelpMenu.Font = _labelSourceRecording.Font; _annotationSegmentFont = FontHelper.MakeFont(Program.DialogFont, 8, FontStyle.Bold); - - LocalizeItemDlg.StringsLocalized += HandleStringsLocalized; } private const int kNumberOfRows = 4; @@ -522,11 +516,10 @@ protected override void OnFormClosed(FormClosedEventArgs e) } /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized() { - base.HandleStringsLocalized(lm); - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - UpdateDisplay(); + base.HandleStringsLocalized(); + UpdateDisplay(); } /// ------------------------------------------------------------------------------------ @@ -1285,11 +1278,9 @@ private void DrawOralAnnotationWave(PaintEventArgs e, Rectangle rc, AnnotationSe try { // Draw the oral annotation's wave in the bottom, reserved area of the wave control. - using (var painter = new WavePainterBasic { ForeColor = Color.Black, BackColor = Color.Black }) - { - painter.SetSamplesToDraw(ViewModel.GetSegmentSamples(segment, (uint)rc.Width)); - painter.Draw(e, rc); - } + using var painter = new WavePainterBasic { ForeColor = Color.Black, BackColor = Color.Black }; + painter.SetSamplesToDraw(ViewModel.GetSegmentSamples(segment, (uint)rc.Width)); + painter.Draw(e, rc); } catch (IOException) { @@ -1304,10 +1295,8 @@ private void DrawCursorInOralAnnotationWave(PaintEventArgs e, Rectangle rc) if (x > 0 && x >= rc.X && x <= rc.Right) { rc.Inflate(0, 3); - using (var pen = new Pen(_waveControl.Painter.CursorColor)) - { - e.Graphics.DrawLine(pen, x, rc.Y, x, rc.Bottom); - } + using var pen = new Pen(_waveControl.Painter.CursorColor); + e.Graphics.DrawLine(pen, x, rc.Y, x, rc.Bottom); } } @@ -1360,8 +1349,8 @@ protected override void HandleWaveControlPostPaint(PaintEventArgs e) var rc = GetReadyToRecordCursorRectangle(); if (rc != Rectangle.Empty) { - using (var brush = new SolidBrush(_labelRecordButton.ForeColor)) - e.Graphics.FillRectangle(brush, rc); + using var brush = new SolidBrush(_labelRecordButton.ForeColor); + e.Graphics.FillRectangle(brush, rc); } } @@ -1396,16 +1385,14 @@ private void DrawHighlightedBorderForRecording(Graphics g, Rectangle rc) if (_labelRecordButton.ClientRectangle.Contains(_labelRecordButton.PointToClient(MousePosition)) || ViewModel.GetIsRecording()) { - using (var pen = new Pen(_labelRecordButton.ForeColor)) - { - var rcHighlight = rc; - rcHighlight.Y--; - rcHighlight.Width--; - rcHighlight.Inflate(-1, -1); - g.DrawRectangle(pen, rcHighlight); - rcHighlight.Inflate(-1, -1); - g.DrawRectangle(pen, rcHighlight); - } + using var pen = new Pen(_labelRecordButton.ForeColor); + var rcHighlight = rc; + rcHighlight.Y--; + rcHighlight.Width--; + rcHighlight.Inflate(-1, -1); + g.DrawRectangle(pen, rcHighlight); + rcHighlight.Inflate(-1, -1); + g.DrawRectangle(pen, rcHighlight); } } @@ -1517,11 +1504,9 @@ private void HandleMediaButtonTableLayoutPaint(object sender, PaintEventArgs e) { var rc = _tableLayoutMediaButtons.ClientRectangle; - using (var pen = new Pen(Settings.Default.BarColorBorder)) - { - e.Graphics.DrawLine(pen, rc.X, rc.Y, rc.X, rc.Bottom); - e.Graphics.DrawLine(pen, rc.Right - 1, rc.Y, rc.Right - 1, rc.Bottom); - } + using var pen = new Pen(Settings.Default.BarColorBorder); + e.Graphics.DrawLine(pen, rc.X, rc.Y, rc.X, rc.Bottom); + e.Graphics.DrawLine(pen, rc.Right - 1, rc.Y, rc.Right - 1, rc.Bottom); } #endregion diff --git a/src/SayMore/Transcription/UI/SegmentingAndRecording/OralAnnotationRecorderDlgBase.designer.cs b/src/SayMore/Transcription/UI/SegmentingAndRecording/OralAnnotationRecorderDlgBase.designer.cs index f7311e5a..ae2a2f1b 100644 --- a/src/SayMore/Transcription/UI/SegmentingAndRecording/OralAnnotationRecorderDlgBase.designer.cs +++ b/src/SayMore/Transcription/UI/SegmentingAndRecording/OralAnnotationRecorderDlgBase.designer.cs @@ -18,7 +18,7 @@ private void InitializeComponent() this.components = new System.ComponentModel.Container(); this._panelListen = new System.Windows.Forms.Panel(); this._labelListenButton = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._labelRecordButton = new System.Windows.Forms.Label(); this._pictureRecording = new System.Windows.Forms.PictureBox(); this._labelErrorInfo = new System.Windows.Forms.Label(); @@ -355,7 +355,7 @@ private void InitializeComponent() #endregion - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Timer _scrollTimer; private System.Windows.Forms.Timer _cursorBlinkTimer; protected System.Windows.Forms.TableLayoutPanel _tableLayoutRecordAnnotations; diff --git a/src/SayMore/Transcription/UI/SegmentingAndRecording/OralTranslationRecorderDlg.designer.cs b/src/SayMore/Transcription/UI/SegmentingAndRecording/OralTranslationRecorderDlg.designer.cs index c6a4a36d..8a2caa5d 100644 --- a/src/SayMore/Transcription/UI/SegmentingAndRecording/OralTranslationRecorderDlg.designer.cs +++ b/src/SayMore/Transcription/UI/SegmentingAndRecording/OralTranslationRecorderDlg.designer.cs @@ -26,7 +26,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._labelOralTranslation = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); this.SuspendLayout(); @@ -70,7 +70,7 @@ private void InitializeComponent() #endregion - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Label _labelOralTranslation; } } diff --git a/src/SayMore/Transcription/UI/SegmentingAndRecording/SegmenterDlgBase.cs b/src/SayMore/Transcription/UI/SegmentingAndRecording/SegmenterDlgBase.cs index 6b7f8a7e..72d7192c 100644 --- a/src/SayMore/Transcription/UI/SegmentingAndRecording/SegmenterDlgBase.cs +++ b/src/SayMore/Transcription/UI/SegmentingAndRecording/SegmenterDlgBase.cs @@ -7,19 +7,18 @@ using System.Linq; using System.Windows.Forms; using L10NSharp; -using L10NSharp.XLiffUtils; -using L10NSharp.UI; +using L10NSharp.Windows.Forms; using NAudio.Wave; -using SIL.Windows.Forms; -using SIL.Windows.Forms.Miscellaneous; -using SIL.Windows.Forms.PortableSettingsProvider; using SayMore.Media.Audio; +using SayMore.Media.MPlayer; using SayMore.Properties; using SayMore.Transcription.Model; using SayMore.UI.LowLevelControls; -using SayMore.Media.MPlayer; using SayMore.Utilities; +using SIL.Windows.Forms; using SIL.Windows.Forms.Extensions; +using SIL.Windows.Forms.Miscellaneous; +using SIL.Windows.Forms.PortableSettingsProvider; using Timer = System.Windows.Forms.Timer; namespace SayMore.Transcription.UI @@ -81,8 +80,6 @@ public SegmenterDlgBase() _segmentXofYFormat = _labelSegmentXofY.Text; _segmentNumberFormat = _labelSegmentNumber.Text; - - LocalizeItemDlg.StringsLocalized += HandleStringsLocalized; } /// ------------------------------------------------------------------------------------ @@ -157,7 +154,7 @@ protected override void OnLoad(EventArgs e) _undoToolStripMenuItem.Height *= 2; _ignoreToolStripMenuItem.Height = _undoToolStripMenuItem.Height; - HandleStringsLocalized(null); + HandleStringsLocalized(); } /// ------------------------------------------------------------------------------------ @@ -186,10 +183,7 @@ protected override void Dispose(bool disposing) { if (disposing) { - LocalizeItemDlg.StringsLocalized -= HandleStringsLocalized; - - if (components != null) - components.Dispose(); + components?.Dispose(); if (_waveControl != null) { @@ -213,14 +207,11 @@ protected virtual WaveControlWithMovableBoundaries CreateWaveControl() } /// ------------------------------------------------------------------------------------ - protected virtual void HandleStringsLocalized(ILocalizationManager lm) + protected virtual void HandleStringsLocalized() { - if (lm != null && lm.Id != ApplicationContainer.kSayMoreLocalizationId) - return; - _segmentXofYFormat = _labelSegmentXofY.Text; _segmentNumberFormat = _labelSegmentNumber.Text; - var zoomToolTip = LocalizationManager.GetLocalizedToolTipForControl(_comboBoxZoom); + var zoomToolTip = LocalizationManagerWinforms.GetLocalizedToolTipForControl(_comboBoxZoom); if (!string.IsNullOrEmpty(zoomToolTip)) _tooltip.SetToolTip(_labelZoom, zoomToolTip); } diff --git a/src/SayMore/Transcription/UI/SegmentingAndRecording/SegmenterDlgBase.designer.cs b/src/SayMore/Transcription/UI/SegmentingAndRecording/SegmenterDlgBase.designer.cs index cfa4c793..a1f4949e 100644 --- a/src/SayMore/Transcription/UI/SegmentingAndRecording/SegmenterDlgBase.designer.cs +++ b/src/SayMore/Transcription/UI/SegmentingAndRecording/SegmenterDlgBase.designer.cs @@ -36,7 +36,7 @@ private void InitializeComponent() this._labelSourceRecording = new System.Windows.Forms.Label(); this._buttonOK = new System.Windows.Forms.Button(); this._buttonCancel = new System.Windows.Forms.Button(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._tableLayoutButtons = new System.Windows.Forms.TableLayoutPanel(); this._tooltip = new System.Windows.Forms.ToolTip(this.components); this._panelWaveControl.SuspendLayout(); @@ -417,7 +417,7 @@ private void InitializeComponent() #endregion protected System.Windows.Forms.Button _buttonOK; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; protected System.Windows.Forms.TableLayoutPanel _tableLayoutOuter; protected Panel _panelWaveControl; protected System.Windows.Forms.Label _labelSourceRecording; diff --git a/src/SayMore/UI/ComponentEditors/AudioComponentEditor.cs b/src/SayMore/UI/ComponentEditors/AudioComponentEditor.cs index ad7d0f13..d1a1c6d1 100644 --- a/src/SayMore/UI/ComponentEditors/AudioComponentEditor.cs +++ b/src/SayMore/UI/ComponentEditors/AudioComponentEditor.cs @@ -1,3 +1,4 @@ +using System; using L10NSharp; using SayMore.Model.Files; using SayMore.Model.Files.DataGathering; @@ -22,11 +23,12 @@ public AudioComponentEditor(ComponentFile file, string imageKey, /// Update the tab text in case it was localized. /// /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) TabText = GetPropertiesTabText(); - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } } } diff --git a/src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs b/src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs index 6a239060..ebc7a4e5 100644 --- a/src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs +++ b/src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs @@ -18,7 +18,8 @@ public partial class AudioVideoPlayer : EditorBase private readonly MediaPlayer _mediaPlayer; /// ------------------------------------------------------------------------------------ - public AudioVideoPlayer(ComponentFile file, string imageKey) : base(file, null, imageKey) + public AudioVideoPlayer(ComponentFile file, string imageKey, ILocalizationManager localizationManager) : + base(file, null, imageKey, localizationManager) { Logger.WriteEvent("AudioVideoPlayer constructor. file = {0}; imageKey = {1}", file, imageKey); InitializeComponent(); @@ -38,7 +39,7 @@ private void FinishInitializing(ComponentFile file) SetComponentFile(file); // SP-831: tab is being localized before the file has been set in the base class - HandleStringsLocalized(null); + HandleStringsLocalized(null, EventArgs.Empty); } /// ------------------------------------------------------------------------------------ @@ -64,12 +65,13 @@ protected override void Dispose(bool disposing) /// Update the tab text in case it was localized. /// /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { // SP-831: tab is being localized before the file has been set in the base class if (_file == null) return; + var lm = (ILocalizationManager)sender; if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { TabText = _file.FileType.IsVideo ? @@ -79,7 +81,7 @@ protected override void HandleStringsLocalized(ILocalizationManager lm) "CommonToMultipleViews.MediaPlayer.TabText-Audio", "Audio"); } - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } /// ------------------------------------------------------------------------------------ @@ -120,7 +122,7 @@ private void LoadAnnotationFile(ComponentFile file) Invoke((Action)(() => ErrorReport.NotifyUserOfProblem(e.Message))); else ErrorReport.NotifyUserOfProblem(e.Message); - }; + } } } @@ -137,12 +139,6 @@ public override void Deactivated() _mediaPlayerViewModel.ShutdownMPlayerProcess(); } - ///// ------------------------------------------------------------------------------------ - //private static void HandleMediaError(object sender, _WMPOCXEvents_MediaErrorEvent e) - //{ - // SIL.Reporting.ErrorReport.NotifyUserOfProblem("Media error: " + e.pMediaObject); - //} - /// ------------------------------------------------------------------------------------ protected override void OnParentChanged(EventArgs e) { diff --git a/src/SayMore/UI/ComponentEditors/BasicFieldGridEditor.cs b/src/SayMore/UI/ComponentEditors/BasicFieldGridEditor.cs index 0ef2b3ed..ab572bb3 100644 --- a/src/SayMore/UI/ComponentEditors/BasicFieldGridEditor.cs +++ b/src/SayMore/UI/ComponentEditors/BasicFieldGridEditor.cs @@ -1,3 +1,4 @@ +using System; using System.Windows.Forms; using L10NSharp; using SayMore.Model.Files; @@ -15,8 +16,9 @@ public partial class BasicFieldGridEditor : EditorBase /// ------------------------------------------------------------------------------------ public BasicFieldGridEditor(ComponentFile file, string imageKey, - AutoCompleteValueGatherer autoCompleteProvider, FieldGatherer fieldGatherer) - : base(file, null, imageKey) + AutoCompleteValueGatherer autoCompleteProvider, FieldGatherer fieldGatherer, + ILocalizationManager localizationManager) + : base(file, null, imageKey, localizationManager) { InitializeComponent(); Name = "BasicFieldGridEditor"; @@ -49,12 +51,13 @@ public override void SetComponentFile(ComponentFile file) /// Update the tab text in case it was localized. /// /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) TabText = GetPropertiesTabText(); - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } } } diff --git a/src/SayMore/UI/ComponentEditors/BrowserEditor.cs b/src/SayMore/UI/ComponentEditors/BrowserEditor.cs index 13b7374a..8b2a6091 100644 --- a/src/SayMore/UI/ComponentEditors/BrowserEditor.cs +++ b/src/SayMore/UI/ComponentEditors/BrowserEditor.cs @@ -193,7 +193,7 @@ void HandleFileLinkClick(object sender, HtmlElementEventArgs e) /// Update the tab text in case it was localized. /// /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { @@ -203,7 +203,7 @@ protected override void HandleStringsLocalized(ILocalizationManager lm) DisplayFile(filePath); } - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } } } diff --git a/src/SayMore/UI/ComponentEditors/ContributorsEditor.cs b/src/SayMore/UI/ComponentEditors/ContributorsEditor.cs index e0b71241..04ec3390 100644 --- a/src/SayMore/UI/ComponentEditors/ContributorsEditor.cs +++ b/src/SayMore/UI/ComponentEditors/ContributorsEditor.cs @@ -6,7 +6,7 @@ using System.Text; using System.Windows.Forms; using L10NSharp; -using L10NSharp.UI; +using L10NSharp.Windows.Forms; using SIL.Windows.Forms.ClearShare; using SIL.Windows.Forms.ClearShare.WinFormsUI; using SayMore.Model; @@ -32,8 +32,9 @@ public partial class ContributorsEditor : EditorBase /// ------------------------------------------------------------------------------------ public ContributorsEditor(ComponentFile file, string imageKey, - AutoCompleteValueGatherer autoCompleteProvider, PersonInformant personInformant) : - base(file, null, imageKey) + AutoCompleteValueGatherer autoCompleteProvider, PersonInformant personInformant, + ILocalizationManager localizationManager) : + base(file, null, imageKey, localizationManager) { InitializeComponent(); Name = "Contributors"; @@ -154,12 +155,12 @@ private void InitializeGrid(Func> getPeopleNames) // set the localizable column header text string[] headerText = - { + [ @"_L10N_:SessionsView.ContributorsEditor.NameColumnTitle!Name", @"_L10N_:SessionsView.ContributorsEditor.RoleColumnTitle!Role", @"_L10N_:SessionsView.ContributorsEditor.DateColumnTitle!Date", @"_L10N_:SessionsView.ContributorsEditor.CommentColumnTitle!Comments" - }; + ]; for (var i = 0; i < headerText.Length; i++) { @@ -416,15 +417,16 @@ private string GetParticipants(bool withRoles) /// Update the tab text in case it was localized. /// /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { TabText = LocalizationManager.GetString( "CommonToMultipleViews.ContributorsEditor.TabText", "Contributors"); } - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } } } diff --git a/src/SayMore/UI/ComponentEditors/EditorBase.cs b/src/SayMore/UI/ComponentEditors/EditorBase.cs index 9ca1f310..aaafd979 100644 --- a/src/SayMore/UI/ComponentEditors/EditorBase.cs +++ b/src/SayMore/UI/ComponentEditors/EditorBase.cs @@ -6,8 +6,6 @@ using System.Threading; using System.Windows.Forms; using L10NSharp; -using L10NSharp.XLiffUtils; -using L10NSharp.UI; using SIL.Windows.Forms; using SayMore.Model.Files; using SayMore.Utilities; @@ -37,6 +35,7 @@ public interface IEditorProvider // Should be abstract, but that messes up the Designer public class EditorBase : UserControl, IEditorProvider { + private readonly ILocalizationManager _localizationManager; private bool _setWorkingFontWhenHandleIsCreated = false; private BindingHelper _binder; protected ComponentFile _file; @@ -48,8 +47,9 @@ public class EditorBase : UserControl, IEditorProvider public Action ComponentFileListRefreshAction { protected get; set; } /// ------------------------------------------------------------------------------------ - public EditorBase() + public EditorBase(ILocalizationManager localizationManager) { + _localizationManager = localizationManager; DoubleBuffered = true; BackColor = AppColors.DataEntryPanelBegin; Padding = new Padding(7); @@ -60,12 +60,13 @@ public EditorBase() ControlRemoved += HandleControlRemoved; Layout += HandleLayout; - LocalizeItemDlg.StringsLocalized += HandleStringsLocalized; - HandleStringsLocalized(null); + localizationManager.UiLanguageChanged += HandleStringsLocalized; + HandleStringsLocalized(null, EventArgs.Empty); } /// ------------------------------------------------------------------------------------ - public EditorBase(ComponentFile file, string tabText, string imageKey) : this() + public EditorBase(ComponentFile file, string tabText, string imageKey, + ILocalizationManager localizationManager) : this(localizationManager) { _file = file; Initialize(tabText, imageKey); @@ -75,8 +76,7 @@ public EditorBase(ComponentFile file, string tabText, string imageKey) : this() protected override void Dispose(bool disposing) { if (disposing) - LocalizeItemDlg.StringsLocalized -= HandleStringsLocalized; - + _localizationManager.UiLanguageChanged -= HandleStringsLocalized; try { base.Dispose(disposing); @@ -208,7 +208,7 @@ public static T FindParent(Control control) where T : Control } /// ------------------------------------------------------------------------------------ - protected virtual void HandleStringsLocalized(ILocalizationManager lm) + protected virtual void HandleStringsLocalized(object sender, EventArgs e) { } diff --git a/src/SayMore/UI/ComponentEditors/FieldsValuesGrid.cs b/src/SayMore/UI/ComponentEditors/FieldsValuesGrid.cs index 1ee4a928..c4d87966 100644 --- a/src/SayMore/UI/ComponentEditors/FieldsValuesGrid.cs +++ b/src/SayMore/UI/ComponentEditors/FieldsValuesGrid.cs @@ -3,7 +3,7 @@ using System.Media; using System.Windows.Forms; using L10NSharp; -using L10NSharp.UI; +using L10NSharp.Windows.Forms; using SIL.Windows.Forms.Widgets.BetterGrid; using SayMore.Properties; using SayMore.UI.LowLevelControls; @@ -390,8 +390,8 @@ private static bool AskUserToVerifyRemovingFieldEverywhere(string id) var msg = LocalizationManager.GetString("CommonToMultipleViews.FieldsAndValuesGrid.VerifyDeleteFieldQuestion", "Do you want to delete the field '{0}' and its contents from the entire project?"); - using (var dlg = new DeleteMessageBox(string.Format(msg, id))) - return (dlg.ShowDialog() == DialogResult.OK); + using var dlg = new DeleteMessageBox(string.Format(msg, id)); + return dlg.ShowDialog() == DialogResult.OK; } } } diff --git a/src/SayMore/UI/ComponentEditors/ImageViewer.Designer.cs b/src/SayMore/UI/ComponentEditors/ImageViewer.Designer.cs index 2590d28f..824e750d 100644 --- a/src/SayMore/UI/ComponentEditors/ImageViewer.Designer.cs +++ b/src/SayMore/UI/ComponentEditors/ImageViewer.Designer.cs @@ -30,7 +30,7 @@ private void InitializeComponent() this._zoomTrackBar = new System.Windows.Forms.TrackBar(); this._tableLayoutZoom = new System.Windows.Forms.TableLayoutPanel(); this._labelZoom = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); ((System.ComponentModel.ISupportInitialize)(this._zoomTrackBar)).BeginInit(); this._tableLayoutZoom.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); @@ -117,6 +117,6 @@ private void InitializeComponent() private System.Windows.Forms.TrackBar _zoomTrackBar; private System.Windows.Forms.TableLayoutPanel _tableLayoutZoom; private System.Windows.Forms.Label _labelZoom; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; } } diff --git a/src/SayMore/UI/ComponentEditors/ImageViewer.cs b/src/SayMore/UI/ComponentEditors/ImageViewer.cs index 1d9d14aa..4cf8861a 100644 --- a/src/SayMore/UI/ComponentEditors/ImageViewer.cs +++ b/src/SayMore/UI/ComponentEditors/ImageViewer.cs @@ -17,7 +17,8 @@ public partial class ImageViewer : EditorBase private ImageViewerViewModel _model; /// ------------------------------------------------------------------------------------ - public ImageViewer(ComponentFile file) : base(file, null, "Image") + public ImageViewer(ComponentFile file, ILocalizationManager localizationManager) : + base(file, null, "Image", localizationManager) { Logger.WriteEvent("ImageViewer constructor. file = {0}", file); InitializeComponent(); @@ -140,15 +141,16 @@ private void HandleZoomTrackBarValueChanged(object sender, EventArgs e) /// Update the tab text in case it was localized. /// /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { TabText = LocalizationManager.GetString( "CommonToMultipleViews.ImageViewer.TabText", "Image"); } - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } } } diff --git a/src/SayMore/UI/ComponentEditors/MediaComponentEditor.Designer.cs b/src/SayMore/UI/ComponentEditors/MediaComponentEditor.Designer.cs index 154cfce1..9425d2cc 100644 --- a/src/SayMore/UI/ComponentEditors/MediaComponentEditor.Designer.cs +++ b/src/SayMore/UI/ComponentEditors/MediaComponentEditor.Designer.cs @@ -34,7 +34,7 @@ private void InitializeComponent() this._buttonPresets = new System.Windows.Forms.ToolStripDropDownButton(); this._buttonMoreInfo = new System.Windows.Forms.ToolStripButton(); this._presetMenu = new System.Windows.Forms.ContextMenuStrip(this.components); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._tableLayout.SuspendLayout(); this._toolStrip.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); @@ -135,7 +135,7 @@ private void InitializeComponent() #endregion private System.Windows.Forms.TableLayoutPanel _tableLayout; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; protected System.Windows.Forms.ContextMenuStrip _presetMenu; private System.Windows.Forms.ToolStrip _toolStrip; private System.Windows.Forms.ToolStripButton _buttonMoreInfo; diff --git a/src/SayMore/UI/ComponentEditors/MediaFileMoreInfoDlg.Designer.cs b/src/SayMore/UI/ComponentEditors/MediaFileMoreInfoDlg.Designer.cs index 74f7fb6b..8b98e5ce 100644 --- a/src/SayMore/UI/ComponentEditors/MediaFileMoreInfoDlg.Designer.cs +++ b/src/SayMore/UI/ComponentEditors/MediaFileMoreInfoDlg.Designer.cs @@ -14,9 +14,7 @@ partial class MediaFileMoreInfoDlg protected override void Dispose(bool disposing) { if (disposing && (components != null)) - { components.Dispose(); - } base.Dispose(disposing); } @@ -36,7 +34,7 @@ private void InitializeComponent() this._flowLayoutButtons = new System.Windows.Forms.FlowLayoutPanel(); this._buttonEvenMoreInfo = new System.Windows.Forms.Button(); this._buttonLessInfo = new System.Windows.Forms.Button(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._lblSource = new System.Windows.Forms.Label(); this.tableLayoutPanel1.SuspendLayout(); this._panelBrowser.SuspendLayout(); @@ -225,7 +223,7 @@ private void InitializeComponent() private System.Windows.Forms.WebBrowser _webBrowserInfo; private SIL.Windows.Forms.Widgets.EnhancedPanel _panelBrowser; private System.Windows.Forms.Button _buttonLessInfo; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Label _lblSource; } } \ No newline at end of file diff --git a/src/SayMore/UI/ComponentEditors/MediaFileMoreInfoDlg.cs b/src/SayMore/UI/ComponentEditors/MediaFileMoreInfoDlg.cs index 731d4f15..0b43f5d3 100644 --- a/src/SayMore/UI/ComponentEditors/MediaFileMoreInfoDlg.cs +++ b/src/SayMore/UI/ComponentEditors/MediaFileMoreInfoDlg.cs @@ -6,8 +6,6 @@ using System.Xml; using System.Xml.Xsl; using L10NSharp; -using L10NSharp.UI; -using L10NSharp.XLiffUtils; using SIL.Reporting; using SIL.Windows.Forms.PortableSettingsProvider; using SayMore.Media; @@ -21,7 +19,7 @@ public partial class MediaFileMoreInfoDlg : Form { private readonly string _mediaFilePath; private string _source; - private static bool alreadyDisplayedEvenMoreInfoDisclaimer = false; + private static bool s_alreadyDisplayedEvenMoreInfoDisclaimer = false; /// ------------------------------------------------------------------------------------ public MediaFileMoreInfoDlg() @@ -29,7 +27,6 @@ public MediaFileMoreInfoDlg() InitializeComponent(); _buttonClose.Click += delegate { Close(); }; - LocalizeItemDlg.StringsLocalized += HandleStringsLocalized; HandleStringsLocalized(); } @@ -49,13 +46,10 @@ public MediaFileMoreInfoDlg(string mediaFileInfo) : this() /// ------------------------------------------------------------------------------------ - protected void HandleStringsLocalized(ILocalizationManager lm = null) + protected void HandleStringsLocalized() { - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - _lblSource.Tag = _lblSource.Text; - UpdateSourceLabelDisplay(); - } + _lblSource.Tag = _lblSource.Text; + UpdateSourceLabelDisplay(); } /// ------------------------------------------------------------------------------------ @@ -105,8 +99,9 @@ private bool LoadBrowserControl() return false; _webBrowserInfo.DocumentStream = TransformInfoOutput(html); - _webBrowserInfo.Document.Encoding = "utf-8"; - return true; + if (_webBrowserInfo.Document != null) + _webBrowserInfo.Document.Encoding = "utf-8"; + return true; } /// ------------------------------------------------------------------------------------ @@ -158,13 +153,11 @@ public MemoryStream TransformInfoOutput(string htmlInput) var inputReader = XmlReader.Create(inputStream); var outputWriter = XmlWriter.Create(outputStream); - using (var xsltReader = new XmlTextReader(xsltStream)) - { - var xslt = new XslCompiledTransform(true); - xslt.Load(xsltReader); - xslt.Transform(inputReader, outputWriter); - xsltReader.Close(); - } + using var xsltReader = new XmlTextReader(xsltStream); + var xslt = new XslCompiledTransform(true); + xslt.Load(xsltReader); + xslt.Transform(inputReader, outputWriter); + xsltReader.Close(); } catch { @@ -183,8 +176,7 @@ public MemoryStream TransformInfoOutput(string htmlInput) var transformedHtml = reader.ReadToEnd(); outputStream.Close(); - var styleInfo = Format("\r\n", - Resources.MoreMediaInfoStyles); + var styleInfo = $"\r"; transformedHtml = transformedHtml.Replace("", HTMLChartBuilder.XMLDocTypeInfo); transformedHtml = transformedHtml.Replace("", styleInfo + ""); @@ -199,7 +191,7 @@ private void HandleEvenMoreInfoButtonClick(object sender, EventArgs e) _buttonLessInfo.Visible = true; var origSource = _source; if (LoadBrowserControl() && origSource != _source && - !alreadyDisplayedEvenMoreInfoDisclaimer) + !s_alreadyDisplayedEvenMoreInfoDisclaimer) { // Note: I'm hard-coding the utility program names in the localizer comment // because as things currently stand, that's definitely what they will be. @@ -212,7 +204,7 @@ private void HandleEvenMoreInfoButtonClick(object sender, EventArgs e) "Parameters are utility program names. Param 0: \"MediaInfo.DLL\";" + " Param 1: \"FFprobe\""), _source, origSource); MessageBox.Show(this, msg, ProductName, MessageBoxButtons.OK); - alreadyDisplayedEvenMoreInfoDisclaimer = true; + s_alreadyDisplayedEvenMoreInfoDisclaimer = true; } } diff --git a/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.cs b/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.cs index 7c717724..3a873f4d 100644 --- a/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.cs +++ b/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.cs @@ -1,3 +1,4 @@ +using System; using System.Windows.Forms; using L10NSharp; using SIL.Reporting; @@ -10,13 +11,13 @@ namespace SayMore.UI.ComponentEditors public partial class MissingMediaFileEditor : EditorBase { /// ------------------------------------------------------------------------------------ - public MissingMediaFileEditor(ComponentFile file, string imageKey) - : base(file, null, imageKey) + public MissingMediaFileEditor(ComponentFile file, string imageKey, ILocalizationManager localizationManager) + : base(file, null, imageKey, localizationManager) { Logger.WriteEvent("MissingMediaFileEditor constructor. file = {0}", file); InitializeComponent(); SetComponentFile(file); - HandleStringsLocalized(null); + HandleStringsLocalized(null, EventArgs.Empty); } /// ------------------------------------------------------------------------------------ @@ -28,14 +29,14 @@ public override void SetComponentFile(ComponentFile file) } /// ------------------------------------------------------------------------------------ - protected override void OnVisibleChanged(System.EventArgs e) + protected override void OnVisibleChanged(EventArgs e) { base.OnVisibleChanged(e); ReselectFilePathAndScrollIntoViewAsMuchAsPossible(); } /// ------------------------------------------------------------------------------------ - protected override void OnSizeChanged(System.EventArgs e) + protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); ReselectFilePathAndScrollIntoViewAsMuchAsPossible(); @@ -55,10 +56,11 @@ private void HandleHelpTopicLinkClicked(object sender, LinkLabelLinkClickedEvent } /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); + var lm = (ILocalizationManager)sender; if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { TabText = LocalizationManager.GetString( diff --git a/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.designer.cs b/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.designer.cs index 2f57ed83..79e562ea 100644 --- a/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.designer.cs +++ b/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.designer.cs @@ -36,7 +36,7 @@ private void InitializeComponent() this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.linkHelpTopic = new System.Windows.Forms.LinkLabel(); this.txtMissingMediaFilePath = new System.Windows.Forms.TextBox(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._panelBrowser.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); @@ -182,7 +182,7 @@ private void InitializeComponent() private System.Windows.Forms.LinkLabel linkHelpTopic; private System.Windows.Forms.TextBox txtMissingMediaFilePath; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Label lblMediaFileMissing; private System.Windows.Forms.Label lblExplanation; } diff --git a/src/SayMore/UI/ComponentEditors/NotesEditor.cs b/src/SayMore/UI/ComponentEditors/NotesEditor.cs index 5097c919..01ba7867 100644 --- a/src/SayMore/UI/ComponentEditors/NotesEditor.cs +++ b/src/SayMore/UI/ComponentEditors/NotesEditor.cs @@ -67,7 +67,7 @@ private static void HandleNotesTextBoxKeyDown(object sender, KeyEventArgs e) /// Update the tab text in case it was localized. /// /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { @@ -75,7 +75,7 @@ protected override void HandleStringsLocalized(ILocalizationManager lm) "CommonToMultipleViews.NotesEditor.TabText", "Notes"); } - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } private void NotesEditor_Load(object sender, EventArgs e) diff --git a/src/SayMore/UI/ComponentEditors/PersonBasicEditor.Designer.cs b/src/SayMore/UI/ComponentEditors/PersonBasicEditor.Designer.cs index 3726b313..3030d8e1 100644 --- a/src/SayMore/UI/ComponentEditors/PersonBasicEditor.Designer.cs +++ b/src/SayMore/UI/ComponentEditors/PersonBasicEditor.Designer.cs @@ -81,7 +81,7 @@ private void InitializeComponent() this._binder = new SayMore.UI.ComponentEditors.BindingHelper(this.components); this._autoCompleteHelper = new SayMore.UI.ComponentEditors.AutoCompleteHelper(this.components); this._tooltip = new System.Windows.Forms.ToolTip(this.components); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._tableLayout.SuspendLayout(); this._panelPicture.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this._personsPicture)).BeginInit(); @@ -1049,7 +1049,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolTip _tooltip; private System.Windows.Forms.PictureBox _personsPicture; private System.Windows.Forms.Panel _panelPicture; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.FlowLayoutPanel _panelPrivacy; private System.Windows.Forms.Label _labelPrivacy; private System.Windows.Forms.CheckBox _privacyProtection; diff --git a/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs b/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs index 246b1890..fb4c3321 100644 --- a/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs +++ b/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs @@ -86,7 +86,7 @@ public PersonBasicEditor(ComponentFile file, string imageKey, { _otherLanguage3, _otherLanguage3.ForeColor} }; - HandleStringsLocalized(null); + HandleStringsLocalized(); _binder.TranslateBoundValueBeingSaved += HandleBinderTranslateBoundValueBeingSaved; _binder.TranslateBoundValueBeingRetrieved += HandleBinderTranslateBoundValueBeingRetrieved; _binder.SetComponentFile(file); @@ -810,12 +810,13 @@ private string GetPictureFileFromDragData(IDataObject data) #endregion #region Methods for handling localized gender names + /// ------------------------------------------------------------------------------------ /// /// Update the tab text and gender names in case they were localized. /// /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { @@ -834,7 +835,7 @@ protected override void HandleStringsLocalized(ILocalizationManager lm) } } - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } /// ------------------------------------------------------------------------------------ diff --git a/src/SayMore/UI/ComponentEditors/PersonContributionEditor.Designer.cs b/src/SayMore/UI/ComponentEditors/PersonContributionEditor.Designer.cs index 943ef6ff..447e9deb 100644 --- a/src/SayMore/UI/ComponentEditors/PersonContributionEditor.Designer.cs +++ b/src/SayMore/UI/ComponentEditors/PersonContributionEditor.Designer.cs @@ -38,7 +38,7 @@ private void InitializeComponent() this.colRole = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.colDate = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.colComments = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); this.SuspendLayout(); // @@ -118,6 +118,6 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn colRole; private System.Windows.Forms.DataGridViewTextBoxColumn colDate; private System.Windows.Forms.DataGridViewTextBoxColumn colComments; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; } } diff --git a/src/SayMore/UI/ComponentEditors/PersonContributionEditor.cs b/src/SayMore/UI/ComponentEditors/PersonContributionEditor.cs index 279526d4..2395cfb4 100644 --- a/src/SayMore/UI/ComponentEditors/PersonContributionEditor.cs +++ b/src/SayMore/UI/ComponentEditors/PersonContributionEditor.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Windows.Forms; using L10NSharp; -using L10NSharp.UI; using SayMore.Model; using SayMore.Model.Files; using DateTime = System.DateTime; @@ -132,7 +131,7 @@ private object[] GetContribRowData(SessionContribution contrib) return new object[] { description, localizedRole, formattedDate, contrib.Contribution.Comments }; } - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { @@ -140,7 +139,7 @@ protected override void HandleStringsLocalized(ILocalizationManager lm) "PeopleView.ContributionEditor.TabText", "Contributions"); } - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } public override void SetComponentFile(ComponentFile file) diff --git a/src/SayMore/UI/ComponentEditors/SessionBasicEditor.Designer.cs b/src/SayMore/UI/ComponentEditors/SessionBasicEditor.Designer.cs index 724cc156..aaa5667c 100644 --- a/src/SayMore/UI/ComponentEditors/SessionBasicEditor.Designer.cs +++ b/src/SayMore/UI/ComponentEditors/SessionBasicEditor.Designer.cs @@ -62,7 +62,7 @@ private void InitializeComponent() this._labelCustomFields = new System.Windows.Forms.Label(); this._binder = new SayMore.UI.ComponentEditors.BindingHelper(this.components); this._autoCompleteHelper = new SayMore.UI.ComponentEditors.AutoCompleteHelper(this.components); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._moreFieldsToolTip = new System.Windows.Forms.ToolTip(this.components); this._tableLayout.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout(); @@ -631,7 +631,7 @@ private void InitializeComponent() private AutoCompleteHelper _autoCompleteHelper; private System.Windows.Forms.Panel _panelGrid; private System.Windows.Forms.Label _labelDate; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.ComboBox _access; private System.Windows.Forms.Label _labelMoreFields; private System.Windows.Forms.Panel _panelAdditionalGrid; diff --git a/src/SayMore/UI/ComponentEditors/SessionBasicEditor.cs b/src/SayMore/UI/ComponentEditors/SessionBasicEditor.cs index a9b78d62..1005a402 100644 --- a/src/SayMore/UI/ComponentEditors/SessionBasicEditor.cs +++ b/src/SayMore/UI/ComponentEditors/SessionBasicEditor.cs @@ -431,7 +431,7 @@ protected override void OnCurrentProjectSet() /// Update the tab text in case it was localized. /// /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { @@ -455,7 +455,7 @@ protected override void HandleStringsLocalized(ILocalizationManager lm) } } - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } /// ------------------------------------------------------------------------------------ diff --git a/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.Designer.cs b/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.Designer.cs index f9d7b060..bd7a55c0 100644 --- a/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.Designer.cs +++ b/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.Designer.cs @@ -38,7 +38,7 @@ private void InitializeComponent() this._labelReadAboutStages = new System.Windows.Forms.Label(); this._labelStagesHint = new System.Windows.Forms.Label(); this._buttonReadAboutStages = new System.Windows.Forms.Button(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._toolTip = new System.Windows.Forms.ToolTip(this.components); this._tableLayoutOuter.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); @@ -253,7 +253,7 @@ private void InitializeComponent() private System.Windows.Forms.Label _labelReadAboutStages; private System.Windows.Forms.Label _labelStagesHint; private System.Windows.Forms.Button _buttonReadAboutStages; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.ToolTip _toolTip; } } diff --git a/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.cs b/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.cs index 80999e15..819835f5 100644 --- a/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.cs +++ b/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.cs @@ -331,7 +331,7 @@ private void HandleStagesColorBlockPaint(object sender, PaintEventArgs e) } /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { @@ -350,7 +350,7 @@ protected override void HandleStringsLocalized(ILocalizationManager lm) } } - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } /// ------------------------------------------------------------------------------------ diff --git a/src/SayMore/UI/ComponentEditors/VideoComponentEditor.cs b/src/SayMore/UI/ComponentEditors/VideoComponentEditor.cs index 3557da9c..3dccc8aa 100644 --- a/src/SayMore/UI/ComponentEditors/VideoComponentEditor.cs +++ b/src/SayMore/UI/ComponentEditors/VideoComponentEditor.cs @@ -1,3 +1,4 @@ +using System; using L10NSharp; using SayMore.Model.Files; using SayMore.Model.Files.DataGathering; @@ -22,11 +23,12 @@ public VideoComponentEditor(ComponentFile file, string imageKey, /// Update the tab text in case it was localized. /// /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) TabText = GetPropertiesTabText(); - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); } } } diff --git a/src/SayMore/UI/ConvertMediaDlg.Designer.cs b/src/SayMore/UI/ConvertMediaDlg.Designer.cs index 174a3a24..8ccbe8e3 100644 --- a/src/SayMore/UI/ConvertMediaDlg.Designer.cs +++ b/src/SayMore/UI/ConvertMediaDlg.Designer.cs @@ -49,7 +49,7 @@ private void InitializeComponent() this._textBoxOutput = new System.Windows.Forms.TextBox(); this._labelOutputFile = new System.Windows.Forms.Label(); this._labelOutputFileValue = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._tableLayoutOuter.SuspendLayout(); this._flowLayoutBottomButtons.SuspendLayout(); this._flowLayoutShowHideButtons.SuspendLayout(); @@ -413,7 +413,7 @@ private void InitializeComponent() private System.Windows.Forms.Button _buttonShowOutput; private System.Windows.Forms.Button _buttonHideOutput; private System.Windows.Forms.TextBox _textBoxOutput; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Label _labelOutputFile; private System.Windows.Forms.Label _labelOutputFileValue; } diff --git a/src/SayMore/UI/ElementListScreen/ComponentFileGrid.Designer.cs b/src/SayMore/UI/ElementListScreen/ComponentFileGrid.Designer.cs index 013d5cc5..13bec35b 100644 --- a/src/SayMore/UI/ElementListScreen/ComponentFileGrid.Designer.cs +++ b/src/SayMore/UI/ElementListScreen/ComponentFileGrid.Designer.cs @@ -1,5 +1,5 @@ using L10NSharp.XLiffUtils; -using L10NSharp.UI; +using L10NSharp.Windows.Forms.UIComponents; namespace SayMore.UI.ElementListScreen { @@ -18,10 +18,9 @@ protected override void Dispose(bool disposing) { if (disposing) { - if (components != null) - components.Dispose(); + components?.Dispose(); - LocalizeItemDlg.StringsLocalized -= HandleStringsLocalized; + _localizationManager.UiLanguageChanged -= HandleStringsLocalized; } base.Dispose(disposing); } @@ -55,7 +54,7 @@ private void InitializeComponent() this._buttonRename = new System.Windows.Forms.ToolStripButton(); this._buttonConvert = new System.Windows.Forms.ToolStripButton(); this._buttonAddFiles = new System.Windows.Forms.ToolStripButton(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._contextMenuStrip.SuspendLayout(); this._panelOuter.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this._grid)).BeginInit(); @@ -339,7 +338,7 @@ private void InitializeComponent() private System.Windows.Forms.DataGridViewTextBoxColumn colDataModified; private System.Windows.Forms.DataGridViewTextBoxColumn colSize; private System.Windows.Forms.DataGridViewTextBoxColumn colDuration; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.ToolStripButton _buttonConvert; } diff --git a/src/SayMore/UI/ElementListScreen/ComponentFileGrid.cs b/src/SayMore/UI/ElementListScreen/ComponentFileGrid.cs index 4186f13f..f0d47f67 100644 --- a/src/SayMore/UI/ElementListScreen/ComponentFileGrid.cs +++ b/src/SayMore/UI/ElementListScreen/ComponentFileGrid.cs @@ -10,7 +10,6 @@ using System.Windows.Forms; using L10NSharp; using L10NSharp.XLiffUtils; -using L10NSharp.UI; using SIL.Reporting; using SIL.Windows.Forms.Widgets.BetterGrid; using SayMore.Model.Files; @@ -26,6 +25,7 @@ namespace SayMore.UI.ElementListScreen /// ---------------------------------------------------------------------------------------- public partial class ComponentFileGrid : UserControl { + private readonly ILocalizationManager _localizationManager; private IReadOnlyCollection _files; private string _gridColSettingPrefix; @@ -63,15 +63,16 @@ public partial class ComponentFileGrid : UserControl public bool ShowContextMenu { get; set; } /// ------------------------------------------------------------------------------------ - public ComponentFileGrid() + public ComponentFileGrid(ILocalizationManager localizationManager) { + _localizationManager = localizationManager; ShowContextMenu = true; Logger.WriteEvent("ComponentFileGrid constructor"); InitializeComponent(); Font = Program.DialogFont; - _toolStripActions.Renderer = new SIL.Windows.Forms.NoToolStripBorderRenderer(); + _toolStripActions.Renderer = new NoToolStripBorderRenderer(); try { @@ -110,12 +111,13 @@ public ComponentFileGrid() _menuDeleteFile.Click += (s, e) => DeleteFile(); - LocalizeItemDlg.StringsLocalized += HandleStringsLocalized; + localizationManager.UiLanguageChanged += HandleStringsLocalized; } /// ------------------------------------------------------------------------------------ - private void HandleStringsLocalized(ILocalizationManager lm) + private void HandleStringsLocalized(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; Debug.Assert(lm != null); // In this class, we never call this method directly. if (_grid != null && !_grid.IsDisposed && lm.Id == ApplicationContainer.kSayMoreLocalizationId) diff --git a/src/SayMore/UI/ElementListScreen/ComponentFileRenamingDialog.Designer.cs b/src/SayMore/UI/ElementListScreen/ComponentFileRenamingDialog.Designer.cs index 68d5a930..14554abf 100644 --- a/src/SayMore/UI/ElementListScreen/ComponentFileRenamingDialog.Designer.cs +++ b/src/SayMore/UI/ElementListScreen/ComponentFileRenamingDialog.Designer.cs @@ -53,7 +53,7 @@ private void InitializeComponent() this._messagePanel = new System.Windows.Forms.Panel(); this._warningIcon = new System.Windows.Forms.PictureBox(); this._labelMessage = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._tableLayout.SuspendLayout(); this._tableLayoutButtons.SuspendLayout(); this._tableLayoutTextBox.SuspendLayout(); @@ -511,7 +511,7 @@ private void InitializeComponent() private System.Windows.Forms.Label _labelPrefix; private System.Windows.Forms.Label _labelMessage; private System.Windows.Forms.Label _labelExtension; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Label _labelChangeNameTo; private System.Windows.Forms.FlowLayoutPanel _flowLayoutShortcuts; private System.Windows.Forms.Label _labelShortcuts; diff --git a/src/SayMore/UI/ElementListScreen/ElementGrid.cs b/src/SayMore/UI/ElementListScreen/ElementGrid.cs index d55007fc..50117cd0 100644 --- a/src/SayMore/UI/ElementListScreen/ElementGrid.cs +++ b/src/SayMore/UI/ElementListScreen/ElementGrid.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Windows.Forms; using L10NSharp; -using L10NSharp.UI; +using L10NSharp.Windows.Forms; using SIL.Extensions; using SIL.Windows.Forms.Widgets.BetterGrid; using SayMore.Model; @@ -27,8 +27,8 @@ public class ElementGrid : BetterGrid public Action DeleteAction; protected FileType _fileType; - private IEnumerable _items = new ProjectElement[] { }; - protected ContextMenuStrip _contextMenuStrip = new ContextMenuStrip(); + private IEnumerable _items = []; + protected ContextMenuStrip _contextMenuStrip = new(); protected readonly L10NSharpExtender _locExtender; /// ------------------------------------------------------------------------------------ diff --git a/src/SayMore/UI/ElementListScreen/ElementListScreen.cs b/src/SayMore/UI/ElementListScreen/ElementListScreen.cs index 2864fb01..06969e20 100644 --- a/src/SayMore/UI/ElementListScreen/ElementListScreen.cs +++ b/src/SayMore/UI/ElementListScreen/ElementListScreen.cs @@ -5,8 +5,6 @@ using System.Linq; using System.Windows.Forms; using L10NSharp; -using L10NSharp.XLiffUtils; -using L10NSharp.UI; using SIL.Windows.Forms.FileSystem; using SayMore.Model.Files; using SayMore.Model; @@ -35,6 +33,7 @@ namespace SayMore.UI.ElementListScreen public partial class ElementListScreen : UserControl where T : ProjectElement { protected readonly ElementListViewModel _model; + private readonly ILocalizationManager _localizationManagerm; protected ElementGrid _elementsGrid; protected TabControl _selectedEditorsTabControl; protected ListPanel _elementsListPanel; @@ -49,9 +48,10 @@ public partial class ElementListScreen : UserControl where T : ProjectElement public ToolStripMenuItem MainMenuItem { get; } /// ------------------------------------------------------------------------------------ - public ElementListScreen(ElementListViewModel presentationModel) + public ElementListScreen(ElementListViewModel presentationModel, ILocalizationManager lm) { _model = presentationModel; + _localizationManagerm = lm; MainMenuItem = new ToolStripMenuItem(); } @@ -99,19 +99,19 @@ protected void Initialize(Control tabControlHostControl, protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); - HandleStringsLocalized(null); - LocalizeItemDlg.StringsLocalized += HandleStringsLocalized; + HandleStringsLocalized(null, EventArgs.Empty); + _localizationManagerm.UiLanguageChanged += HandleStringsLocalized; } /// ------------------------------------------------------------------------------------ protected override void OnHandleDestroyed(EventArgs e) { - LocalizeItemDlg.StringsLocalized -= HandleStringsLocalized; + _localizationManagerm.UiLanguageChanged -= HandleStringsLocalized; base.OnHandleDestroyed(e); } /// ------------------------------------------------------------------------------------ - protected virtual void HandleStringsLocalized(ILocalizationManager lm) + protected virtual void HandleStringsLocalized(object sender, EventArgs e) { // Overridden in derived classes } @@ -138,8 +138,8 @@ private void HandleParentFormActivated(object sender, EventArgs e) if (_model.FileLoadErrors.Any()) { - using (var dlg = new FileLoadErrorsReportDlg(_model.FileLoadErrors)) - dlg.ShowDialog(this); + using var dlg = new FileLoadErrorsReportDlg(_model.FileLoadErrors); + dlg.ShowDialog(this); } // Do this in case some of the metadata changed (e.g. audio file was edited) diff --git a/src/SayMore/UI/ElementListScreen/PersonListScreen.Designer.cs b/src/SayMore/UI/ElementListScreen/PersonListScreen.Designer.cs index 418937d3..b82048ae 100644 --- a/src/SayMore/UI/ElementListScreen/PersonListScreen.Designer.cs +++ b/src/SayMore/UI/ElementListScreen/PersonListScreen.Designer.cs @@ -36,7 +36,7 @@ private void InitializeComponent() this._componentsSplitter = new System.Windows.Forms.SplitContainer(); this._personComponentFileGrid = new SayMore.UI.ElementListScreen.ComponentFileGrid(); this._labelClickNewHelpPrompt = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._elementListSplitter.Panel1.SuspendLayout(); this._elementListSplitter.Panel2.SuspendLayout(); this._elementListSplitter.SuspendLayout(); @@ -170,6 +170,6 @@ private void InitializeComponent() private System.Windows.Forms.SplitContainer _componentsSplitter; private ComponentFileGrid _personComponentFileGrid; private System.Windows.Forms.Label _labelClickNewHelpPrompt; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; } } diff --git a/src/SayMore/UI/ElementListScreen/PersonListScreen.cs b/src/SayMore/UI/ElementListScreen/PersonListScreen.cs index 7fd6b8fa..a6e8f11d 100644 --- a/src/SayMore/UI/ElementListScreen/PersonListScreen.cs +++ b/src/SayMore/UI/ElementListScreen/PersonListScreen.cs @@ -14,7 +14,8 @@ public partial class PersonListScreen : ConcretePersonListScreen, ISayMoreView { /// ------------------------------------------------------------------------------------ public PersonListScreen(ElementListViewModel presentationModel, - PersonGrid.Factory personGridFactory) : base(presentationModel) + PersonGrid.Factory personGridFactory, ILocalizationManager localizationManager) : + base(presentationModel, localizationManager) { Logger.WriteEvent("PersonListScreen constructor"); @@ -47,8 +48,9 @@ public PersonListScreen(ElementListViewModel presentationModel, } /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { _personComponentFileGrid.AddFileButtonTooltipText = @@ -93,28 +95,16 @@ void HandleLastSetOfComponentEditorsRemoved(object sender, ControlEventArgs e) } /// ------------------------------------------------------------------------------------ - public Image Image - { - get { return ResourceImageCache.People; } - } + public Image Image => ResourceImageCache.People; /// ------------------------------------------------------------------------------------ - public string NameForUsageReporting - { - get { return "People"; } - } + public string NameForUsageReporting => "People"; /// ------------------------------------------------------------------------------------ - protected override Color ComponentEditorBackgroundColor - { - get { return Settings.Default.PersonEditorsBackgroundColor; } - } + protected override Color ComponentEditorBackgroundColor => Settings.Default.PersonEditorsBackgroundColor; /// ------------------------------------------------------------------------------------ - protected override Color ComponentEditorBorderColor - { - get { return Settings.Default.PersonEditorsBorderColor; } - } + protected override Color ComponentEditorBorderColor => Settings.Default.PersonEditorsBorderColor; /// ------------------------------------------------------------------------------------ public void AddTabToTabGroup(ViewTabGroup viewTabGroup) @@ -161,18 +151,18 @@ protected override void OnHandleDestroyed(EventArgs e) /// /// This class is used to overcome a limitation in the VS 2008 designer: /// not only can it not design a generic class, but it cannot even design a class which - /// directly inhertis from a generic class! So we have this intermediate class. + /// directly inherits from a generic class! So we have this intermediate class. /// /// ---------------------------------------------------------------------------------------- public class ConcretePersonListScreen : ElementListScreen { //design time only - private ConcretePersonListScreen() - : base(null) + private ConcretePersonListScreen() : base(null, null) {} - public ConcretePersonListScreen(ElementListViewModel presentationModel) - : base(presentationModel) + public ConcretePersonListScreen(ElementListViewModel presentationModel, + ILocalizationManager localizationManager) + : base(presentationModel, localizationManager) {} } } diff --git a/src/SayMore/UI/ElementListScreen/SessionsListScreen.Designer.cs b/src/SayMore/UI/ElementListScreen/SessionsListScreen.Designer.cs index b45438ea..e63d74f0 100644 --- a/src/SayMore/UI/ElementListScreen/SessionsListScreen.Designer.cs +++ b/src/SayMore/UI/ElementListScreen/SessionsListScreen.Designer.cs @@ -26,7 +26,7 @@ private void InitializeComponent() this._componentsSplitter = new System.Windows.Forms.SplitContainer(); this._sessionComponentFileGrid = new SayMore.UI.ElementListScreen.ComponentFileGrid(); this._labelClickNewHelpPrompt = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); ((System.ComponentModel.ISupportInitialize)(this._elementListSplitter)).BeginInit(); this._elementListSplitter.Panel1.SuspendLayout(); this._elementListSplitter.Panel2.SuspendLayout(); @@ -204,7 +204,7 @@ private void InitializeComponent() private ComponentFileGrid _sessionComponentFileGrid; private System.Windows.Forms.Button _buttonNewFromFiles; private System.Windows.Forms.Label _labelClickNewHelpPrompt; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Button _buttonNewFromRecording; public string NameForUsageReporting diff --git a/src/SayMore/UI/ElementListScreen/SessionsListScreen.cs b/src/SayMore/UI/ElementListScreen/SessionsListScreen.cs index d59a897f..34fcd7f9 100644 --- a/src/SayMore/UI/ElementListScreen/SessionsListScreen.cs +++ b/src/SayMore/UI/ElementListScreen/SessionsListScreen.cs @@ -21,8 +21,8 @@ public partial class SessionsListScreen : ConcreteSessionScreen, ISayMoreView /// ------------------------------------------------------------------------------------ public SessionsListScreen(ElementListViewModel presentationModel, NewSessionsFromFileDlgViewModel.Factory newSessionsFromFileDlgViewModel, - SessionsGrid.Factory sessionGridFactory) - : base(presentationModel) + SessionsGrid.Factory sessionGridFactory, ILocalizationManager localizationManager) + : base(presentationModel, localizationManager) { Logger.WriteEvent("PersonListScreen constructor"); @@ -59,8 +59,9 @@ public SessionsListScreen(ElementListViewModel presentationModel, } /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { _sessionComponentFileGrid.AddFileButtonTooltipText = LocalizationManager.GetString( @@ -156,22 +157,13 @@ public override void ViewDeactivated() } /// ------------------------------------------------------------------------------------ - public Image Image - { - get { return ResourceImageCache.Sessions; } - } + public Image Image => ResourceImageCache.Sessions; /// ------------------------------------------------------------------------------------ - protected override Color ComponentEditorBackgroundColor - { - get { return Settings.Default.SessionEditorsBackgroundColor; } - } + protected override Color ComponentEditorBackgroundColor => Settings.Default.SessionEditorsBackgroundColor; /// ------------------------------------------------------------------------------------ - protected override Color ComponentEditorBorderColor - { - get { return Settings.Default.SessionEditorsBorderColor; } - } + protected override Color ComponentEditorBorderColor => Settings.Default.SessionEditorsBorderColor; /// ------------------------------------------------------------------------------------ protected override void OnHandleDestroyed(EventArgs e) @@ -187,14 +179,12 @@ private void HandleButtonNewFromFilesClick(object sender, EventArgs e) if (!_elementsGrid.IsOKToSelectDifferentElement()) return; - using (var viewModel = _newSessionsFromFileDlgViewModel(_model)) - using (var dlg = new NewSessionsFromFilesDlg(viewModel)) - { - if (dlg.ShowDialog(FindForm()) == DialogResult.OK) - LoadElementList(viewModel.FirstNewSessionAdded); + using var viewModel = _newSessionsFromFileDlgViewModel(_model); + using var dlg = new NewSessionsFromFilesDlg(viewModel); + if (dlg.ShowDialog(FindForm()) == DialogResult.OK) + LoadElementList(viewModel.FirstNewSessionAdded); - SetFocusOnId(); - } + SetFocusOnId(); } /// ------------------------------------------------------------------------------------ @@ -203,18 +193,16 @@ private void HandleButtonNewFromRecordingsClick(object sender, EventArgs e) if (!_elementsGrid.IsOKToSelectDifferentElement() || !AudioUtils.GetCanRecordAudio()) return; - using (var viewModel = new SessionRecorderDlgViewModel()) - using (var dlg = new SessionRecorderDlg(viewModel)) - { - if (dlg.ShowDialog(FindForm()) != DialogResult.OK) - return; + using var viewModel = new SessionRecorderDlgViewModel(); + using var dlg = new SessionRecorderDlg(viewModel); + if (dlg.ShowDialog(FindForm()) != DialogResult.OK) + return; - var newSession = _model.CreateNewElement(); - viewModel.MoveRecordingToSessionFolder(newSession); - LoadElementList(newSession); + var newSession = _model.CreateNewElement(); + viewModel.MoveRecordingToSessionFolder(newSession); + LoadElementList(newSession); - SetFocusOnId(); - } + SetFocusOnId(); } /// SP-55: Set focus to id field after creating a new session, and select the text @@ -261,11 +249,12 @@ public class ConcreteSessionScreen : ElementListScreen { //design time only private ConcreteSessionScreen() - : base(null) + : base(null, null) {} - public ConcreteSessionScreen(ElementListViewModel presentationModel) - : base(presentationModel) + public ConcreteSessionScreen(ElementListViewModel presentationModel, + ILocalizationManager localizationManager) + : base(presentationModel, localizationManager) {} } } diff --git a/src/SayMore/UI/LoadingDlg.Designer.cs b/src/SayMore/UI/LoadingDlg.Designer.cs index 86be78d9..216368b0 100644 --- a/src/SayMore/UI/LoadingDlg.Designer.cs +++ b/src/SayMore/UI/LoadingDlg.Designer.cs @@ -32,7 +32,7 @@ private void InitializeComponent() this._labelLoading = new System.Windows.Forms.Label(); this._linkCancel = new System.Windows.Forms.LinkLabel(); this._pictureLoading = new System.Windows.Forms.PictureBox(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); ((System.ComponentModel.ISupportInitialize)(this._pictureLoading)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); @@ -153,7 +153,7 @@ private void InitializeComponent() private System.Windows.Forms.Label _labelLoading; private System.Windows.Forms.PictureBox _pictureLoading; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.LinkLabel _linkCancel; private System.Windows.Forms.TableLayoutPanel _tableLayoutPanel; } diff --git a/src/SayMore/UI/LowLevelControls/DeleteMessageBox.Designer.cs b/src/SayMore/UI/LowLevelControls/DeleteMessageBox.Designer.cs index 2f5abbbe..394b2314 100644 --- a/src/SayMore/UI/LowLevelControls/DeleteMessageBox.Designer.cs +++ b/src/SayMore/UI/LowLevelControls/DeleteMessageBox.Designer.cs @@ -35,7 +35,7 @@ private void InitializeComponent() this._buttonDelete = new System.Windows.Forms.Button(); this._buttonCancel = new System.Windows.Forms.Button(); this._tableLayoutButtons = new System.Windows.Forms.TableLayoutPanel(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._tableLayoutMessage.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this._pictureDeleteX)).BeginInit(); this._tableLayoutButtons.SuspendLayout(); @@ -194,6 +194,6 @@ private void InitializeComponent() private System.Windows.Forms.Button _buttonCancel; private SIL.Windows.Forms.Widgets.AutoHeightLabel _labelMessage; private System.Windows.Forms.TableLayoutPanel _tableLayoutButtons; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; } } \ No newline at end of file diff --git a/src/SayMore/UI/LowLevelControls/ListPanel.Designer.cs b/src/SayMore/UI/LowLevelControls/ListPanel.Designer.cs index f052ab11..591cddbe 100644 --- a/src/SayMore/UI/LowLevelControls/ListPanel.Designer.cs +++ b/src/SayMore/UI/LowLevelControls/ListPanel.Designer.cs @@ -1,5 +1,6 @@ using L10NSharp; -using L10NSharp.UI; +using L10NSharp.Windows.Forms; +using L10NSharp.Windows.Forms.UIComponents; namespace SayMore.UI.LowLevelControls { @@ -20,7 +21,7 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ListPanel)); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._outerPanel = new SIL.Windows.Forms.Widgets.EnhancedPanel(); this._buttonsFlowLayoutPanel = new System.Windows.Forms.FlowLayoutPanel(); this._buttonNew = new System.Windows.Forms.Button(); diff --git a/src/SayMore/UI/NewSessionsFromFiles/NewSessionsFromFilesDlg.designer.cs b/src/SayMore/UI/NewSessionsFromFiles/NewSessionsFromFilesDlg.designer.cs index 7ad3891c..84e1b74c 100644 --- a/src/SayMore/UI/NewSessionsFromFiles/NewSessionsFromFilesDlg.designer.cs +++ b/src/SayMore/UI/NewSessionsFromFiles/NewSessionsFromFilesDlg.designer.cs @@ -45,7 +45,7 @@ private void InitializeComponent() this._tableLayoutButtons = new System.Windows.Forms.TableLayoutPanel(); this._gridFiles = new SayMore.UI.ElementListScreen.ComponentFileGrid(); this._panelMetadata = new System.Windows.Forms.Panel(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._mediaPlayerPanel.SuspendLayout(); this._panelProgress.SuspendLayout(); this._outerTableLayout.SuspendLayout(); @@ -346,6 +346,6 @@ private void InitializeComponent() private System.Windows.Forms.Panel _panelMetadata; private SayMore.UI.ElementListScreen.ComponentFileGrid _gridFiles; private System.Windows.Forms.TableLayoutPanel _tableLayoutButtons; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; } } \ No newline at end of file diff --git a/src/SayMore/UI/NewSessionsFromFiles/NewSessionsFromFilesDlgFolderNotFoundMsg.designer.cs b/src/SayMore/UI/NewSessionsFromFiles/NewSessionsFromFilesDlgFolderNotFoundMsg.designer.cs index 81b554f8..722c1322 100644 --- a/src/SayMore/UI/NewSessionsFromFiles/NewSessionsFromFilesDlgFolderNotFoundMsg.designer.cs +++ b/src/SayMore/UI/NewSessionsFromFiles/NewSessionsFromFilesDlgFolderNotFoundMsg.designer.cs @@ -35,7 +35,7 @@ private void InitializeComponent() this._tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); this._labelPossibleProblemsMsg2 = new SIL.Windows.Forms.Widgets.AutoHeightLabel(); this._labelPossibleProblemsMsg3 = new SIL.Windows.Forms.Widgets.AutoHeightLabel(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._tableLayoutPanel.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); this.SuspendLayout(); @@ -187,6 +187,6 @@ private void InitializeComponent() private System.Windows.Forms.TableLayoutPanel _tableLayoutPanel; private SIL.Windows.Forms.Widgets.AutoHeightLabel _labelPossibleProblemsMsg2; private SIL.Windows.Forms.Widgets.AutoHeightLabel _labelPossibleProblemsMsg3; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; } } diff --git a/src/SayMore/UI/Overview/ProgressScreen.cs b/src/SayMore/UI/Overview/ProgressScreen.cs index a5d74075..0eeb2a7a 100644 --- a/src/SayMore/UI/Overview/ProgressScreen.cs +++ b/src/SayMore/UI/Overview/ProgressScreen.cs @@ -19,7 +19,7 @@ public ProgressScreen(StatisticsViewModel statisticsModel) Logger.WriteEvent("ProgressScreen constructor"); InitializeComponent(); - _statsView = new StatisticsView(statisticsModel) {Dock = DockStyle.Fill}; + _statsView = new StatisticsView(statisticsModel, TODO) {Dock = DockStyle.Fill}; Controls.Add(_statsView); _mnuProgress = new ToolStripMenuItem diff --git a/src/SayMore/UI/Overview/ProjectAccessScreen.Designer.cs b/src/SayMore/UI/Overview/ProjectAccessScreen.Designer.cs index 30984b37..2004af16 100644 --- a/src/SayMore/UI/Overview/ProjectAccessScreen.Designer.cs +++ b/src/SayMore/UI/Overview/ProjectAccessScreen.Designer.cs @@ -1,5 +1,4 @@ -using L10NSharp.XLiffUtils; -using L10NSharp.UI; +using L10NSharp.Windows.Forms.UIComponents; namespace SayMore.UI.Overview { @@ -18,7 +17,7 @@ protected override void Dispose(bool disposing) { if (disposing) { - LocalizeItemDlg.StringsLocalized -= HandleStringsLocalized; + _localizationManager.UiLanguageChanged -= HandleStringsLocalized; if (components != null) components.Dispose(); } @@ -40,7 +39,7 @@ private void InitializeComponent() this._labelCustomAccess = new System.Windows.Forms.Label(); this._labelCustomInstructions = new System.Windows.Forms.Label(); this._customAccessChoices = new System.Windows.Forms.TextBox(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._webBrowser = new System.Windows.Forms.WebBrowser(); this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); this._linkHelp = new System.Windows.Forms.LinkLabel(); @@ -233,7 +232,7 @@ private void InitializeComponent() private System.Windows.Forms.TableLayoutPanel _layoutTable; private System.Windows.Forms.Label _labelAccessProtocol; private System.Windows.Forms.ComboBox _projectAccess; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Label _labelCustomAccess; private System.Windows.Forms.Label _labelCustomInstructions; private System.Windows.Forms.TextBox _customAccessChoices; diff --git a/src/SayMore/UI/Overview/ProjectAccessScreen.cs b/src/SayMore/UI/Overview/ProjectAccessScreen.cs index 938fcc30..b7067d9f 100644 --- a/src/SayMore/UI/Overview/ProjectAccessScreen.cs +++ b/src/SayMore/UI/Overview/ProjectAccessScreen.cs @@ -4,8 +4,6 @@ using System.Linq; using System.Windows.Forms; using L10NSharp; -using L10NSharp.XLiffUtils; -using L10NSharp.UI; using SIL.IO; using SIL.Reporting; using SIL.Archiving.Generic.AccessProtocol; @@ -14,20 +12,22 @@ namespace SayMore.UI.Overview { public partial class ProjectAccessScreen : UserControl, ISaveable { + private readonly ILocalizationManager _localizationManager; private bool _isLoaded; private string _currentUri; private string _archivingFileDirectoryName; /// ------------------------------------------------------------------------------------ - public ProjectAccessScreen() + public ProjectAccessScreen(ILocalizationManager localizationManager) { + _localizationManager = localizationManager; Logger.WriteEvent("ProjectAccessScreen constructor"); InitializeComponent(); // access protocol list - HandleStringsLocalized(null); - LocalizeItemDlg.StringsLocalized += HandleStringsLocalized; + HandleStringsLocalized(null, EventArgs.Empty); + localizationManager.UiLanguageChanged += HandleStringsLocalized; _linkHelp.Click += (s, e) => Program.ShowHelpTopic("/Using_Tools/Project_tab/Choose_Access_Protocol.htm"); @@ -40,8 +40,9 @@ private string GetBaseUriDirectory() } /// ------------------------------------------------------------------------------------ - private void HandleStringsLocalized(ILocalizationManager lm) + private void HandleStringsLocalized(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; if (lm != null && lm.Id != ApplicationContainer.kSayMoreLocalizationId) return; diff --git a/src/SayMore/UI/Overview/ProjectDocsScreen.Designer.cs b/src/SayMore/UI/Overview/ProjectDocsScreen.Designer.cs index 6104d217..608cad90 100644 --- a/src/SayMore/UI/Overview/ProjectDocsScreen.Designer.cs +++ b/src/SayMore/UI/Overview/ProjectDocsScreen.Designer.cs @@ -31,7 +31,7 @@ private void InitializeComponent() this.components = new System.ComponentModel.Container(); this._labelInformation = new System.Windows.Forms.Label(); this._linkHowArchived = new System.Windows.Forms.LinkLabel(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._descriptionFileGrid = new SayMore.UI.ElementListScreen.ComponentFileGrid(); this._layoutTable = new System.Windows.Forms.TableLayoutPanel(); this._splitter = new System.Windows.Forms.SplitContainer(); @@ -155,7 +155,7 @@ private void InitializeComponent() #endregion - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.LinkLabel _linkHowArchived; private System.Windows.Forms.TableLayoutPanel _layoutTable; protected System.Windows.Forms.Label _labelInformation; diff --git a/src/SayMore/UI/Overview/ProjectDocsScreen.cs b/src/SayMore/UI/Overview/ProjectDocsScreen.cs index e867b464..3ab43645 100644 --- a/src/SayMore/UI/Overview/ProjectDocsScreen.cs +++ b/src/SayMore/UI/Overview/ProjectDocsScreen.cs @@ -17,16 +17,19 @@ namespace SayMore.UI.Overview { public abstract partial class ProjectDocsScreen : EditorBase, ISayMoreView { + private readonly ILocalizationManager _localizationManager; private const string kOfficeTempPrefix = "~$"; protected abstract string FolderName { get; } protected abstract string ArchiveSessionName { get; } - private readonly ImageList _tabControlImages = new ImageList(); + private readonly ImageList _tabControlImages = new(); private ComponentEditorsTabControl _tabCtrl; protected string _toolTipText; - protected ProjectDocsScreen() + protected ProjectDocsScreen(ILocalizationManager localizationManager) : + base(localizationManager) { + _localizationManager = localizationManager; Logger.WriteEvent("ProjectDocsScreen constructor"); InitializeComponent(); @@ -87,9 +90,10 @@ protected override void OnHandleCreated(EventArgs e) LocalizeStrings(); } - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); + var lm = (ILocalizationManager)sender; if ((lm == null || lm.Id == kSayMoreLocalizationId) && _descriptionFileGrid != null) LocalizeStrings(); } @@ -145,7 +149,7 @@ private IReadOnlyCollection GetFiles() { var dir = Path.Combine(Program.CurrentProject.FolderPath, FolderName); if (!Directory.Exists(dir)) - return new ComponentFile[0]; + return []; var unknownFileType = new FileType[] {new UnknownFileType(null, null), new AudioFileType(null, null, null), new VideoFileType(null, null, null), new ImageFileType(null, null) }; @@ -188,9 +192,9 @@ private void HandleAfterComponentFileSelected(int index) List providers = new List(); if ((file.FileType is AudioFileType) || (file.FileType is VideoFileType)) - providers.Add(new AudioVideoPlayer(file, null)); + providers.Add(new AudioVideoPlayer(file, null, _localizationManager)); else if (file.FileType is ImageFileType) - providers.Add(new ImageViewer(file)); + providers.Add(new ImageViewer(file, _localizationManager)); else providers.Add(new BrowserEditor(file, null)); @@ -237,7 +241,8 @@ public class ProjectDescriptionDocsScreen : ProjectDocsScreen internal static string kFolderName = "DescriptionDocuments"; internal static string kArchiveSessionName = "Project Description Documents"; - public ProjectDescriptionDocsScreen() + public ProjectDescriptionDocsScreen(ILocalizationManager localizationManager) : + base(localizationManager) { _descriptionFileGrid.InitializeGrid("ProjectDescriptionDocuments"); } @@ -263,7 +268,8 @@ public class ProjectOtherDocsScreen : ProjectDocsScreen internal static string kFolderName = "OtherDocuments"; internal static string kArchiveSessionName = "Other Project Documents"; - public ProjectOtherDocsScreen() + public ProjectOtherDocsScreen(ILocalizationManager localizationManager) : + base(localizationManager) { _descriptionFileGrid.InitializeGrid("ProjectOtherDocuments"); } diff --git a/src/SayMore/UI/Overview/ProjectMetadataScreen.Designer.cs b/src/SayMore/UI/Overview/ProjectMetadataScreen.Designer.cs index 2c159cd3..1337875a 100644 --- a/src/SayMore/UI/Overview/ProjectMetadataScreen.Designer.cs +++ b/src/SayMore/UI/Overview/ProjectMetadataScreen.Designer.cs @@ -81,7 +81,7 @@ private void InitializeComponent() this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); this._labelsubOfTheProject = new System.Windows.Forms.Label(); this._labelDescription = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._errorProvider = new System.Windows.Forms.ErrorProvider(this.components); this._tableLayout.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout(); @@ -1014,7 +1014,7 @@ private void InitializeComponent() private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; private System.Windows.Forms.Label _labelSelectedContentLanguage; private System.Windows.Forms.LinkLabel _linkSelectContentLanguage; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Label _labelRegion; private System.Windows.Forms.TextBox _region; private System.Windows.Forms.Label _labelDateAvailable; diff --git a/src/SayMore/UI/Overview/ProjectMetadataScreen.cs b/src/SayMore/UI/Overview/ProjectMetadataScreen.cs index 641887d9..cd4d0f8f 100644 --- a/src/SayMore/UI/Overview/ProjectMetadataScreen.cs +++ b/src/SayMore/UI/Overview/ProjectMetadataScreen.cs @@ -23,7 +23,7 @@ public partial class ProjectMetadataScreen : EditorBase, ISayMoreView, ISaveable private string _fmtFontForWorkingLanguage; private readonly IMDIItemList _countryList; - public ProjectMetadataScreen() + public ProjectMetadataScreen(ILocalizationManager localizationManager) : base(localizationManager) { Logger.WriteEvent("ProjectMetadataScreen constructor"); @@ -52,16 +52,17 @@ public ProjectMetadataScreen() } /// ------------------------------------------------------------------------------------ - protected override void HandleStringsLocalized(ILocalizationManager lm) + protected override void HandleStringsLocalized(object sender, EventArgs e) { - base.HandleStringsLocalized(lm); + base.HandleStringsLocalized(sender, e); + var lm = (ILocalizationManager)sender; if (lm != null && lm.Id != ApplicationContainer.kSayMoreLocalizationId) return; if (_linkSelectFontForWorkingLanguage == null) { - Load += (o, args) => + Load += (_, _) => { Debug.Assert(_linkSelectFontForWorkingLanguage != null); _fmtFontForWorkingLanguage = _linkSelectFontForWorkingLanguage.Text; diff --git a/src/SayMore/UI/Overview/ProjectScreen.cs b/src/SayMore/UI/Overview/ProjectScreen.cs index 199f4604..2f69adf3 100644 --- a/src/SayMore/UI/Overview/ProjectScreen.cs +++ b/src/SayMore/UI/Overview/ProjectScreen.cs @@ -1,9 +1,8 @@ +using System; using System.Collections.Generic; using System.Drawing; using L10NSharp; using System.Windows.Forms; -using L10NSharp.XLiffUtils; -using L10NSharp.UI; using SIL.Reporting; using SayMore.UI.ComponentEditors; using SayMore.UI.ProjectWindow; @@ -22,10 +21,13 @@ public partial class ProjectScreen : UserControl, ISayMoreView, ISaveable private readonly ProjectAccessScreen _accessView; private readonly ProjectDocsScreen _descriptionDocsView; private readonly ProjectOtherDocsScreen _otherDocsView; + private readonly ILocalizationManager _localizationManager; private bool _statsViewActivated; /// ------------------------------------------------------------------------------------ - public ProjectScreen(ProjectMetadataScreen metadataView, ProjectAccessScreen accessView, ProgressScreen progressView, ProjectDescriptionDocsScreen descriptionDocsView, ProjectOtherDocsScreen otherDocsView) + public ProjectScreen(ProjectMetadataScreen metadataView, ProjectAccessScreen accessView, + ProgressScreen progressView, ProjectDescriptionDocsScreen descriptionDocsView, + ProjectOtherDocsScreen otherDocsView, ILocalizationManager localizationManager) { Logger.WriteEvent("ProjectScreen constructor"); @@ -34,10 +36,11 @@ public ProjectScreen(ProjectMetadataScreen metadataView, ProjectAccessScreen acc _accessView = accessView; _descriptionDocsView = descriptionDocsView; _otherDocsView = otherDocsView; + _localizationManager = localizationManager; InitializeComponent(); - HandleStringsLocalized(null); + HandleStringsLocalized(null, EventArgs.Empty); _splitter.Panel2.BackColor = Color.FromArgb(230, 150, 100); _metadataView.BackColor = _splitter.Panel2.BackColor; _progressView.BackColor = _splitter.Panel2.BackColor; @@ -45,7 +48,7 @@ public ProjectScreen(ProjectMetadataScreen metadataView, ProjectAccessScreen acc _descriptionDocsView.BackColor = _splitter.Panel2.BackColor; _otherDocsView.BackColor = _splitter.Panel2.BackColor; - LocalizeItemDlg.StringsLocalized += HandleStringsLocalized; + localizationManager.UiLanguageChanged += HandleStringsLocalized; } /// ------------------------------------------------------------------------------------ @@ -58,7 +61,7 @@ protected override void Dispose(bool disposing) if (disposing) { // SP-788: "Cannot access a disposed object" when changing UI language - LocalizeItemDlg.StringsLocalized -= HandleStringsLocalized; + _localizationManager.UiLanguageChanged -= HandleStringsLocalized; if (components != null) components.Dispose(); @@ -68,8 +71,9 @@ protected override void Dispose(bool disposing) } /// ------------------------------------------------------------------------------------ - private void HandleStringsLocalized(ILocalizationManager lm) + private void HandleStringsLocalized(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; if (lm != null && lm.Id != ApplicationContainer.kSayMoreLocalizationId) return; diff --git a/src/SayMore/UI/Overview/Statistics/StatisticsView.Designer.cs b/src/SayMore/UI/Overview/Statistics/StatisticsView.Designer.cs index 2393df3a..90b9fe44 100644 --- a/src/SayMore/UI/Overview/Statistics/StatisticsView.Designer.cs +++ b/src/SayMore/UI/Overview/Statistics/StatisticsView.Designer.cs @@ -13,10 +13,11 @@ partial class StatisticsView /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { - if (disposing && (components != null)) + if (disposing) { - components.Dispose(); - } + components?.Dispose(); + _localizationManager.UiLanguageChanged -= UpdateDisplay; + } base.Dispose(disposing); } @@ -35,7 +36,7 @@ private void InitializeComponent() this._tableLayoutWorking = new System.Windows.Forms.TableLayoutPanel(); this._labelWorking = new System.Windows.Forms.Label(); this._pictureWorking = new System.Windows.Forms.PictureBox(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._toolStripActions = new SayMore.UI.LowLevelControls.ElementBar(); this._buttonRefresh = new System.Windows.Forms.ToolStripButton(); this._buttonCopy = new System.Windows.Forms.ToolStripButton(); @@ -289,7 +290,7 @@ private void InitializeComponent() private SIL.Windows.Forms.Widgets.EnhancedPanel _panelWorking; private System.Windows.Forms.PictureBox _pictureWorking; private System.Windows.Forms.TableLayoutPanel _tableLayoutWorking; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.ToolStripButton _buttonCopy; private System.Windows.Forms.ToolStripButton _buttonSave; private System.Windows.Forms.ToolStripButton _buttonPrint; diff --git a/src/SayMore/UI/Overview/Statistics/StatisticsView.cs b/src/SayMore/UI/Overview/Statistics/StatisticsView.cs index 7869ac8a..eccd4b7c 100644 --- a/src/SayMore/UI/Overview/Statistics/StatisticsView.cs +++ b/src/SayMore/UI/Overview/Statistics/StatisticsView.cs @@ -4,9 +4,7 @@ using System.Threading; using System.Windows.Forms; using L10NSharp; -using L10NSharp.XLiffUtils; using Microsoft.Win32; -using L10NSharp.UI; using SIL.Reporting; namespace SayMore.UI.Overview.Statistics @@ -14,13 +12,15 @@ namespace SayMore.UI.Overview.Statistics public partial class StatisticsView : UserControl { private readonly StatisticsViewModel _model; + private readonly ILocalizationManager _localizationManager; /// ------------------------------------------------------------------------------------ - public StatisticsView(StatisticsViewModel model) + public StatisticsView(StatisticsViewModel model, ILocalizationManager localizationManager) { Logger.WriteEvent("StatisticsView constructor"); _model = model; + _localizationManager = localizationManager; InitializeComponent(); _panelWorking.BorderStyle = BorderStyle.None; @@ -32,7 +32,7 @@ protected override void OnHandleDestroyed(EventArgs e) { base.OnHandleDestroyed(e); - LocalizeItemDlg.StringsLocalized -= UpdateDisplay; + _localizationManager.UiLanguageChanged -= UpdateDisplay; _model.FinishedGatheringStatisticsForAllFiles -= HandleNewDataAvailable; _model.NewStatisticsAvailable -= HandleNewDataAvailable; } @@ -46,15 +46,16 @@ public void InitializeView() if (_model.IsDataUpToDate) { _model.NewStatisticsAvailable += HandleNewDataAvailable; - UpdateDisplay(); + UpdateDisplay(null, EventArgs.Empty); } - LocalizeItemDlg.StringsLocalized += UpdateDisplay; + _localizationManager.UiLanguageChanged += UpdateDisplay; } /// ------------------------------------------------------------------------------------ - private void UpdateDisplay(ILocalizationManager lm = null) + private void UpdateDisplay(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; if (lm != null && lm.Id != ApplicationContainer.kSayMoreLocalizationId) return; @@ -77,9 +78,11 @@ private void UpdateDisplay(ILocalizationManager lm = null) _timerDetectBrowserRefreshedUsingContextMenu.Enabled = true; })); - }); - updateDisplayThread.Name = "StatisticsView.UpdateDisplay"; - updateDisplayThread.IsBackground = true; + }) + { + Name = "StatisticsView.UpdateDisplay", + IsBackground = true + }; updateDisplayThread.Start(); } @@ -151,15 +154,13 @@ public void HandleSaveButtonClicked(object sender, EventArgs e) // I could use the browser's ShowSaveAsDialog method, but that // doesn't give me as much control over the dialog's settings. - using (var dlg = new System.Windows.Forms.SaveFileDialog()) - { - dlg.DefaultExt = "html"; - dlg.Filter = @"HTML File (*.html)|*.html|All Files (*.*)|*.*"; - dlg.FileName = Path.ChangeExtension(_webBrowser.DocumentTitle, "html"); - dlg.OverwritePrompt = true; - if (dlg.ShowDialog() == DialogResult.OK) - File.WriteAllText(dlg.FileName, _webBrowser.DocumentText); - } + using var dlg = new System.Windows.Forms.SaveFileDialog(); + dlg.DefaultExt = "html"; + dlg.Filter = @"HTML File (*.html)|*.html|All Files (*.*)|*.*"; + dlg.FileName = Path.ChangeExtension(_webBrowser.DocumentTitle, "html"); + dlg.OverwritePrompt = true; + if (dlg.ShowDialog() == DialogResult.OK) + File.WriteAllText(dlg.FileName, _webBrowser.DocumentText); } /// ------------------------------------------------------------------------------------ @@ -180,7 +181,7 @@ void HandleNewDataAvailable(object sender, EventArgs e) // Can't actually call UpdateDisplay from here because this event is fired from // a background (data gathering) thread and updating the browser control on the // background thread is a no-no. - BeginInvoke(new Action(() => UpdateDisplay())); + BeginInvoke(new Action(() => UpdateDisplay(null, EventArgs.Empty))); } private void _detectContextMenuRefreshTimer_Tick(object sender, EventArgs e) diff --git a/src/SayMore/UI/ProgressDlg.Designer.cs b/src/SayMore/UI/ProgressDlg.Designer.cs index 3e10d030..ea8cdb05 100644 --- a/src/SayMore/UI/ProgressDlg.Designer.cs +++ b/src/SayMore/UI/ProgressDlg.Designer.cs @@ -32,7 +32,7 @@ private void InitializeComponent() this._buttonOK = new System.Windows.Forms.Button(); this._tableLayout = new System.Windows.Forms.TableLayoutPanel(); this._buttonCancel = new System.Windows.Forms.Button(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._tableLayout.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); this.SuspendLayout(); @@ -126,7 +126,7 @@ private void InitializeComponent() private System.Windows.Forms.Button _buttonOK; private System.Windows.Forms.TableLayoutPanel _tableLayout; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.Button _buttonCancel; } } \ No newline at end of file diff --git a/src/SayMore/UI/ProjectChoosingAndCreating/NewProjectDialog/NewProjectDlg.Designer.cs b/src/SayMore/UI/ProjectChoosingAndCreating/NewProjectDialog/NewProjectDlg.Designer.cs index 78cc3a4a..97033154 100644 --- a/src/SayMore/UI/ProjectChoosingAndCreating/NewProjectDialog/NewProjectDlg.Designer.cs +++ b/src/SayMore/UI/ProjectChoosingAndCreating/NewProjectDialog/NewProjectDlg.Designer.cs @@ -1,4 +1,5 @@ -using L10NSharp.UI; +using L10NSharp.Windows.Forms; +using L10NSharp.Windows.Forms.UIComponents; namespace SayMore.UI.ProjectChoosingAndCreating.NewProjectDialog { @@ -32,7 +33,7 @@ private void InitializeComponent() this._buttonCancel = new System.Windows.Forms.Button(); this._textBoxName = new System.Windows.Forms.TextBox(); this._labelNewProjectPath = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); this.SuspendLayout(); // diff --git a/src/SayMore/UI/ProjectChoosingAndCreating/WelcomeDialog.Designer.cs b/src/SayMore/UI/ProjectChoosingAndCreating/WelcomeDialog.Designer.cs index 24293a58..3665c58b 100644 --- a/src/SayMore/UI/ProjectChoosingAndCreating/WelcomeDialog.Designer.cs +++ b/src/SayMore/UI/ProjectChoosingAndCreating/WelcomeDialog.Designer.cs @@ -1,6 +1,7 @@ using L10NSharp; +using L10NSharp.Windows.Forms; using L10NSharp.XLiffUtils; -using L10NSharp.UI; +using L10NSharp.Windows.Forms.UIComponents; using SayMore.UI.LowLevelControls; namespace SayMore.UI.ProjectChoosingAndCreating @@ -19,12 +20,7 @@ sealed partial class WelcomeDialog protected override void Dispose(bool disposing) { if (disposing) - { - if (components != null) - components.Dispose(); - - LocalizeItemDlg.StringsLocalized -= LocalizationInitiated; - } + components?.Dispose(); base.Dispose(disposing); } @@ -49,7 +45,7 @@ private void InitializeComponent() this._linkSILWebsite = new System.Windows.Forms.LinkLabel(); this._labelVersionInfo = new System.Windows.Forms.Label(); this._labelSubTitle = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._linkSayMoreWebsite = new System.Windows.Forms.LinkLabel(); this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); this.pnlOptions.SuspendLayout(); diff --git a/src/SayMore/UI/ProjectChoosingAndCreating/WelcomeDialog.cs b/src/SayMore/UI/ProjectChoosingAndCreating/WelcomeDialog.cs index b47b27ee..1e79ace6 100644 --- a/src/SayMore/UI/ProjectChoosingAndCreating/WelcomeDialog.cs +++ b/src/SayMore/UI/ProjectChoosingAndCreating/WelcomeDialog.cs @@ -4,8 +4,6 @@ using System.IO; using System.Windows.Forms; using L10NSharp; -using L10NSharp.XLiffUtils; -using L10NSharp.UI; using SIL.Reporting; using SIL.Windows.Forms.PortableSettingsProvider; using SayMore.Model; @@ -17,8 +15,8 @@ namespace SayMore.UI.ProjectChoosingAndCreating { /// ---------------------------------------------------------------------------------------- /// - /// Incapsulates the welcome dialog box, in which users may create new projects, or open - /// existing projects via browsing the file systsem or by choosing a recently used project. + /// Encapsulates the welcome dialog box, in which users may create new projects, or open + /// existing projects via browsing the file system or by choosing a recently used project. /// /// ---------------------------------------------------------------------------------------- public sealed partial class WelcomeDialog : Form @@ -49,8 +47,7 @@ public WelcomeDialog(WelcomeDialogViewModel viewModel) LoadMRUButtons(); - LocalizeItemDlg.StringsLocalized += LocalizationInitiated; - LocalizationInitiated(null); + LocalizationInitiated(); } /// ------------------------------------------------------------------------------------ @@ -91,14 +88,11 @@ private void LoadMRUButtons() /// ------------------------------------------------------------------------------------ /// /// Sets up the link label with proper localizations. This method gets called from the - /// constructor and after strings are localized in the string localizing dialog box. + /// constructor and whenever the UI locale changes. /// /// ------------------------------------------------------------------------------------ - private void LocalizationInitiated(ILocalizationManager lm) + private void LocalizationInitiated() { - if (lm != null && lm.Id != ApplicationContainer.kSayMoreLocalizationId) - return; - _labelVersionInfo.Text = ApplicationContainer.GetVersionInfo(_labelVersionInfo.Text, BuildType.Current); _linkSILWebsite.Text = String.Format(_linkSILWebsite.Text, Application.CompanyName); @@ -107,7 +101,7 @@ private void LocalizationInitiated(ILocalizationManager lm) _linkSILWebsite.Links.Clear(); _linkSayMoreWebsite.Links.Clear(); - // Add the underline and link for SIL's website. + // Add the underline and link for the SIL Global website. int i = _linkSILWebsite.Text.IndexOf(Application.CompanyName, StringComparison.Ordinal); if (i >= 0) _linkSILWebsite.Links.Add(i, Application.CompanyName.Length, Settings.Default.SilWebSite); @@ -156,7 +150,7 @@ private void HandleBrowseForExistingProjectClick(object sender, EventArgs e) // context stuff well enough. // JH says: The di approach is to inject, not reach out. - // I.e., it should be a parameter to the contructor of this class. + // I.e., it should be a parameter to the constructor of this class. var projPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "SayMore"); @@ -179,22 +173,19 @@ private void HandleCreateProjectClick(object sender, EventArgs e) { var viewModel = new NewProjectDlgViewModel(); - using (var dlg = new NewProjectDlg(viewModel)) + using var dlg = new NewProjectDlg(viewModel); + if (dlg.ShowDialog() == DialogResult.OK) { - if (dlg.ShowDialog() == DialogResult.OK) - { - Model.SetRequestedPath(NewProjectDlgViewModel.ParentFolderPathForNewProject, viewModel.NewProjectName); - DialogResult = DialogResult.OK; - Close(); - } + Model.SetRequestedPath(NewProjectDlgViewModel.ParentFolderPathForNewProject, viewModel.NewProjectName); + DialogResult = DialogResult.OK; + Close(); } } /// ------------------------------------------------------------------------------------ private void HandleMruClick(object sender, EventArgs e) { - var tsb = sender as ToolStripButton; - if (tsb != null) + if (sender is ToolStripButton tsb) { Model.ProjectSettingsFilePath = tsb.Name; DialogResult = DialogResult.OK; diff --git a/src/SayMore/UI/ProjectWindow/ProjectWindow.Designer.cs b/src/SayMore/UI/ProjectWindow/ProjectWindow.Designer.cs index 9457de81..3b2d8b3d 100644 --- a/src/SayMore/UI/ProjectWindow/ProjectWindow.Designer.cs +++ b/src/SayMore/UI/ProjectWindow/ProjectWindow.Designer.cs @@ -1,4 +1,5 @@ -using L10NSharp.UI; +using L10NSharp.Windows.Forms; +using L10NSharp.Windows.Forms.UIComponents; namespace SayMore.UI.ProjectWindow { @@ -19,7 +20,7 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProjectWindow)); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._mainMenuStrip = new System.Windows.Forms.MenuStrip(); this._menuProject = new System.Windows.Forms.ToolStripMenuItem(); this._menuOpenProject = new System.Windows.Forms.ToolStripMenuItem(); @@ -38,6 +39,7 @@ private void InitializeComponent() this._menuReleaseNotes = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); this._menuHelp = new System.Windows.Forms.ToolStripMenuItem(); + this._menuPrivacy = new System.Windows.Forms.ToolStripMenuItem(); this._menuAbout = new System.Windows.Forms.ToolStripMenuItem(); this._viewTabGroup = new SayMore.UI.ProjectWindow.ViewTabGroup(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); @@ -203,6 +205,7 @@ private void InitializeComponent() this._menuReleaseNotes, this.toolStripSeparator1, this._menuHelp, + this._menuPrivacy, this._menuAbout}); this.locExtender.SetLocalizableToolTip(this._mainMenuHelp, null); this.locExtender.SetLocalizationComment(this._mainMenuHelp, null); @@ -236,9 +239,19 @@ private void InitializeComponent() this._menuHelp.Size = new System.Drawing.Size(156, 22); this._menuHelp.Text = "&Help..."; this._menuHelp.Click += new System.EventHandler(this.HandleHelpClick); - // + // + // _menuPrivacy + // + this.locExtender.SetLocalizableToolTip(this._menuPrivacy, null); + this.locExtender.SetLocalizationComment(this._menuPrivacy, null); + this.locExtender.SetLocalizingId(this._menuPrivacy, "MainWindow._menuPrivacy"); + this._menuPrivacy.Name = "_menuPrivacy"; + this._menuPrivacy.Size = new System.Drawing.Size(156, 22); + this._menuPrivacy.Text = "&Privacy Settings..."; + this._menuPrivacy.Click += new System.EventHandler(this.HandlePrivacyMenuClick); + // // _menuAbout - // + // this.locExtender.SetLocalizableToolTip(this._menuAbout, null); this.locExtender.SetLocalizationComment(this._menuAbout, null); this.locExtender.SetLocalizingId(this._menuAbout, "MainWindow._menuAbout"); @@ -298,6 +311,7 @@ private void InitializeComponent() private SayMore.UI.ProjectWindow.ViewTabGroup _viewTabGroup; private System.Windows.Forms.ToolStripMenuItem _mainMenuHelp; private System.Windows.Forms.ToolStripMenuItem _menuAbout; + private System.Windows.Forms.ToolStripMenuItem _menuPrivacy; private System.Windows.Forms.ToolStripMenuItem _menuReleaseNotes; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; private System.Windows.Forms.ToolStripMenuItem _menuHelp; diff --git a/src/SayMore/UI/ProjectWindow/ProjectWindow.cs b/src/SayMore/UI/ProjectWindow/ProjectWindow.cs index cc050716..ef6aea12 100644 --- a/src/SayMore/UI/ProjectWindow/ProjectWindow.cs +++ b/src/SayMore/UI/ProjectWindow/ProjectWindow.cs @@ -1,7 +1,7 @@ // -------------------------------------------------------------------------------------------- -#region // Copyright (c) 2025, SIL Global. All Rights Reserved. -// -// Copyright (c) 2025, SIL Global. All Rights Reserved. +#region // Copyright (c) 2026, SIL Global. All Rights Reserved. +// +// Copyright (c) 2026, SIL Global. All Rights Reserved. // // Distributable under the terms of the MIT License (https://sil.mit-license.org/) // @@ -18,8 +18,6 @@ using System.Windows.Forms; using DesktopAnalytics; using L10NSharp; -using L10NSharp.XLiffUtils; -using L10NSharp.UI; using NetSparkle; using SIL.IO; using SIL.Reporting; @@ -31,6 +29,7 @@ using SayMore.Utilities; using SIL.Windows.Forms.Extensions; using SIL.Windows.Forms.Miscellaneous; +using SIL.Windows.Forms.Privacy; using static System.String; using static SayMore.Utilities.FileSystemUtils; @@ -50,6 +49,7 @@ public partial class ProjectWindow : Form private readonly string _projectPath; private readonly IEnumerable _commands; private readonly UILanguageDlg.Factory _uiLanguageDialogFactory; + private readonly ILocalizationManager _localizationManager; private MPlayerDebuggingOutputWindow _outputDebuggingWindow; private string _titleFmt; @@ -125,7 +125,8 @@ protected override bool ProcessDialogKey(Keys keyData) /// ------------------------------------------------------------------------------------ public ProjectWindow(string projectPath, IEnumerable views, - IEnumerable commands, UILanguageDlg.Factory uiLanguageDialogFactory) : this() + IEnumerable commands, UILanguageDlg.Factory uiLanguageDialogFactory, + ILocalizationManager localizationManager) : this() { if (Settings.Default.ProjectWindow == null) { @@ -136,6 +137,7 @@ public ProjectWindow(string projectPath, IEnumerable views, _projectPath = projectPath; _commands = commands; _uiLanguageDialogFactory = uiLanguageDialogFactory; + _localizationManager = localizationManager; _viewTabGroup.Visible = false; @@ -157,8 +159,8 @@ public ProjectWindow(string projectPath, IEnumerable views, ((UserControl)vw).Enabled = false; } - SetWindowText(); - LocalizeItemDlg.StringsLocalized += SetWindowText; + SetWindowText(null, EventArgs.Empty); + localizationManager.UiLanguageChanged += SetWindowText; foreach (var tab in _viewTabGroup.Tabs.Where(tab => tab.View is ProjectScreen)) _viewTabGroup.SetActiveView(tab); @@ -182,7 +184,7 @@ protected override void Dispose(bool disposing) { FailedToGetShortName -= HandleFailureToGetShortName; - LocalizeItemDlg.StringsLocalized -= SetWindowText; + _localizationManager.UiLanguageChanged -= SetWindowText; ExceptionHandler.RemoveDelegate(AudioUtils.HandleGlobalNAudioException); @@ -199,8 +201,9 @@ protected override void Dispose(bool disposing) /// Sets the localized window title texts. /// /// ------------------------------------------------------------------------------------ - private void SetWindowText(ILocalizationManager lm = null) + private void SetWindowText(object sender, EventArgs e) { + var lm = (ILocalizationManager)sender; if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) { var ver = Assembly.GetExecutingAssembly().GetName().Version; @@ -297,12 +300,10 @@ private void HandleExitClick(object sender, EventArgs e) /// ------------------------------------------------------------------------------------ private void HandleHelpAboutClick(object sender, EventArgs e) { - using (var dlg = new SILAboutBox(FileLocationUtilities.GetFileDistributedWithApplication("aboutbox.htm"))) - { - dlg.Text += "\u2122"; - dlg.CheckForUpdatesClicked += HandleAboutDialogCheckForUpdatesClick; - dlg.ShowDialog(this); - } + using var dlg = new SILAboutBox(FileLocationUtilities.GetFileDistributedWithApplication("aboutbox.htm")); + dlg.Text += "\u2122"; + dlg.CheckForUpdatesClicked += HandleAboutDialogCheckForUpdatesClick; + dlg.ShowDialog(this); } private static void HandleAboutDialogCheckForUpdatesClick(object sender, EventArgs e) @@ -330,6 +331,15 @@ private void HandleHelpClick(object sender, EventArgs e) Analytics.Track("Show Help from main menu"); } + /// ------------------------------------------------------------------------------------ + private void HandlePrivacyMenuClick(object sender, EventArgs e) + { + using var dlg = new PrivacyDlg(Program.AnalyticsImpl); + dlg.RestartLabelColor = Color.Orange; + dlg.ShowDialog(this); + + } + /// ------------------------------------------------------------------------------------ private void HandleCommandMenuItemClick(object sender, EventArgs e) { @@ -357,21 +367,19 @@ private void ReportAnyFileLoadErrors() var loadErrors = Program.FileLoadErrors; if (loadErrors.Any()) { - using (var dlg = new FileLoadErrorsReportDlg(loadErrors)) - dlg.ShowDialog(this); + using var dlg = new FileLoadErrorsReportDlg(loadErrors); + dlg.ShowDialog(this); } } /// ------------------------------------------------------------------------------------ private void HandleChangeUILanguageMenuClick(object sender, EventArgs e) { - using (var dlg = _uiLanguageDialogFactory()) - { - if (dlg.ShowDialog(this) != DialogResult.OK) - return; + using var dlg = _uiLanguageDialogFactory(); + if (dlg.ShowDialog(this) != DialogResult.OK) + return; - Program.UpdateUiLanguageForUser(dlg.UILanguage); - } + Program.UpdateUiLanguageForUser(dlg.UILanguage); } /// ------------------------------------------------------------------------------------ @@ -416,11 +424,9 @@ private void HandleShowMPlayerDebugWindowMenuClick(object sender, EventArgs e) private void HandleMainMenuPaint(object sender, PaintEventArgs e) { var clr = Color.FromArgb(30, Color.Black); - using (var pen = new Pen(clr)) - { - var rc = _mainMenuStrip.ClientRectangle; - e.Graphics.DrawLine(pen, 0, rc.Bottom - 1, rc.Right, rc.Bottom - 1); - } + using var pen = new Pen(clr); + var rc = _mainMenuStrip.ClientRectangle; + e.Graphics.DrawLine(pen, 0, rc.Bottom - 1, rc.Right, rc.Bottom - 1); } /// ------------------------------------------------------------------------------------ diff --git a/src/SayMore/UI/ProjectWindow/UILanguageDlg.Designer.cs b/src/SayMore/UI/ProjectWindow/UILanguageDlg.Designer.cs index a12d6bdd..522106d2 100644 --- a/src/SayMore/UI/ProjectWindow/UILanguageDlg.Designer.cs +++ b/src/SayMore/UI/ProjectWindow/UILanguageDlg.Designer.cs @@ -30,11 +30,11 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this._tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); - this._comboUILanguage = new L10NSharp.UI.UILanguageComboBox(); + this._comboUILanguage = new L10NSharp.Windows.Forms.UIComponents.UILanguageComboBox(); this._labelLanguage = new System.Windows.Forms.Label(); this._buttonCancel = new System.Windows.Forms.Button(); this._buttonOK = new System.Windows.Forms.Button(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._linkIWantToLocalize = new System.Windows.Forms.LinkLabel(); this._linkHelpOnLocalizing = new System.Windows.Forms.LinkLabel(); this._tableLayoutPanel.SuspendLayout(); @@ -200,11 +200,11 @@ private void InitializeComponent() #endregion private System.Windows.Forms.TableLayoutPanel _tableLayoutPanel; - private L10NSharp.UI.UILanguageComboBox _comboUILanguage; + private L10NSharp.Windows.Forms.UIComponents.UILanguageComboBox _comboUILanguage; private System.Windows.Forms.Label _labelLanguage; private System.Windows.Forms.Button _buttonCancel; private System.Windows.Forms.Button _buttonOK; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.LinkLabel _linkIWantToLocalize; private System.Windows.Forms.LinkLabel _linkHelpOnLocalizing; } diff --git a/src/SayMore/UI/SessionRecording/SessionRecorderDlg.cs b/src/SayMore/UI/SessionRecording/SessionRecorderDlg.cs index a3a77c6a..f752253d 100644 --- a/src/SayMore/UI/SessionRecording/SessionRecorderDlg.cs +++ b/src/SayMore/UI/SessionRecording/SessionRecorderDlg.cs @@ -6,8 +6,6 @@ using System.Windows.Forms; using DesktopAnalytics; using L10NSharp; -using L10NSharp.XLiffUtils; -using L10NSharp.UI; using SIL.Media.Naudio.UI; using SIL.Reporting; using SIL.Windows.Forms.PortableSettingsProvider; @@ -15,6 +13,7 @@ using SayMore.Properties; using SayMore.Media.MPlayer; using SIL.Media; +using SIL.Windows.Forms; namespace SayMore.UI.SessionRecording { @@ -90,14 +89,6 @@ public SessionRecorderDlg(SessionRecorderDlgViewModel viewModel) : this() _peakMeter = AudioUtils.CreatePeakMeterControl(_panelPeakMeter); SetupRecordingDeviceButton(); - LocalizeItemDlg.StringsLocalized += HandleStringsLocalized; - } - - /// ------------------------------------------------------------------------------------ - private void HandleStringsLocalized(ILocalizationManager lm) - { - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - _recordedLengthLabelFormat = _labelRecLength.Text; } /// ------------------------------------------------------------------------------------ diff --git a/src/SayMore/UI/SessionRecording/SessionRecorderDlg.designer.cs b/src/SayMore/UI/SessionRecording/SessionRecorderDlg.designer.cs index b0a4e21d..2e64ffe5 100644 --- a/src/SayMore/UI/SessionRecording/SessionRecorderDlg.designer.cs +++ b/src/SayMore/UI/SessionRecording/SessionRecorderDlg.designer.cs @@ -1,6 +1,6 @@ using L10NSharp.XLiffUtils; -using L10NSharp.UI; +using L10NSharp.Windows.Forms.UIComponents; namespace SayMore.UI.SessionRecording { @@ -18,12 +18,7 @@ partial class SessionRecorderDlg protected override void Dispose(bool disposing) { if (disposing) - { - if (components != null) - components.Dispose(); - - LocalizeItemDlg.StringsLocalized -= HandleStringsLocalized; - } + components?.Dispose(); base.Dispose(disposing); } @@ -46,7 +41,7 @@ private void InitializeComponent() this._buttonPlayback = new System.Windows.Forms.ToolStripButton(); this._buttonStop = new System.Windows.Forms.ToolStripButton(); this._labelRecLength = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this.tableLayoutPanel1.SuspendLayout(); this.toolStrip1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); @@ -275,7 +270,7 @@ private void InitializeComponent() private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; private System.Windows.Forms.Label _labelRecordingFormat; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.ToolStrip toolStrip1; private System.Windows.Forms.ToolStripButton _buttonRecord; private System.Windows.Forms.ToolStripButton _buttonPlayback; diff --git a/src/SayMore/UI/ShortFileNameWarningDlg.Designer.cs b/src/SayMore/UI/ShortFileNameWarningDlg.Designer.cs index e774a5a5..08a58fde 100644 --- a/src/SayMore/UI/ShortFileNameWarningDlg.Designer.cs +++ b/src/SayMore/UI/ShortFileNameWarningDlg.Designer.cs @@ -47,7 +47,7 @@ private void InitializeComponent() this._flowLayoutFailedActions = new System.Windows.Forms.FlowLayoutPanel(); this._checkDone = new System.Windows.Forms.CheckBox(); this._btnClose = new System.Windows.Forms.Button(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this.dataGridViewTextBoxColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.dataGridViewTextBoxColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this._tableLayoutPanelMain.SuspendLayout(); @@ -295,7 +295,7 @@ private void InitializeComponent() private System.Windows.Forms.TableLayoutPanel _tableLayoutPanelMain; private System.Windows.Forms.Button _btnClose; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.LinkLabel _linkLabelFsUtilMsg; private System.Windows.Forms.Label _lblFailedActions; private System.Windows.Forms.Label _lblDoNotReportForVolumes; diff --git a/src/SayMore/UI/ShortFileNameWarningDlg.cs b/src/SayMore/UI/ShortFileNameWarningDlg.cs index 085c4f7e..d51d9841 100644 --- a/src/SayMore/UI/ShortFileNameWarningDlg.cs +++ b/src/SayMore/UI/ShortFileNameWarningDlg.cs @@ -7,10 +7,7 @@ using System.Windows.Forms; using DesktopAnalytics; using L10NSharp; -using L10NSharp.UI; -using L10NSharp.XLiffUtils; using SayMore.Utilities; -using SIL.Windows.Forms.Extensions; using SIL.Windows.Forms.PortableSettingsProvider; using static System.String; using Process = SIL.Program.Process; @@ -241,8 +238,6 @@ private ShortFileNameWarningDlg() StartPosition = FormStartPosition.CenterParent; Settings.Default.ShortFileNameWarningDlg = FormSettings.Create(this); } - - LocalizeItemDlg.StringsLocalized += HandleStringsLocalized; } /// ------------------------------------------------------------------------------------ @@ -274,7 +269,7 @@ private void InitializeVolumesChecklist() private void InitializeFilenamesChecklist() { var filenameWarningsToSuppress = Settings.Default.ShortFilenameWarningsToSuppress - .Split(new [] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries); + .Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); PopulateChecklist(_checkedListBoxFiles, filenameWarningsToSuppress); _checkedListBoxFiles.Tag = new Action(() => @@ -295,33 +290,29 @@ private static void PopulateChecklist(CheckedListBox listbox, } /// ------------------------------------------------------------------------------------ - protected void HandleStringsLocalized(ILocalizationManager lm = null) + protected void HandleStringsLocalized() { - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - const string fsUtil8dot3 = "fsutil 8dot3name"; - - _linkLabelFsUtilMsg.Text = Format(_linkLabelFsUtilMsg.Text, fsUtil8dot3); + const string fsUtil8dot3 = "fsutil 8dot3name"; + _linkLabelFsUtilMsg.Text = Format(_linkLabelFsUtilMsg.Text, fsUtil8dot3); - _linkLabelFsUtilMsg.LinkArea = new LinkArea( - _linkLabelFsUtilMsg.Text.IndexOf(fsUtil8dot3, StringComparison.Ordinal), - fsUtil8dot3.Length); - - if (_flowLayoutFailedActions.Controls.Count == 0) - { - _failedActionsLabelOrigText = _lblFailedActions.Text; - _lblFailedActions.Text = Format(LocalizationManager.GetString( - "ShortFileNameWarningDlg.lblFailedActionsNoCurrentFailures", - "This will help to avoid problems with certain utilities that {0} uses.", - "Param is \"SayMore\" (program name)"), - Program.ProductName); - } + _linkLabelFsUtilMsg.LinkArea = new LinkArea( + _linkLabelFsUtilMsg.Text.IndexOf(fsUtil8dot3, StringComparison.Ordinal), + fsUtil8dot3.Length); - _chkDoNotReportAnymoreThisSession.Text = - Format(_chkDoNotReportAnymoreThisSession.Text, Program.ProductName); + if (_flowLayoutFailedActions.Controls.Count == 0) + { + _failedActionsLabelOrigText = _lblFailedActions.Text; + _lblFailedActions.Text = Format(LocalizationManager.GetString( + "ShortFileNameWarningDlg.lblFailedActionsNoCurrentFailures", + "This will help to avoid problems with certain utilities that {0} uses.", + "Param is \"SayMore\" (program name)"), + Program.ProductName); } + + _chkDoNotReportAnymoreThisSession.Text = + Format(_chkDoNotReportAnymoreThisSession.Text, Program.ProductName); } - + /// ------------------------------------------------------------------------------------ private void _linkLabelFsUtilMsg_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { diff --git a/src/SayMore/UI/SplashScreenForm.Designer.cs b/src/SayMore/UI/SplashScreenForm.Designer.cs index d7c0771f..85f20d94 100644 --- a/src/SayMore/UI/SplashScreenForm.Designer.cs +++ b/src/SayMore/UI/SplashScreenForm.Designer.cs @@ -25,7 +25,7 @@ private void InitializeComponent() this.lblProductName = new System.Windows.Forms.Label(); this._labelLoading = new System.Windows.Forms.Label(); this._labelVersionInfo = new System.Windows.Forms.Label(); - this.locExtender = new L10NSharp.UI.L10NSharpExtender(this.components); + this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this.pictureBox2 = new System.Windows.Forms.PictureBox(); this.label1 = new System.Windows.Forms.Label(); this.m_panel.SuspendLayout(); @@ -231,7 +231,7 @@ private void InitializeComponent() private System.Windows.Forms.Label _labelLoading; private System.Windows.Forms.Label _labelVersionInfo; - private L10NSharp.UI.L10NSharpExtender locExtender; + private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.PictureBox pictureBox2; private System.Windows.Forms.Label label1; diff --git a/src/SayMoreTests/SayMoreTests.csproj b/src/SayMoreTests/SayMoreTests.csproj index b2b02d7b..1f7c0a6b 100644 --- a/src/SayMoreTests/SayMoreTests.csproj +++ b/src/SayMoreTests/SayMoreTests.csproj @@ -59,7 +59,7 @@ - + @@ -68,13 +68,13 @@ - - - - - - - + + + + + + + From 58a232f8fe43433b1791e9dc8450cfc0390c7550 Mon Sep 17 00:00:00 2001 From: tombogle Date: Fri, 5 Jun 2026 11:09:28 -0400 Subject: [PATCH 12/29] Add ApplicationContainer.SayMoreLocalizationManager static property Exposes the SayMore-specific ILocalizationManager as a static so EditorBase and other classes can subscribe to UiLanguageChanged without needing constructor injection. Co-Authored-By: Claude Sonnet 4.6 --- src/SayMore/ApplicationContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/SayMore/ApplicationContainer.cs b/src/SayMore/ApplicationContainer.cs index 9894016e..92d62289 100644 --- a/src/SayMore/ApplicationContainer.cs +++ b/src/SayMore/ApplicationContainer.cs @@ -35,6 +35,7 @@ public class ApplicationContainer : IDisposable private ISplashScreen _splashScreen; public const string kSayMoreLocalizationId = "SayMore"; private const string kPalasoLocalizationId = "Palaso"; + public static ILocalizationManager SayMoreLocalizationManager { get; private set; } /// ------------------------------------------------------------------------------------ public ApplicationContainer() : this(false) @@ -247,6 +248,8 @@ public ILocalizationManager CreateLocalizationManager() relativePathForWritingL10nFiles, Resources.SayMore, ["SayMore"]); + SayMoreLocalizationManager = localizationManager; + LocalizationManagerWinforms.Create(currentUiLanguage, kPalasoLocalizationId, kPalasoLocalizationId, ProductVersion, installedStringFileFolder, relativePathForWritingL10nFiles, Resources.SayMore, From 04fc998439fc68e06683145de0158124929577ec Mon Sep 17 00:00:00 2001 From: tombogle Date: Fri, 5 Jun 2026 11:22:28 -0400 Subject: [PATCH 13/29] Replace lm-parameter EditorBase constructors with static-based no-arg constructors - Replace `EditorBase(ILocalizationManager)` with `protected EditorBase()` that reads from `ApplicationContainer.SayMoreLocalizationManager` directly - Replace 4-arg `EditorBase(ComponentFile, string, string, ILocalizationManager)` with 3-arg version delegating to the no-arg constructor - Use null-guard `if (_localizationManager != null)` for event subscription/ unsubscription to support unit tests where ApplicationContainer is not initialized - Fixes "does not contain a constructor that takes 0 arguments" errors in MediaComponentEditor, DiagnosticsFileInfoControl, and related subclasses Co-Authored-By: Claude Sonnet 4.6 --- src/SayMore/UI/ComponentEditors/EditorBase.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/SayMore/UI/ComponentEditors/EditorBase.cs b/src/SayMore/UI/ComponentEditors/EditorBase.cs index aaafd979..6e876938 100644 --- a/src/SayMore/UI/ComponentEditors/EditorBase.cs +++ b/src/SayMore/UI/ComponentEditors/EditorBase.cs @@ -47,9 +47,9 @@ public class EditorBase : UserControl, IEditorProvider public Action ComponentFileListRefreshAction { protected get; set; } /// ------------------------------------------------------------------------------------ - public EditorBase(ILocalizationManager localizationManager) + protected EditorBase() { - _localizationManager = localizationManager; + _localizationManager = ApplicationContainer.SayMoreLocalizationManager; DoubleBuffered = true; BackColor = AppColors.DataEntryPanelBegin; Padding = new Padding(7); @@ -60,13 +60,13 @@ public EditorBase(ILocalizationManager localizationManager) ControlRemoved += HandleControlRemoved; Layout += HandleLayout; - localizationManager.UiLanguageChanged += HandleStringsLocalized; + if (_localizationManager != null) + _localizationManager.UiLanguageChanged += HandleStringsLocalized; HandleStringsLocalized(null, EventArgs.Empty); } /// ------------------------------------------------------------------------------------ - public EditorBase(ComponentFile file, string tabText, string imageKey, - ILocalizationManager localizationManager) : this(localizationManager) + public EditorBase(ComponentFile file, string tabText, string imageKey) : this() { _file = file; Initialize(tabText, imageKey); @@ -75,7 +75,7 @@ public EditorBase(ComponentFile file, string tabText, string imageKey, /// ------------------------------------------------------------------------------------ protected override void Dispose(bool disposing) { - if (disposing) + if (disposing && _localizationManager != null) _localizationManager.UiLanguageChanged -= HandleStringsLocalized; try { From f105fc438a9cfe183722e5b4e6a5442044a0adf1 Mon Sep 17 00:00:00 2001 From: tombogle Date: Mon, 8 Jun 2026 08:55:54 -0400 Subject: [PATCH 14/29] Make ComponentFileGrid constructor no-arg, use SayMoreLocalizationManager static Co-Authored-By: Claude Sonnet 4.6 --- .../UI/ElementListScreen/ComponentFileGrid.Designer.cs | 3 ++- src/SayMore/UI/ElementListScreen/ComponentFileGrid.cs | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/SayMore/UI/ElementListScreen/ComponentFileGrid.Designer.cs b/src/SayMore/UI/ElementListScreen/ComponentFileGrid.Designer.cs index 13bec35b..651d10b4 100644 --- a/src/SayMore/UI/ElementListScreen/ComponentFileGrid.Designer.cs +++ b/src/SayMore/UI/ElementListScreen/ComponentFileGrid.Designer.cs @@ -20,7 +20,8 @@ protected override void Dispose(bool disposing) { components?.Dispose(); - _localizationManager.UiLanguageChanged -= HandleStringsLocalized; + if (_localizationManager != null) + _localizationManager.UiLanguageChanged -= HandleStringsLocalized; } base.Dispose(disposing); } diff --git a/src/SayMore/UI/ElementListScreen/ComponentFileGrid.cs b/src/SayMore/UI/ElementListScreen/ComponentFileGrid.cs index f0d47f67..6aa36b85 100644 --- a/src/SayMore/UI/ElementListScreen/ComponentFileGrid.cs +++ b/src/SayMore/UI/ElementListScreen/ComponentFileGrid.cs @@ -63,9 +63,9 @@ public partial class ComponentFileGrid : UserControl public bool ShowContextMenu { get; set; } /// ------------------------------------------------------------------------------------ - public ComponentFileGrid(ILocalizationManager localizationManager) + public ComponentFileGrid() { - _localizationManager = localizationManager; + _localizationManager = ApplicationContainer.SayMoreLocalizationManager; ShowContextMenu = true; Logger.WriteEvent("ComponentFileGrid constructor"); @@ -111,7 +111,8 @@ public ComponentFileGrid(ILocalizationManager localizationManager) _menuDeleteFile.Click += (s, e) => DeleteFile(); - localizationManager.UiLanguageChanged += HandleStringsLocalized; + if (_localizationManager != null) + _localizationManager.UiLanguageChanged += HandleStringsLocalized; } /// ------------------------------------------------------------------------------------ From 5cbfb0936b31c7380580bf18452d3e7330612be1 Mon Sep 17 00:00:00 2001 From: tombogle Date: Mon, 8 Jun 2026 09:02:50 -0400 Subject: [PATCH 15/29] StatisticsView/ProgressScreen: remove ILocalizationManager param, use static Co-Authored-By: Claude Sonnet 4.6 --- src/SayMore/UI/Overview/ProgressScreen.cs | 2 +- src/SayMore/UI/Overview/Statistics/StatisticsView.cs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/SayMore/UI/Overview/ProgressScreen.cs b/src/SayMore/UI/Overview/ProgressScreen.cs index 0eeb2a7a..a5d74075 100644 --- a/src/SayMore/UI/Overview/ProgressScreen.cs +++ b/src/SayMore/UI/Overview/ProgressScreen.cs @@ -19,7 +19,7 @@ public ProgressScreen(StatisticsViewModel statisticsModel) Logger.WriteEvent("ProgressScreen constructor"); InitializeComponent(); - _statsView = new StatisticsView(statisticsModel, TODO) {Dock = DockStyle.Fill}; + _statsView = new StatisticsView(statisticsModel) {Dock = DockStyle.Fill}; Controls.Add(_statsView); _mnuProgress = new ToolStripMenuItem diff --git a/src/SayMore/UI/Overview/Statistics/StatisticsView.cs b/src/SayMore/UI/Overview/Statistics/StatisticsView.cs index eccd4b7c..1ac26cbe 100644 --- a/src/SayMore/UI/Overview/Statistics/StatisticsView.cs +++ b/src/SayMore/UI/Overview/Statistics/StatisticsView.cs @@ -15,12 +15,12 @@ public partial class StatisticsView : UserControl private readonly ILocalizationManager _localizationManager; /// ------------------------------------------------------------------------------------ - public StatisticsView(StatisticsViewModel model, ILocalizationManager localizationManager) + public StatisticsView(StatisticsViewModel model) { Logger.WriteEvent("StatisticsView constructor"); _model = model; - _localizationManager = localizationManager; + _localizationManager = ApplicationContainer.SayMoreLocalizationManager; InitializeComponent(); _panelWorking.BorderStyle = BorderStyle.None; @@ -32,6 +32,7 @@ protected override void OnHandleDestroyed(EventArgs e) { base.OnHandleDestroyed(e); + if (_localizationManager != null) _localizationManager.UiLanguageChanged -= UpdateDisplay; _model.FinishedGatheringStatisticsForAllFiles -= HandleNewDataAvailable; _model.NewStatisticsAvailable -= HandleNewDataAvailable; @@ -49,6 +50,7 @@ public void InitializeView() UpdateDisplay(null, EventArgs.Empty); } + if (_localizationManager != null) _localizationManager.UiLanguageChanged += UpdateDisplay; } From 0df26ddfcedb26d7494c4ba86d16101dd0a8964c Mon Sep 17 00:00:00 2001 From: tombogle Date: Mon, 8 Jun 2026 09:18:52 -0400 Subject: [PATCH 16/29] Fix indentation on null-conditional UiLanguageChanged guards in StatisticsView --- src/SayMore/UI/Overview/Statistics/StatisticsView.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SayMore/UI/Overview/Statistics/StatisticsView.cs b/src/SayMore/UI/Overview/Statistics/StatisticsView.cs index 1ac26cbe..be46acc4 100644 --- a/src/SayMore/UI/Overview/Statistics/StatisticsView.cs +++ b/src/SayMore/UI/Overview/Statistics/StatisticsView.cs @@ -33,7 +33,7 @@ protected override void OnHandleDestroyed(EventArgs e) base.OnHandleDestroyed(e); if (_localizationManager != null) - _localizationManager.UiLanguageChanged -= UpdateDisplay; + _localizationManager.UiLanguageChanged -= UpdateDisplay; _model.FinishedGatheringStatisticsForAllFiles -= HandleNewDataAvailable; _model.NewStatisticsAvailable -= HandleNewDataAvailable; } @@ -51,7 +51,7 @@ public void InitializeView() } if (_localizationManager != null) - _localizationManager.UiLanguageChanged += UpdateDisplay; + _localizationManager.UiLanguageChanged += UpdateDisplay; } /// ------------------------------------------------------------------------------------ From 104088d80fe39fb515aa7b28d570316bcc0b6104 Mon Sep 17 00:00:00 2001 From: tombogle Date: Mon, 8 Jun 2026 11:53:28 -0400 Subject: [PATCH 17/29] Task 5: remove ILocalizationManager from FileType hierarchy Drop ILocalizationManager constructor params and field storage from FileType base, AnnotationFileWithMissingMediaFileType, AudioVideoFileTypeBase, AudioFileType, VideoFileType, OralAnnotationFileType, and ImageFileType. Co-Authored-By: Claude Sonnet 4.6 --- src/SayMore/Model/Files/FileType.cs | 41 +++++++++++------------------ 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/src/SayMore/Model/Files/FileType.cs b/src/SayMore/Model/Files/FileType.cs index 88b48af2..ecb2b0a0 100644 --- a/src/SayMore/Model/Files/FileType.cs +++ b/src/SayMore/Model/Files/FileType.cs @@ -34,7 +34,6 @@ public class FileType { protected Func _basicFieldGridEditorFactoryLazy; protected Func _isMatchPredicate; - protected readonly ILocalizationManager _localizationManager; protected readonly Dictionary> _editors = new Dictionary>(); @@ -605,13 +604,10 @@ public override string GetMetaFilePath(string pathToAnnotatedFile) /// ---------------------------------------------------------------------------------------- public class AnnotationFileWithMissingMediaFileType : FileType { - private readonly ILocalizationManager _localizationManager; - /// ------------------------------------------------------------------------------------ - public AnnotationFileWithMissingMediaFileType(ILocalizationManager localizationManager) + public AnnotationFileWithMissingMediaFileType() : base("AnnotationsWithMissingMedia", GetIsAnAnnotationFileWithMissingMedia) { - _localizationManager = localizationManager; } /// ------------------------------------------------------------------------------------ @@ -626,7 +622,7 @@ public static bool GetIsAnAnnotationFileWithMissingMedia(string path) /// ------------------------------------------------------------------------------------ protected override IEnumerable GetNewSetOfEditorProviders(ComponentFile file) { - yield return new MissingMediaFileEditor(file, "/Concepts/ELAN.htm", _localizationManager); + yield return new MissingMediaFileEditor(file, "/Concepts/ELAN.htm"); } /// ------------------------------------------------------------------------------------ @@ -646,9 +642,8 @@ public class OralAnnotationFileType : AudioFileType public OralAnnotationFileType( Func project, Lazy> audioComponentEditorFactoryLazy, - Lazy> contributorsEditorFactoryLazy, - ILocalizationManager localizationManager) : - base(project(), audioComponentEditorFactoryLazy, contributorsEditorFactoryLazy, localizationManager) + Lazy> contributorsEditorFactoryLazy) : + base(project(), audioComponentEditorFactoryLazy, contributorsEditorFactoryLazy) { Name = "OralAnnotations"; } @@ -662,7 +657,7 @@ public override bool IsMatch(string path) /// ------------------------------------------------------------------------------------ protected override IEnumerable GetNewSetOfEditorProviders(ComponentFile file) { - yield return new OralAnnotationEditor(file, _localizationManager); + yield return new OralAnnotationEditor(file); yield return AudioComponentEditorFactoryLazy.Value()(file, null); //yield return _contributorsEditorFactoryLazy()(file, null); //yield return new NotesEditor(file); @@ -683,23 +678,20 @@ protected override IEnumerable GetNewSetOfEditorProviders(Compo public abstract class AudioVideoFileTypeBase : FileTypeWithContributors { private readonly Project _project; - protected readonly ILocalizationManager _localizationManager; /// ------------------------------------------------------------------------------------ protected AudioVideoFileTypeBase(string name, Project project, Func isMatchPredicate, - Lazy> contributorsEditorFactoryLazy, - ILocalizationManager localizationManager) + Lazy> contributorsEditorFactoryLazy) : base(name, isMatchPredicate, contributorsEditorFactoryLazy) { _project = project; - _localizationManager = localizationManager; } /// ------------------------------------------------------------------------------------ protected override IEnumerable GetNewSetOfEditorProviders(ComponentFile file) { yield return new StartAnnotatingEditor(file, _project); - yield return new ConvertToStandardAudioEditor(file, _localizationManager); + yield return new ConvertToStandardAudioEditor(file); } /// ------------------------------------------------------------------------------------ @@ -937,11 +929,10 @@ public class AudioFileType : AudioVideoFileTypeBase /// ------------------------------------------------------------------------------------ public AudioFileType(Project project, Lazy> audioComponentEditorFactoryLazy, - Lazy> contributorsEditorFactoryLazy, - ILocalizationManager localizationManager) + Lazy> contributorsEditorFactoryLazy) : base("Audio", project, p => FileUtils.AudioFileExtensions.Cast().Any(ext => p.ToLower().EndsWith(ext.ToLower())), - contributorsEditorFactoryLazy, localizationManager) + contributorsEditorFactoryLazy) { AudioComponentEditorFactoryLazy = audioComponentEditorFactoryLazy; } @@ -979,7 +970,7 @@ public override bool GetShowInPresetOptions(string key) /// ------------------------------------------------------------------------------------ protected override IEnumerable GetNewSetOfEditorProviders(ComponentFile file) { - yield return new AudioVideoPlayer(file, "Audio", _localizationManager); + yield return new AudioVideoPlayer(file, "Audio"); yield return AudioComponentEditorFactoryLazy.Value()(file, null); yield return ContributorsEditorFactoryLazy.Value()(file, null); yield return new NotesEditor(file); @@ -1003,10 +994,9 @@ public class VideoFileType : AudioVideoFileTypeBase /// ------------------------------------------------------------------------------------ public VideoFileType(Project project, Func videoComponentEditorFactoryLazy, - Lazy> contributorsEditorFactoryLazy, - ILocalizationManager localizationManager) + Lazy> contributorsEditorFactoryLazy) : base("Video", project, p => FileUtils.VideoFileExtensions.Cast() - .Any(ext => p.ToLower().EndsWith(ext.ToLower())), contributorsEditorFactoryLazy, localizationManager) + .Any(ext => p.ToLower().EndsWith(ext.ToLower())), contributorsEditorFactoryLazy) { _videoComponentEditorFactoryLazy = videoComponentEditorFactoryLazy; } @@ -1045,7 +1035,7 @@ public override bool GetShowInPresetOptions(string key) /// ------------------------------------------------------------------------------------ protected override IEnumerable GetNewSetOfEditorProviders(ComponentFile file) { - yield return new AudioVideoPlayer(file, "Video", _localizationManager); + yield return new AudioVideoPlayer(file, "Video"); yield return _videoComponentEditorFactoryLazy()(file, null); yield return ContributorsEditorFactoryLazy.Value()(file, null); yield return new NotesEditor(file); @@ -1069,8 +1059,7 @@ public class ImageFileType : FileType /// ------------------------------------------------------------------------------------ public ImageFileType( Func basicFieldGridEditorFactoryLazy, - Func contributorsEditorFactoryLazy, - ILocalizationManager localizationManager) + Func contributorsEditorFactoryLazy) : base("Image", p => FileUtils.ImageFileExtensions.Cast().Any(ext => p.ToLower().EndsWith(ext.ToLower()))) { _basicFieldGridEditorFactoryLazy = basicFieldGridEditorFactoryLazy; @@ -1083,7 +1072,7 @@ public ImageFileType( /// ------------------------------------------------------------------------------------ protected override IEnumerable GetNewSetOfEditorProviders(ComponentFile file) { - yield return new ImageViewer(file, _localizationManager); + yield return new ImageViewer(file); yield return _basicFieldGridEditorFactoryLazy()(file, null); yield return _contributorsEditorFactoryLazy()(file, null); yield return new NotesEditor(file); From 05e6a4d9c2ad7e4814490ff360845e4e377eab1e Mon Sep 17 00:00:00 2001 From: tombogle Date: Mon, 8 Jun 2026 13:39:58 -0400 Subject: [PATCH 18/29] Task 6: remove lm guard from HandleStringsLocalized in 7 EditorBase subclasses Co-Authored-By: Claude Sonnet 4.6 --- .../ComponentEditors/StartAnnotatingEditor.cs | 19 +++++------- .../ComponentEditors/TextAnnotationEditor.cs | 7 ++--- .../UI/ComponentEditors/BrowserEditor.cs | 11 +++---- .../UI/ComponentEditors/NotesEditor.cs | 7 ++--- .../PersonContributionEditor.cs | 7 ++--- .../UI/ComponentEditors/SessionBasicEditor.cs | 29 +++++++++---------- .../ComponentEditors/StatusAndStagesEditor.cs | 21 ++++++-------- 7 files changed, 40 insertions(+), 61 deletions(-) diff --git a/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.cs b/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.cs index 8c08ac6b..627f8ccb 100644 --- a/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.cs +++ b/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.cs @@ -80,18 +80,15 @@ public override bool IsOKToShow /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) + TabText = CommonUIStrings.StartAnnotatingTabText; + + if (_cboAudacityLabelTier != null) { - TabText = CommonUIStrings.StartAnnotatingTabText; - - if (_cboAudacityLabelTier != null) - { - var selectedIndex = _cboAudacityLabelTier.SelectedIndex; - _cboAudacityLabelTier.Items.Clear(); - PopulateAudacityLabelTierItems(); - _cboAudacityLabelTier.SelectedIndex = selectedIndex >= 0 ? selectedIndex : 0; - } - } + var selectedIndex = _cboAudacityLabelTier.SelectedIndex; + _cboAudacityLabelTier.Items.Clear(); + PopulateAudacityLabelTierItems(); + _cboAudacityLabelTier.SelectedIndex = selectedIndex >= 0 ? selectedIndex : 0; + } base.HandleStringsLocalized(sender, e); } diff --git a/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.cs b/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.cs index bfb7fef3..db862d1f 100644 --- a/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.cs +++ b/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.cs @@ -457,11 +457,8 @@ private void HandleResegmentButtonClick(object sender, EventArgs e) /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - TabText = LocalizationManager.GetString( - "SessionsView.Transcription.TextAnnotationEditor.TabText", "Annotations"); - } + TabText = LocalizationManager.GetString( + "SessionsView.Transcription.TextAnnotationEditor.TabText", "Annotations"); base.HandleStringsLocalized(sender, e); } diff --git a/src/SayMore/UI/ComponentEditors/BrowserEditor.cs b/src/SayMore/UI/ComponentEditors/BrowserEditor.cs index 8b2a6091..c041582c 100644 --- a/src/SayMore/UI/ComponentEditors/BrowserEditor.cs +++ b/src/SayMore/UI/ComponentEditors/BrowserEditor.cs @@ -195,13 +195,10 @@ void HandleFileLinkClick(object sender, HtmlElementEventArgs e) /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - TabText = LocalizationManager.GetString( - "CommonToMultipleViews.GenericFileTypeViewer.TabText", "View"); - if (_browser?.Tag is string filePath) - DisplayFile(filePath); - } + TabText = LocalizationManager.GetString( + "CommonToMultipleViews.GenericFileTypeViewer.TabText", "View"); + if (_browser?.Tag is string filePath) + DisplayFile(filePath); base.HandleStringsLocalized(sender, e); } diff --git a/src/SayMore/UI/ComponentEditors/NotesEditor.cs b/src/SayMore/UI/ComponentEditors/NotesEditor.cs index 01ba7867..0ac6a029 100644 --- a/src/SayMore/UI/ComponentEditors/NotesEditor.cs +++ b/src/SayMore/UI/ComponentEditors/NotesEditor.cs @@ -69,11 +69,8 @@ private static void HandleNotesTextBoxKeyDown(object sender, KeyEventArgs e) /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - _origTabText = TabText = LocalizationManager.GetString( - "CommonToMultipleViews.NotesEditor.TabText", "Notes"); - } + _origTabText = TabText = LocalizationManager.GetString( + "CommonToMultipleViews.NotesEditor.TabText", "Notes"); base.HandleStringsLocalized(sender, e); } diff --git a/src/SayMore/UI/ComponentEditors/PersonContributionEditor.cs b/src/SayMore/UI/ComponentEditors/PersonContributionEditor.cs index 2395cfb4..95e89f5c 100644 --- a/src/SayMore/UI/ComponentEditors/PersonContributionEditor.cs +++ b/src/SayMore/UI/ComponentEditors/PersonContributionEditor.cs @@ -133,11 +133,8 @@ private object[] GetContribRowData(SessionContribution contrib) protected override void HandleStringsLocalized(object sender, EventArgs e) { - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - TabText = LocalizationManager.GetString( - "PeopleView.ContributionEditor.TabText", "Contributions"); - } + TabText = LocalizationManager.GetString( + "PeopleView.ContributionEditor.TabText", "Contributions"); base.HandleStringsLocalized(sender, e); } diff --git a/src/SayMore/UI/ComponentEditors/SessionBasicEditor.cs b/src/SayMore/UI/ComponentEditors/SessionBasicEditor.cs index 1005a402..086f006c 100644 --- a/src/SayMore/UI/ComponentEditors/SessionBasicEditor.cs +++ b/src/SayMore/UI/ComponentEditors/SessionBasicEditor.cs @@ -433,25 +433,22 @@ protected override void OnCurrentProjectSet() /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) + TabText = LocalizationManager.GetString("SessionsView.MetadataEditor.TabText", + "Session"); + if (_genre != null && !String.IsNullOrEmpty(_genre.Text)) { - TabText = LocalizationManager.GetString("SessionsView.MetadataEditor.TabText", - "Session"); - if (_genre != null && !String.IsNullOrEmpty(_genre.Text)) - { - var genreId = GenreDefinition.TranslateNameToId(_genre.Text); - if (genreId != _genre.Text) - _genre.Text = GenreDefinition.TranslateIdToName(genreId); - } + var genreId = GenreDefinition.TranslateNameToId(_genre.Text); + if (genreId != _genre.Text) + _genre.Text = GenreDefinition.TranslateIdToName(genreId); + } - if (_gridAdditionalFields != null) + if (_gridAdditionalFields != null) + { + for (int iRow = 0; iRow < _gridAdditionalFields.RowCount; iRow++) { - for (int iRow = 0; iRow < _gridAdditionalFields.RowCount; iRow++) - { - var comboBoxCell = _gridAdditionalFields[1, iRow] as DataGridViewComboBoxCell; - if (comboBoxCell?.DataSource is IMDIItemList list) - list.Localize(Localize); - } + var comboBoxCell = _gridAdditionalFields[1, iRow] as DataGridViewComboBoxCell; + if (comboBoxCell?.DataSource is IMDIItemList list) + list.Localize(Localize); } } diff --git a/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.cs b/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.cs index 819835f5..cd946e4c 100644 --- a/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.cs +++ b/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.cs @@ -333,20 +333,17 @@ private void HandleStagesColorBlockPaint(object sender, PaintEventArgs e) /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) + TabText = LocalizationManager.GetString( + "SessionsView.StatusAndStagesEditor.TabText", "Status && Stages"); + if (_statusRadioButtons != null) { - TabText = LocalizationManager.GetString( - "SessionsView.StatusAndStagesEditor.TabText", "Status && Stages"); - if (_statusRadioButtons != null) + foreach (var radioButton in _statusRadioButtons.Where(b => b.Tag is Session.Status)) { - foreach (var radioButton in _statusRadioButtons.Where(b => b.Tag is Session.Status)) - { - var status = (Session.Status)radioButton.Tag; - radioButton.Text = Session.GetLocalizedStatus(status.ToString()); - var toolTip = GetStatusToolTip(status); - if (toolTip != null) - _toolTip.SetToolTip(radioButton, toolTip); - } + var status = (Session.Status)radioButton.Tag; + radioButton.Text = Session.GetLocalizedStatus(status.ToString()); + var toolTip = GetStatusToolTip(status); + if (toolTip != null) + _toolTip.SetToolTip(radioButton, toolTip); } } From 870e9f721563935bbcdddb41ec3be33ebf5df6cc Mon Sep 17 00:00:00 2001 From: tombogle Date: Mon, 8 Jun 2026 13:49:20 -0400 Subject: [PATCH 19/29] =?UTF-8?q?Task=207:=20fix=20PersonBasicEditor=20?= =?UTF-8?q?=E2=80=94=20remove=20no-arg=20HandleStringsLocalized=20call=20a?= =?UTF-8?q?nd=20lm=20guard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../UI/ComponentEditors/PersonBasicEditor.cs | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs b/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs index fb4c3321..3b3eb3f9 100644 --- a/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs +++ b/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs @@ -86,7 +86,6 @@ public PersonBasicEditor(ComponentFile file, string imageKey, { _otherLanguage3, _otherLanguage3.ForeColor} }; - HandleStringsLocalized(); _binder.TranslateBoundValueBeingSaved += HandleBinderTranslateBoundValueBeingSaved; _binder.TranslateBoundValueBeingRetrieved += HandleBinderTranslateBoundValueBeingRetrieved; _binder.SetComponentFile(file); @@ -818,21 +817,18 @@ private string GetPictureFileFromDragData(IDataObject data) /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - TabText = LocalizationManager.GetString("PeopleView.MetadataEditor.TabText", - "Person"); + TabText = LocalizationManager.GetString("PeopleView.MetadataEditor.TabText", + "Person"); - if (_gender != null) - { - int i = _gender.SelectedIndex; - _gender.Items.Clear(); - _gender.Items.Add(LocalizationManager.GetString( - "PeopleView.MetadataEditor.GenderSelector.Male", "Male")); - _gender.Items.Add(LocalizationManager.GetString( - "PeopleView.MetadataEditor.GenderSelector.Female", "Female")); - _gender.SelectedIndex = i; - } + if (_gender != null) + { + int i = _gender.SelectedIndex; + _gender.Items.Clear(); + _gender.Items.Add(LocalizationManager.GetString( + "PeopleView.MetadataEditor.GenderSelector.Male", "Male")); + _gender.Items.Add(LocalizationManager.GetString( + "PeopleView.MetadataEditor.GenderSelector.Female", "Female")); + _gender.SelectedIndex = i; } base.HandleStringsLocalized(sender, e); From 72ff64469eed34d4356975210af0ab47f5d9f93c Mon Sep 17 00:00:00 2001 From: tombogle Date: Mon, 8 Jun 2026 14:02:40 -0400 Subject: [PATCH 20/29] Task 8: drop lm constructor param and clean up HandleStringsLocalized in 5 EditorBase subclasses Co-Authored-By: Claude Sonnet 4.6 --- .../ConvertToStandardAudioEditor.cs | 10 ++----- .../ComponentEditors/OralAnnotationEditor.cs | 14 ++++----- .../UI/ComponentEditors/AudioVideoPlayer.cs | 18 +++++------ .../UI/ComponentEditors/ImageViewer.cs | 12 +++----- .../MissingMediaFileEditor.cs | 30 ++++++++----------- 5 files changed, 32 insertions(+), 52 deletions(-) diff --git a/src/SayMore/Transcription/UI/ComponentEditors/ConvertToStandardAudioEditor.cs b/src/SayMore/Transcription/UI/ComponentEditors/ConvertToStandardAudioEditor.cs index ddf27a00..b70d0ee2 100644 --- a/src/SayMore/Transcription/UI/ComponentEditors/ConvertToStandardAudioEditor.cs +++ b/src/SayMore/Transcription/UI/ComponentEditors/ConvertToStandardAudioEditor.cs @@ -18,8 +18,8 @@ public partial class ConvertToStandardAudioEditor : EditorBase { private static Bitmap s_informationIconAsBitmap; /// ------------------------------------------------------------------------------------ - public ConvertToStandardAudioEditor(ComponentFile file, ILocalizationManager localizationManager) : - base(file, null, null, localizationManager) + public ConvertToStandardAudioEditor(ComponentFile file) : + base(file, null, null) { Logger.WriteEvent("ConvertToStandardAudioEditor constructor. file = {0}", file); InitializeComponent(); @@ -110,11 +110,7 @@ private string GetIntroMessage() /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - var lm = sender as ILocalizationManager; - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - TabText = CommonUIStrings.StartAnnotatingTabText; - } + TabText = CommonUIStrings.StartAnnotatingTabText; base.HandleStringsLocalized(sender, e); } diff --git a/src/SayMore/Transcription/UI/ComponentEditors/OralAnnotationEditor.cs b/src/SayMore/Transcription/UI/ComponentEditors/OralAnnotationEditor.cs index 13282cd2..30e40e91 100644 --- a/src/SayMore/Transcription/UI/ComponentEditors/OralAnnotationEditor.cs +++ b/src/SayMore/Transcription/UI/ComponentEditors/OralAnnotationEditor.cs @@ -20,8 +20,8 @@ public partial class OralAnnotationEditor : EditorBase private string _fileTooLongMsgDisplayedForFile; /// ------------------------------------------------------------------------------------ - public OralAnnotationEditor(ComponentFile file, ILocalizationManager localizationManager) : - base(file, null, "Audio", localizationManager) + public OralAnnotationEditor(ComponentFile file) : + base(file, null, "Audio") { Logger.WriteEvent("OralAnnotationEditor constructor. file = {0}", file); InitializeComponent(); @@ -271,13 +271,9 @@ private void HandleRegenerateFileButtonClick(object sender, EventArgs e) /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - var lm = (ILocalizationManager)sender; - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - TabText = LocalizationManager.GetString( - "SessionsView.Transcription.GeneratedOralAnnotationView.TabText", - "Generated Audio"); - } + TabText = LocalizationManager.GetString( + "SessionsView.Transcription.GeneratedOralAnnotationView.TabText", + "Generated Audio"); base.HandleStringsLocalized(sender, e); } diff --git a/src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs b/src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs index ebc7a4e5..be7ddb80 100644 --- a/src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs +++ b/src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs @@ -18,8 +18,8 @@ public partial class AudioVideoPlayer : EditorBase private readonly MediaPlayer _mediaPlayer; /// ------------------------------------------------------------------------------------ - public AudioVideoPlayer(ComponentFile file, string imageKey, ILocalizationManager localizationManager) : - base(file, null, imageKey, localizationManager) + public AudioVideoPlayer(ComponentFile file, string imageKey) : + base(file, null, imageKey) { Logger.WriteEvent("AudioVideoPlayer constructor. file = {0}; imageKey = {1}", file, imageKey); InitializeComponent(); @@ -71,15 +71,11 @@ protected override void HandleStringsLocalized(object sender, EventArgs e) if (_file == null) return; - var lm = (ILocalizationManager)sender; - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - TabText = _file.FileType.IsVideo ? - LocalizationManager.GetString( - "CommonToMultipleViews.MediaPlayer.TabText-Video", "Video") : - LocalizationManager.GetString( - "CommonToMultipleViews.MediaPlayer.TabText-Audio", "Audio"); - } + TabText = _file.FileType.IsVideo ? + LocalizationManager.GetString( + "CommonToMultipleViews.MediaPlayer.TabText-Video", "Video") : + LocalizationManager.GetString( + "CommonToMultipleViews.MediaPlayer.TabText-Audio", "Audio"); base.HandleStringsLocalized(sender, e); } diff --git a/src/SayMore/UI/ComponentEditors/ImageViewer.cs b/src/SayMore/UI/ComponentEditors/ImageViewer.cs index 4cf8861a..691dac05 100644 --- a/src/SayMore/UI/ComponentEditors/ImageViewer.cs +++ b/src/SayMore/UI/ComponentEditors/ImageViewer.cs @@ -17,8 +17,8 @@ public partial class ImageViewer : EditorBase private ImageViewerViewModel _model; /// ------------------------------------------------------------------------------------ - public ImageViewer(ComponentFile file, ILocalizationManager localizationManager) : - base(file, null, "Image", localizationManager) + public ImageViewer(ComponentFile file) : + base(file, null, "Image") { Logger.WriteEvent("ImageViewer constructor. file = {0}", file); InitializeComponent(); @@ -143,12 +143,8 @@ private void HandleZoomTrackBarValueChanged(object sender, EventArgs e) /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - var lm = (ILocalizationManager)sender; - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - TabText = LocalizationManager.GetString( - "CommonToMultipleViews.ImageViewer.TabText", "Image"); - } + TabText = LocalizationManager.GetString( + "CommonToMultipleViews.ImageViewer.TabText", "Image"); base.HandleStringsLocalized(sender, e); } diff --git a/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.cs b/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.cs index 3a873f4d..d5e512ba 100644 --- a/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.cs +++ b/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.cs @@ -11,8 +11,8 @@ namespace SayMore.UI.ComponentEditors public partial class MissingMediaFileEditor : EditorBase { /// ------------------------------------------------------------------------------------ - public MissingMediaFileEditor(ComponentFile file, string imageKey, ILocalizationManager localizationManager) - : base(file, null, imageKey, localizationManager) + public MissingMediaFileEditor(ComponentFile file, string imageKey) + : base(file, null, imageKey) { Logger.WriteEvent("MissingMediaFileEditor constructor. file = {0}", file); InitializeComponent(); @@ -60,22 +60,18 @@ protected override void HandleStringsLocalized(object sender, EventArgs e) { base.HandleStringsLocalized(sender, e); - var lm = (ILocalizationManager)sender; - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - TabText = LocalizationManager.GetString( - "SessionsView.MissingMediaFileEditor.TabText", "Missing Media File"); - - if (lblExplanation == null) - return; + TabText = LocalizationManager.GetString( + "SessionsView.MissingMediaFileEditor.TabText", "Missing Media File"); - lblExplanation.Text = LocalizationManager.GetString( - "SessionsView.MissingMediaFileEditor.lblExplanation", - "This can happen if the media file is inadvertently deleted or renamed outside of SayMore. " + - "It could also happen if a properly named ELAN file is added to a SayMore session but internally " + - "refers to a media file that is not where SayMore expects to find it. If you have access to the media " + - "file and would like to be able to annotate it in SayMore, please copy it to the above location."); - } + if (lblExplanation == null) + return; + + lblExplanation.Text = LocalizationManager.GetString( + "SessionsView.MissingMediaFileEditor.lblExplanation", + "This can happen if the media file is inadvertently deleted or renamed outside of SayMore. " + + "It could also happen if a properly named ELAN file is added to a SayMore session but internally " + + "refers to a media file that is not where SayMore expects to find it. If you have access to the media " + + "file and would like to be able to annotate it in SayMore, please copy it to the above location."); } } } From 3a7dcdc31eceab658352bb82b19e58545a255e19 Mon Sep 17 00:00:00 2001 From: tombogle Date: Mon, 8 Jun 2026 14:36:51 -0400 Subject: [PATCH 21/29] Task 9: remove ILocalizationManager from ProjectMetadataScreen and ProjectDocsScreen Drop lm constructor params from ProjectMetadataScreen, ProjectDocsScreen, ProjectDescriptionDocsScreen, and ProjectOtherDocsScreen. Remove _localizationManager field and clean up HandleStringsLocalized and HandleAfterComponentFileSelected. Co-Authored-By: Claude Sonnet 4.6 --- src/SayMore/UI/Overview/ProjectDocsScreen.cs | 18 ++++++------------ .../UI/Overview/ProjectMetadataScreen.cs | 2 +- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/SayMore/UI/Overview/ProjectDocsScreen.cs b/src/SayMore/UI/Overview/ProjectDocsScreen.cs index 3ab43645..4d66f97b 100644 --- a/src/SayMore/UI/Overview/ProjectDocsScreen.cs +++ b/src/SayMore/UI/Overview/ProjectDocsScreen.cs @@ -17,7 +17,6 @@ namespace SayMore.UI.Overview { public abstract partial class ProjectDocsScreen : EditorBase, ISayMoreView { - private readonly ILocalizationManager _localizationManager; private const string kOfficeTempPrefix = "~$"; protected abstract string FolderName { get; } protected abstract string ArchiveSessionName { get; } @@ -26,10 +25,8 @@ public abstract partial class ProjectDocsScreen : EditorBase, ISayMoreView private ComponentEditorsTabControl _tabCtrl; protected string _toolTipText; - protected ProjectDocsScreen(ILocalizationManager localizationManager) : - base(localizationManager) + protected ProjectDocsScreen() : base() { - _localizationManager = localizationManager; Logger.WriteEvent("ProjectDocsScreen constructor"); InitializeComponent(); @@ -93,8 +90,7 @@ protected override void OnHandleCreated(EventArgs e) protected override void HandleStringsLocalized(object sender, EventArgs e) { base.HandleStringsLocalized(sender, e); - var lm = (ILocalizationManager)sender; - if ((lm == null || lm.Id == kSayMoreLocalizationId) && _descriptionFileGrid != null) + if (_descriptionFileGrid != null) LocalizeStrings(); } @@ -192,9 +188,9 @@ private void HandleAfterComponentFileSelected(int index) List providers = new List(); if ((file.FileType is AudioFileType) || (file.FileType is VideoFileType)) - providers.Add(new AudioVideoPlayer(file, null, _localizationManager)); + providers.Add(new AudioVideoPlayer(file, null)); else if (file.FileType is ImageFileType) - providers.Add(new ImageViewer(file, _localizationManager)); + providers.Add(new ImageViewer(file)); else providers.Add(new BrowserEditor(file, null)); @@ -241,8 +237,7 @@ public class ProjectDescriptionDocsScreen : ProjectDocsScreen internal static string kFolderName = "DescriptionDocuments"; internal static string kArchiveSessionName = "Project Description Documents"; - public ProjectDescriptionDocsScreen(ILocalizationManager localizationManager) : - base(localizationManager) + public ProjectDescriptionDocsScreen() : base() { _descriptionFileGrid.InitializeGrid("ProjectDescriptionDocuments"); } @@ -268,8 +263,7 @@ public class ProjectOtherDocsScreen : ProjectDocsScreen internal static string kFolderName = "OtherDocuments"; internal static string kArchiveSessionName = "Other Project Documents"; - public ProjectOtherDocsScreen(ILocalizationManager localizationManager) : - base(localizationManager) + public ProjectOtherDocsScreen() : base() { _descriptionFileGrid.InitializeGrid("ProjectOtherDocuments"); } diff --git a/src/SayMore/UI/Overview/ProjectMetadataScreen.cs b/src/SayMore/UI/Overview/ProjectMetadataScreen.cs index cd4d0f8f..96b7b640 100644 --- a/src/SayMore/UI/Overview/ProjectMetadataScreen.cs +++ b/src/SayMore/UI/Overview/ProjectMetadataScreen.cs @@ -23,7 +23,7 @@ public partial class ProjectMetadataScreen : EditorBase, ISayMoreView, ISaveable private string _fmtFontForWorkingLanguage; private readonly IMDIItemList _countryList; - public ProjectMetadataScreen(ILocalizationManager localizationManager) : base(localizationManager) + public ProjectMetadataScreen() : base() { Logger.WriteEvent("ProjectMetadataScreen constructor"); From cc5cb1ddf8521e62476985c4bdfa0d9b0f7e173e Mon Sep 17 00:00:00 2001 From: tombogle Date: Mon, 8 Jun 2026 14:39:52 -0400 Subject: [PATCH 22/29] =?UTF-8?q?Task=2010:=20rewrite=20UILanguageDlg=20?= =?UTF-8?q?=E2=80=94=20remove=20ILocalizationManager,=20replace=20ShowLoca?= =?UTF-8?q?lizationDialogBox=20with=20Crowdin=20URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../ProjectWindow/UILanguageDlg.Designer.cs | 29 +++---------------- src/SayMore/UI/ProjectWindow/UILanguageDlg.cs | 20 ++----------- 2 files changed, 7 insertions(+), 42 deletions(-) diff --git a/src/SayMore/UI/ProjectWindow/UILanguageDlg.Designer.cs b/src/SayMore/UI/ProjectWindow/UILanguageDlg.Designer.cs index 522106d2..ccf38388 100644 --- a/src/SayMore/UI/ProjectWindow/UILanguageDlg.Designer.cs +++ b/src/SayMore/UI/ProjectWindow/UILanguageDlg.Designer.cs @@ -36,7 +36,6 @@ private void InitializeComponent() this._buttonOK = new System.Windows.Forms.Button(); this.locExtender = new L10NSharp.Windows.Forms.L10NSharpExtender(this.components); this._linkIWantToLocalize = new System.Windows.Forms.LinkLabel(); - this._linkHelpOnLocalizing = new System.Windows.Forms.LinkLabel(); this._tableLayoutPanel.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.locExtender)).BeginInit(); this.SuspendLayout(); @@ -49,18 +48,16 @@ private void InitializeComponent() this._tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this._tableLayoutPanel.Controls.Add(this._comboUILanguage, 1, 0); this._tableLayoutPanel.Controls.Add(this._labelLanguage, 0, 0); - this._tableLayoutPanel.Controls.Add(this._buttonCancel, 2, 3); - this._tableLayoutPanel.Controls.Add(this._buttonOK, 1, 3); + this._tableLayoutPanel.Controls.Add(this._buttonCancel, 2, 2); + this._tableLayoutPanel.Controls.Add(this._buttonOK, 1, 2); this._tableLayoutPanel.Controls.Add(this._linkIWantToLocalize, 0, 1); - this._tableLayoutPanel.Controls.Add(this._linkHelpOnLocalizing, 0, 2); this._tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; this._tableLayoutPanel.Location = new System.Drawing.Point(20, 20); this._tableLayoutPanel.Name = "_tableLayoutPanel"; - this._tableLayoutPanel.RowCount = 4; + this._tableLayoutPanel.RowCount = 3; this._tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this._tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); this._tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this._tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); this._tableLayoutPanel.Size = new System.Drawing.Size(298, 126); this._tableLayoutPanel.TabIndex = 0; // @@ -152,24 +149,7 @@ private void InitializeComponent() this._linkIWantToLocalize.TabStop = true; this._linkIWantToLocalize.Text = "I want to localize SayMore for another language..."; this._linkIWantToLocalize.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.HandleIWantToLocalizeLinkClicked); - // - // _linkHelpOnLocalizing - // - this._linkHelpOnLocalizing.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this._linkHelpOnLocalizing.AutoSize = true; - this._tableLayoutPanel.SetColumnSpan(this._linkHelpOnLocalizing, 3); - this.locExtender.SetLocalizableToolTip(this._linkHelpOnLocalizing, null); - this.locExtender.SetLocalizationComment(this._linkHelpOnLocalizing, null); - this.locExtender.SetLocalizingId(this._linkHelpOnLocalizing, "DialogBoxes.UserInterfaceLanguageDlg.HelpOnLocalizingLink"); - this._linkHelpOnLocalizing.Location = new System.Drawing.Point(0, 67); - this._linkHelpOnLocalizing.Margin = new System.Windows.Forms.Padding(0, 10, 0, 0); - this._linkHelpOnLocalizing.Name = "_linkHelpOnLocalizing"; - this._linkHelpOnLocalizing.Size = new System.Drawing.Size(298, 13); - this._linkHelpOnLocalizing.TabIndex = 3; - this._linkHelpOnLocalizing.TabStop = true; - this._linkHelpOnLocalizing.Text = "Help on localization"; - this._linkHelpOnLocalizing.Visible = false; - // + // // UILanguageDlg // this.AcceptButton = this._buttonOK; @@ -206,6 +186,5 @@ private void InitializeComponent() private System.Windows.Forms.Button _buttonOK; private L10NSharp.Windows.Forms.L10NSharpExtender locExtender; private System.Windows.Forms.LinkLabel _linkIWantToLocalize; - private System.Windows.Forms.LinkLabel _linkHelpOnLocalizing; } } \ No newline at end of file diff --git a/src/SayMore/UI/ProjectWindow/UILanguageDlg.cs b/src/SayMore/UI/ProjectWindow/UILanguageDlg.cs index 7462ee2e..8d822936 100644 --- a/src/SayMore/UI/ProjectWindow/UILanguageDlg.cs +++ b/src/SayMore/UI/ProjectWindow/UILanguageDlg.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.Globalization; using System.Windows.Forms; using L10NSharp; @@ -7,41 +8,26 @@ namespace SayMore.UI.ProjectWindow { public partial class UILanguageDlg : Form { - private readonly ILocalizationManager _localizationManager; - public delegate UILanguageDlg Factory(); //autofac uses this public string UILanguage { get; private set; } - /// ------------------------------------------------------------------------------------ - public UILanguageDlg(ILocalizationManager localizationManager) + public UILanguageDlg() { Logger.WriteEvent("UILanguageDlg constructor"); - - _localizationManager = localizationManager; InitializeComponent(); - _labelLanguage.Font = Program.DialogFont; _linkIWantToLocalize.Font = Program.DialogFont; - if (!localizationManager.CanCustomizeLocalizations) - { - _linkIWantToLocalize.Text = LocalizationManager.GetString( - "DialogBoxes.UserInterfaceLanguageDlg.ViewLocalizationsLink", - "View SayMore localizations..."); - } - _linkHelpOnLocalizing.Font = Program.DialogFont; _comboUILanguage.Font = Program.DialogFont; _comboUILanguage.SelectedItem = CultureInfo.GetCultureInfo(LocalizationManager.UILanguageId); DialogResult = DialogResult.Cancel; } - /// ------------------------------------------------------------------------------------ private void HandleIWantToLocalizeLinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - _localizationManager.ShowLocalizationDialogBox(false); + Process.Start("https://crowdin.com/project/saymore"); _comboUILanguage.RefreshList(); } - /// ------------------------------------------------------------------------------------ protected override void OnFormClosing(FormClosingEventArgs e) { if (DialogResult == DialogResult.OK) From c3e4e9250b923be1039730fe25dcd8a2e3ce2559 Mon Sep 17 00:00:00 2001 From: tombogle Date: Mon, 8 Jun 2026 14:58:20 -0400 Subject: [PATCH 23/29] Task 11a: fix two missed EditorBase subclasses (BasicFieldGridEditor, ContributorsEditor) These were not in the original plan but had the same 4-arg base call and lm guard patterns as Task 8 files. Co-Authored-By: Claude Sonnet 4.6 --- .../UI/ComponentEditors/BasicFieldGridEditor.cs | 9 +++------ .../UI/ComponentEditors/ContributorsEditor.cs | 13 ++++--------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/SayMore/UI/ComponentEditors/BasicFieldGridEditor.cs b/src/SayMore/UI/ComponentEditors/BasicFieldGridEditor.cs index ab572bb3..c65dd46b 100644 --- a/src/SayMore/UI/ComponentEditors/BasicFieldGridEditor.cs +++ b/src/SayMore/UI/ComponentEditors/BasicFieldGridEditor.cs @@ -16,9 +16,8 @@ public partial class BasicFieldGridEditor : EditorBase /// ------------------------------------------------------------------------------------ public BasicFieldGridEditor(ComponentFile file, string imageKey, - AutoCompleteValueGatherer autoCompleteProvider, FieldGatherer fieldGatherer, - ILocalizationManager localizationManager) - : base(file, null, imageKey, localizationManager) + AutoCompleteValueGatherer autoCompleteProvider, FieldGatherer fieldGatherer) + : base(file, null, imageKey) { InitializeComponent(); Name = "BasicFieldGridEditor"; @@ -53,9 +52,7 @@ public override void SetComponentFile(ComponentFile file) /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - var lm = (ILocalizationManager)sender; - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - TabText = GetPropertiesTabText(); + TabText = GetPropertiesTabText(); base.HandleStringsLocalized(sender, e); } diff --git a/src/SayMore/UI/ComponentEditors/ContributorsEditor.cs b/src/SayMore/UI/ComponentEditors/ContributorsEditor.cs index 04ec3390..0162f055 100644 --- a/src/SayMore/UI/ComponentEditors/ContributorsEditor.cs +++ b/src/SayMore/UI/ComponentEditors/ContributorsEditor.cs @@ -32,9 +32,8 @@ public partial class ContributorsEditor : EditorBase /// ------------------------------------------------------------------------------------ public ContributorsEditor(ComponentFile file, string imageKey, - AutoCompleteValueGatherer autoCompleteProvider, PersonInformant personInformant, - ILocalizationManager localizationManager) : - base(file, null, imageKey, localizationManager) + AutoCompleteValueGatherer autoCompleteProvider, PersonInformant personInformant) : + base(file, null, imageKey) { InitializeComponent(); Name = "Contributors"; @@ -419,12 +418,8 @@ private string GetParticipants(bool withRoles) /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - var lm = (ILocalizationManager)sender; - if (lm == null || lm.Id == ApplicationContainer.kSayMoreLocalizationId) - { - TabText = LocalizationManager.GetString( - "CommonToMultipleViews.ContributorsEditor.TabText", "Contributors"); - } + TabText = LocalizationManager.GetString( + "CommonToMultipleViews.ContributorsEditor.TabText", "Contributors"); base.HandleStringsLocalized(sender, e); } From cb3ef5237e12b20f756de47bafcc7707851b5eb1 Mon Sep 17 00:00:00 2001 From: tombogle Date: Tue, 9 Jun 2026 10:40:57 -0400 Subject: [PATCH 24/29] Refactor: move HandleStringsLocalized initial call from EditorBase constructor to OnLoad Co-Authored-By: Claude Sonnet 4.6 --- src/SayMore/UI/ComponentEditors/EditorBase.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/SayMore/UI/ComponentEditors/EditorBase.cs b/src/SayMore/UI/ComponentEditors/EditorBase.cs index 6e876938..1ef538b9 100644 --- a/src/SayMore/UI/ComponentEditors/EditorBase.cs +++ b/src/SayMore/UI/ComponentEditors/EditorBase.cs @@ -60,9 +60,7 @@ protected EditorBase() ControlRemoved += HandleControlRemoved; Layout += HandleLayout; - if (_localizationManager != null) - _localizationManager.UiLanguageChanged += HandleStringsLocalized; - HandleStringsLocalized(null, EventArgs.Empty); + _localizationManager?.UiLanguageChanged += HandleStringsLocalized; } /// ------------------------------------------------------------------------------------ @@ -181,6 +179,7 @@ protected set protected override void OnLoad(EventArgs e) { SetLabelFonts(this, FontHelper.MakeFont(Program.DialogFont, FontStyle.Bold)); + HandleStringsLocalized(null, EventArgs.Empty); base.OnLoad(e); } @@ -190,8 +189,7 @@ protected override void OnHandleCreated(EventArgs e) base.OnHandleCreated(e); var owningTabControl = FindParent(this); - if (owningTabControl != null) - owningTabControl.VisibleChanged += (sender, args) => OnParentTabControlVisibleChanged(); + owningTabControl?.VisibleChanged += (sender, args) => OnParentTabControlVisibleChanged(); if (_setWorkingFontWhenHandleIsCreated) SetWorkingLanguageFont(); From 39df72098ee010d5a5606cad42c4813aa173d105 Mon Sep 17 00:00:00 2001 From: tombogle Date: Tue, 9 Jun 2026 10:40:57 -0400 Subject: [PATCH 25/29] Add superpowers/ to .gitignore Co-Authored-By: Claude Sonnet 4.6 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d88d8e35..f5dc2d0e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +superpowers/** obj/ **/output/** **/bin/** From 4d135fd716509ac9a7f78d814cf07953f90c560b Mon Sep 17 00:00:00 2001 From: tombogle Date: Tue, 9 Jun 2026 10:49:38 -0400 Subject: [PATCH 26/29] Cleanup: remove dead tabText constructor param and Initialize method from EditorBase tabText was always null at every call site; Initialize only set ImageKey (after a no-op TabText assignment). Replace the 3-param EditorBase constructor with a 2-param one that sets ImageKey directly, remove Initialize from both the IEditorProvider interface and the class body, and update all 18 subclasses (including MediaComponentEditor and its two subclasses) to drop the null arg. Co-Authored-By: Claude Sonnet 4.6 --- .../ComponentEditors/ConvertToStandardAudioEditor.cs | 2 +- .../UI/ComponentEditors/OralAnnotationEditor.cs | 2 +- .../UI/ComponentEditors/StartAnnotatingEditor.cs | 2 +- .../UI/ComponentEditors/TextAnnotationEditor.cs | 2 +- .../UI/ComponentEditors/AudioComponentEditor.cs | 2 +- src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs | 2 +- .../UI/ComponentEditors/BasicFieldGridEditor.cs | 2 +- src/SayMore/UI/ComponentEditors/BrowserEditor.cs | 2 +- .../UI/ComponentEditors/ContributorsEditor.cs | 2 +- src/SayMore/UI/ComponentEditors/EditorBase.cs | 12 ++---------- src/SayMore/UI/ComponentEditors/ImageViewer.cs | 2 +- .../UI/ComponentEditors/MediaComponentEditor.cs | 4 ++-- .../UI/ComponentEditors/MissingMediaFileEditor.cs | 2 +- src/SayMore/UI/ComponentEditors/NotesEditor.cs | 2 +- src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs | 2 +- .../UI/ComponentEditors/PersonContributionEditor.cs | 2 +- .../UI/ComponentEditors/SessionBasicEditor.cs | 2 +- .../UI/ComponentEditors/StatusAndStagesEditor.cs | 2 +- .../UI/ComponentEditors/VideoComponentEditor.cs | 2 +- 19 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/SayMore/Transcription/UI/ComponentEditors/ConvertToStandardAudioEditor.cs b/src/SayMore/Transcription/UI/ComponentEditors/ConvertToStandardAudioEditor.cs index b70d0ee2..acf97eda 100644 --- a/src/SayMore/Transcription/UI/ComponentEditors/ConvertToStandardAudioEditor.cs +++ b/src/SayMore/Transcription/UI/ComponentEditors/ConvertToStandardAudioEditor.cs @@ -19,7 +19,7 @@ public partial class ConvertToStandardAudioEditor : EditorBase private static Bitmap s_informationIconAsBitmap; /// ------------------------------------------------------------------------------------ public ConvertToStandardAudioEditor(ComponentFile file) : - base(file, null, null) + base(file, null) { Logger.WriteEvent("ConvertToStandardAudioEditor constructor. file = {0}", file); InitializeComponent(); diff --git a/src/SayMore/Transcription/UI/ComponentEditors/OralAnnotationEditor.cs b/src/SayMore/Transcription/UI/ComponentEditors/OralAnnotationEditor.cs index 30e40e91..12c096e7 100644 --- a/src/SayMore/Transcription/UI/ComponentEditors/OralAnnotationEditor.cs +++ b/src/SayMore/Transcription/UI/ComponentEditors/OralAnnotationEditor.cs @@ -21,7 +21,7 @@ public partial class OralAnnotationEditor : EditorBase /// ------------------------------------------------------------------------------------ public OralAnnotationEditor(ComponentFile file) : - base(file, null, "Audio") + base(file, "Audio") { Logger.WriteEvent("OralAnnotationEditor constructor. file = {0}", file); InitializeComponent(); diff --git a/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.cs b/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.cs index 627f8ccb..8bfb5a5c 100644 --- a/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.cs +++ b/src/SayMore/Transcription/UI/ComponentEditors/StartAnnotatingEditor.cs @@ -21,7 +21,7 @@ public partial class StartAnnotatingEditor : EditorBase /// ------------------------------------------------------------------------------------ public StartAnnotatingEditor(ComponentFile file, Project project) : - base(file, null, null) + base(file, null) { _project = project; Logger.WriteEvent("OralAnnotationEditor constructor. file = {0}", file); diff --git a/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.cs b/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.cs index db862d1f..a4677e3f 100644 --- a/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.cs +++ b/src/SayMore/Transcription/UI/ComponentEditors/TextAnnotationEditor.cs @@ -38,7 +38,7 @@ public partial class TextAnnotationEditor : EditorBase /// ------------------------------------------------------------------------------------ public TextAnnotationEditor(ComponentFile file, string imageKey, Project project) - : base(file, null, imageKey) + : base(file, imageKey) { Logger.WriteEvent("TextAnnotationEditor constructor. file = {0}; imagekey = {1}", file, imageKey); InitializeComponent(); diff --git a/src/SayMore/UI/ComponentEditors/AudioComponentEditor.cs b/src/SayMore/UI/ComponentEditors/AudioComponentEditor.cs index d1a1c6d1..475598b1 100644 --- a/src/SayMore/UI/ComponentEditors/AudioComponentEditor.cs +++ b/src/SayMore/UI/ComponentEditors/AudioComponentEditor.cs @@ -13,7 +13,7 @@ public partial class AudioComponentEditor : MediaComponentEditor /// ------------------------------------------------------------------------------------ public AudioComponentEditor(ComponentFile file, string imageKey, AutoCompleteValueGatherer autoCompleteProvider, FieldGatherer fieldGatherer) - : base(file, null, imageKey, autoCompleteProvider, fieldGatherer) + : base(file, imageKey, autoCompleteProvider, fieldGatherer) { Name = "Audio File Information"; } diff --git a/src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs b/src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs index be7ddb80..f997fcfb 100644 --- a/src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs +++ b/src/SayMore/UI/ComponentEditors/AudioVideoPlayer.cs @@ -19,7 +19,7 @@ public partial class AudioVideoPlayer : EditorBase /// ------------------------------------------------------------------------------------ public AudioVideoPlayer(ComponentFile file, string imageKey) : - base(file, null, imageKey) + base(file, imageKey) { Logger.WriteEvent("AudioVideoPlayer constructor. file = {0}; imageKey = {1}", file, imageKey); InitializeComponent(); diff --git a/src/SayMore/UI/ComponentEditors/BasicFieldGridEditor.cs b/src/SayMore/UI/ComponentEditors/BasicFieldGridEditor.cs index c65dd46b..34e365c8 100644 --- a/src/SayMore/UI/ComponentEditors/BasicFieldGridEditor.cs +++ b/src/SayMore/UI/ComponentEditors/BasicFieldGridEditor.cs @@ -17,7 +17,7 @@ public partial class BasicFieldGridEditor : EditorBase /// ------------------------------------------------------------------------------------ public BasicFieldGridEditor(ComponentFile file, string imageKey, AutoCompleteValueGatherer autoCompleteProvider, FieldGatherer fieldGatherer) - : base(file, null, imageKey) + : base(file, imageKey) { InitializeComponent(); Name = "BasicFieldGridEditor"; diff --git a/src/SayMore/UI/ComponentEditors/BrowserEditor.cs b/src/SayMore/UI/ComponentEditors/BrowserEditor.cs index c041582c..41f56d16 100644 --- a/src/SayMore/UI/ComponentEditors/BrowserEditor.cs +++ b/src/SayMore/UI/ComponentEditors/BrowserEditor.cs @@ -17,7 +17,7 @@ public partial class BrowserEditor : EditorBase private HtmlElement _fileLink; /// ------------------------------------------------------------------------------------ - public BrowserEditor(ComponentFile file, string imageKey) : base(file, null, imageKey) + public BrowserEditor(ComponentFile file, string imageKey) : base(file, imageKey) { InitializeComponent(); Name = "Browser"; diff --git a/src/SayMore/UI/ComponentEditors/ContributorsEditor.cs b/src/SayMore/UI/ComponentEditors/ContributorsEditor.cs index 0162f055..30870e56 100644 --- a/src/SayMore/UI/ComponentEditors/ContributorsEditor.cs +++ b/src/SayMore/UI/ComponentEditors/ContributorsEditor.cs @@ -33,7 +33,7 @@ public partial class ContributorsEditor : EditorBase /// ------------------------------------------------------------------------------------ public ContributorsEditor(ComponentFile file, string imageKey, AutoCompleteValueGatherer autoCompleteProvider, PersonInformant personInformant) : - base(file, null, imageKey) + base(file, imageKey) { InitializeComponent(); Name = "Contributors"; diff --git a/src/SayMore/UI/ComponentEditors/EditorBase.cs b/src/SayMore/UI/ComponentEditors/EditorBase.cs index 1ef538b9..53a95699 100644 --- a/src/SayMore/UI/ComponentEditors/EditorBase.cs +++ b/src/SayMore/UI/ComponentEditors/EditorBase.cs @@ -18,7 +18,6 @@ public interface IEditorProvider Control Control { get; } string TabText { get; } string ImageKey { get; } - void Initialize(string tabText, string imageKey); void SetComponentFile(ComponentFile file); bool ComponentFileDeletionInitiated(ComponentFile file); Action ComponentFileListRefreshAction { set; } @@ -64,10 +63,10 @@ protected EditorBase() } /// ------------------------------------------------------------------------------------ - public EditorBase(ComponentFile file, string tabText, string imageKey) : this() + public EditorBase(ComponentFile file, string imageKey) : this() { _file = file; - Initialize(tabText, imageKey); + ImageKey = imageKey; } /// ------------------------------------------------------------------------------------ @@ -89,13 +88,6 @@ protected override void Dispose(bool disposing) } } - /// ------------------------------------------------------------------------------------ - public void Initialize(string tabText, string imageKey) - { - TabText = tabText ?? TabText; - ImageKey = imageKey; - } - /// ------------------------------------------------------------------------------------ public void RefreshComponentFiles(string fileToSelectAfterRefresh, Type componentEditorTypeToSelect) diff --git a/src/SayMore/UI/ComponentEditors/ImageViewer.cs b/src/SayMore/UI/ComponentEditors/ImageViewer.cs index 691dac05..c8ee18d8 100644 --- a/src/SayMore/UI/ComponentEditors/ImageViewer.cs +++ b/src/SayMore/UI/ComponentEditors/ImageViewer.cs @@ -18,7 +18,7 @@ public partial class ImageViewer : EditorBase /// ------------------------------------------------------------------------------------ public ImageViewer(ComponentFile file) : - base(file, null, "Image") + base(file, "Image") { Logger.WriteEvent("ImageViewer constructor. file = {0}", file); InitializeComponent(); diff --git a/src/SayMore/UI/ComponentEditors/MediaComponentEditor.cs b/src/SayMore/UI/ComponentEditors/MediaComponentEditor.cs index 412d497e..03aa4702 100644 --- a/src/SayMore/UI/ComponentEditors/MediaComponentEditor.cs +++ b/src/SayMore/UI/ComponentEditors/MediaComponentEditor.cs @@ -26,9 +26,9 @@ public MediaComponentEditor() } /// ------------------------------------------------------------------------------------ - public MediaComponentEditor(ComponentFile file, string tabText, string imageKey, + public MediaComponentEditor(ComponentFile file, string imageKey, AutoCompleteValueGatherer autoCompleteProvider, FieldGatherer fieldGatherer) - : base(file, tabText, imageKey) + : base(file, imageKey) { InitializeComponent(); InitializeGrid(autoCompleteProvider, fieldGatherer); diff --git a/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.cs b/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.cs index d5e512ba..86897cf3 100644 --- a/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.cs +++ b/src/SayMore/UI/ComponentEditors/MissingMediaFileEditor.cs @@ -12,7 +12,7 @@ public partial class MissingMediaFileEditor : EditorBase { /// ------------------------------------------------------------------------------------ public MissingMediaFileEditor(ComponentFile file, string imageKey) - : base(file, null, imageKey) + : base(file, imageKey) { Logger.WriteEvent("MissingMediaFileEditor constructor. file = {0}", file); InitializeComponent(); diff --git a/src/SayMore/UI/ComponentEditors/NotesEditor.cs b/src/SayMore/UI/ComponentEditors/NotesEditor.cs index 0ac6a029..9f092c9f 100644 --- a/src/SayMore/UI/ComponentEditors/NotesEditor.cs +++ b/src/SayMore/UI/ComponentEditors/NotesEditor.cs @@ -14,7 +14,7 @@ public partial class NotesEditor : EditorBase private string _origTabText; /// ------------------------------------------------------------------------------------ - public NotesEditor(ComponentFile file) : base(file, null, "Notes") + public NotesEditor(ComponentFile file) : base(file, "Notes") { InitializeComponent(); Name = "Notes"; diff --git a/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs b/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs index 3b3eb3f9..91c04afc 100644 --- a/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs +++ b/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs @@ -51,7 +51,7 @@ public sealed partial class PersonBasicEditor : EditorBase public PersonBasicEditor(ComponentFile file, string imageKey, AutoCompleteValueGatherer autoCompleteProvider, FieldGatherer fieldGatherer, ImageFileType imgFileType) - : base(file, null, imageKey) + : base(file, imageKey) { Logger.WriteEvent("PersonBasicEditor constructor. file = {0}", file); diff --git a/src/SayMore/UI/ComponentEditors/PersonContributionEditor.cs b/src/SayMore/UI/ComponentEditors/PersonContributionEditor.cs index 95e89f5c..df69295a 100644 --- a/src/SayMore/UI/ComponentEditors/PersonContributionEditor.cs +++ b/src/SayMore/UI/ComponentEditors/PersonContributionEditor.cs @@ -20,7 +20,7 @@ public partial class PersonContributionEditor : EditorBase private string _personCode; public PersonContributionEditor(ComponentFile file, string imageKey) - : base(file, null, imageKey) + : base(file, imageKey) { InitializeComponent(); RememberPersonId(file); diff --git a/src/SayMore/UI/ComponentEditors/SessionBasicEditor.cs b/src/SayMore/UI/ComponentEditors/SessionBasicEditor.cs index 086f006c..246bebd2 100644 --- a/src/SayMore/UI/ComponentEditors/SessionBasicEditor.cs +++ b/src/SayMore/UI/ComponentEditors/SessionBasicEditor.cs @@ -42,7 +42,7 @@ public partial class SessionBasicEditor : EditorBase public SessionBasicEditor(ComponentFile file, string imageKey, AutoCompleteValueGatherer autoCompleteProvider, FieldGatherer fieldGatherer, PersonInformant personInformant) - : base(file, null, imageKey) + : base(file, imageKey) { Logger.WriteEvent("PersonBasicEditor constructor. file = {0}", file); diff --git a/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.cs b/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.cs index cd946e4c..d33ec7e4 100644 --- a/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.cs +++ b/src/SayMore/UI/ComponentEditors/StatusAndStagesEditor.cs @@ -23,7 +23,7 @@ public partial class StatusAndStagesEditor : EditorBase /// ---------------------------------------------------------------------------------------- public StatusAndStagesEditor(ComponentFile file, string imageKey, - IEnumerable componentRoles) : base(file, null, imageKey) + IEnumerable componentRoles) : base(file, imageKey) { InitializeComponent(); Name = "StatusAndStages"; diff --git a/src/SayMore/UI/ComponentEditors/VideoComponentEditor.cs b/src/SayMore/UI/ComponentEditors/VideoComponentEditor.cs index 3dccc8aa..12377946 100644 --- a/src/SayMore/UI/ComponentEditors/VideoComponentEditor.cs +++ b/src/SayMore/UI/ComponentEditors/VideoComponentEditor.cs @@ -13,7 +13,7 @@ public partial class VideoComponentEditor : MediaComponentEditor /// ------------------------------------------------------------------------------------ public VideoComponentEditor(ComponentFile file, string imageKey, AutoCompleteValueGatherer autoCompleteProvider, FieldGatherer fieldGatherer) - : base(file, null, imageKey, autoCompleteProvider, fieldGatherer) + : base(file, imageKey, autoCompleteProvider, fieldGatherer) { Name = "Video File Information"; } From 928ad459273ccd7366bdc8879e305d24cd2bfb31 Mon Sep 17 00:00:00 2001 From: tombogle Date: Wed, 10 Jun 2026 09:13:08 -0400 Subject: [PATCH 27/29] Fix: defer gender ComboBox selection until items are populated (crash after lm removal) --- .../UI/ComponentEditors/PersonBasicEditor.cs | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs b/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs index 91c04afc..b7be6e8c 100644 --- a/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs +++ b/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs @@ -22,12 +22,16 @@ using static System.StringComparison; using static SayMore.UI.LowLevelControls.ParentType; using static SIL.Windows.Forms.Extensions.ControlExtensions.ErrorHandlingAction; +using static System.Text.NormalizationForm; namespace SayMore.UI.ComponentEditors { /// ---------------------------------------------------------------------------------------- public sealed partial class PersonBasicEditor : EditorBase { + private const int kMaleIndex = 0; + private const int kFemaleIndex = 1; + public delegate PersonBasicEditor Factory(ComponentFile file, string imageKey); private readonly List _fatherButtons = new List(); @@ -38,6 +42,7 @@ public sealed partial class PersonBasicEditor : EditorBase private readonly ImageFileType _imgFileType; private bool _loaded; + private int? _pendingSelectedGenderIndex; // SP-846: Do not save parent languages while setting them private bool _loadingLanguages; @@ -817,18 +822,18 @@ private string GetPictureFileFromDragData(IDataObject data) /// ------------------------------------------------------------------------------------ protected override void HandleStringsLocalized(object sender, EventArgs e) { - TabText = LocalizationManager.GetString("PeopleView.MetadataEditor.TabText", - "Person"); + TabText = LocalizationManager.GetString("PeopleView.MetadataEditor.TabText", "Person"); if (_gender != null) { - int i = _gender.SelectedIndex; + int selectedIndex = _pendingSelectedGenderIndex ?? _gender.SelectedIndex; + _pendingSelectedGenderIndex = null; _gender.Items.Clear(); _gender.Items.Add(LocalizationManager.GetString( "PeopleView.MetadataEditor.GenderSelector.Male", "Male")); _gender.Items.Add(LocalizationManager.GetString( "PeopleView.MetadataEditor.GenderSelector.Female", "Female")); - _gender.SelectedIndex = i; + _gender.SelectedIndex = selectedIndex; } base.HandleStringsLocalized(sender, e); @@ -836,10 +841,25 @@ protected override void HandleStringsLocalized(object sender, EventArgs e) /// ------------------------------------------------------------------------------------ /// - /// Instead of letting the binding helper set the gender combo box value from the - /// value in the file (which will be the English text for male or female), we'll - /// intercept the process since the text in the gender combo box may have been - /// localized to non-English text. + /// Localized forms of "Male" known to have been written by versions of SayMore affected + /// by SP-847. + /// + /// ------------------------------------------------------------------------------------ + private static readonly HashSet s_maleGenderValues = + [ + "Male", + "Macho", + "Mâle".Normalize(FormD), + "Мужской".Normalize(FormD), + "男性".Normalize(FormD), + ]; + + /// ------------------------------------------------------------------------------------ + /// + /// A former bug (SP-847) caused gender metadata to be saved as a localized form rather + /// than the standard (English) values. So, instead of letting the binding helper set the + /// index of the gender combo box from the value in the file, recognize the localized + /// versions as well. /// /// ------------------------------------------------------------------------------------ private void HandleBinderTranslateBoundValueBeingRetrieved(object sender, @@ -847,15 +867,12 @@ private void HandleBinderTranslateBoundValueBeingRetrieved(object sender, { if (args.BoundControl == _gender) { - // Because of a former bug (SP-847), gender metadata was saved as localized - // string instead of English, so when retrieving, recognize those versions of the - // values for "Male" as well. - string valueFromFile = args.ValueFromFile.Normalize(NormalizationForm.FormD); - _gender.SelectedIndex = (valueFromFile == "Male" || - valueFromFile == "Macho" || - valueFromFile == "Mâle".Normalize(NormalizationForm.FormD) || - valueFromFile == "Мужской".Normalize(NormalizationForm.FormD) || - valueFromFile == "男性".Normalize(NormalizationForm.FormD) ? 0 : 1); + string valueFromFile = args.ValueFromFile.Normalize(FormD); + int index = s_maleGenderValues.Contains(valueFromFile) ? kMaleIndex : kFemaleIndex; + if (_gender.Items.Count < 2) + _pendingSelectedGenderIndex = index; + else + _gender.SelectedIndex = index; args.Handled = true; } } From bc0d2470a1dfe0db3fe893a75d8f90609c3296e2 Mon Sep 17 00:00:00 2001 From: tombogle Date: Thu, 25 Jun 2026 17:26:21 -0400 Subject: [PATCH 28/29] Fixed problem with unit tests when trying to select an invalid index for the _gender control. --- .../UI/ComponentEditors/PersonBasicEditor.cs | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs b/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs index b7be6e8c..f2cd0d07 100644 --- a/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs +++ b/src/SayMore/UI/ComponentEditors/PersonBasicEditor.cs @@ -826,14 +826,26 @@ protected override void HandleStringsLocalized(object sender, EventArgs e) if (_gender != null) { - int selectedIndex = _pendingSelectedGenderIndex ?? _gender.SelectedIndex; + // If a pending selected index was recorded earlier (before we had populated + // the items), prefer that; otherwise use the current SelectedIndex. We'll + // populate the localized items and then clamp the selected index to a valid + // range to avoid exceptions during startup/initialization. + int selectedIndex = _pendingSelectedGenderIndex ?? _gender.SelectedIndex; _pendingSelectedGenderIndex = null; _gender.Items.Clear(); _gender.Items.Add(LocalizationManager.GetString( "PeopleView.MetadataEditor.GenderSelector.Male", "Male")); _gender.Items.Add(LocalizationManager.GetString( "PeopleView.MetadataEditor.GenderSelector.Female", "Female")); - _gender.SelectedIndex = selectedIndex; + // Ensure the index is within bounds in case of unusual state during startup. + if (_gender.Items.Count > 0) + { + if (selectedIndex < 0) + selectedIndex = 0; + if (selectedIndex >= _gender.Items.Count) + selectedIndex = _gender.Items.Count - 1; + _gender.SelectedIndex = selectedIndex; + } } base.HandleStringsLocalized(sender, e); @@ -867,12 +879,14 @@ private void HandleBinderTranslateBoundValueBeingRetrieved(object sender, { if (args.BoundControl == _gender) { + // Normalize and map any localized "male" values to our canonical indices. string valueFromFile = args.ValueFromFile.Normalize(FormD); int index = s_maleGenderValues.Contains(valueFromFile) ? kMaleIndex : kFemaleIndex; - if (_gender.Items.Count < 2) - _pendingSelectedGenderIndex = index; - else - _gender.SelectedIndex = index; + // Record the desired index and defer actually setting SelectedIndex until the + // localized items have been populated (see HandleStringsLocalized). This avoids + // attempting to set SelectedIndex on a ComboBox that hasn't been filled yet, + // which can throw in certain initialization sequences. + _pendingSelectedGenderIndex = index; args.Handled = true; } } From 1aa9d31d481a8c31a2aca8957329f40a224cea1d Mon Sep 17 00:00:00 2001 From: tombogle Date: Wed, 1 Jul 2026 11:36:11 -0400 Subject: [PATCH 29/29] Updated to latest (beta) SIL DLLs --- src/SayMore/SayMore.csproj | 16 ++++++++-------- src/SayMoreTests/SayMoreTests.csproj | 14 +++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/SayMore/SayMore.csproj b/src/SayMore/SayMore.csproj index 7516423b..fe3da98c 100644 --- a/src/SayMore/SayMore.csproj +++ b/src/SayMore/SayMore.csproj @@ -37,7 +37,7 @@ - + @@ -49,18 +49,18 @@ - - + + - + All - - - - + + + + diff --git a/src/SayMoreTests/SayMoreTests.csproj b/src/SayMoreTests/SayMoreTests.csproj index 1f7c0a6b..cc979e02 100644 --- a/src/SayMoreTests/SayMoreTests.csproj +++ b/src/SayMoreTests/SayMoreTests.csproj @@ -68,13 +68,13 @@ - - - - - - - + + + + + + +