Skip to content

Commit aa743e1

Browse files
committed
LT-18830: Rework the IUtility system
Includes: 1. Assimilating all IUtility implementations into the UtilityDlg class. 2. Make one version of the string "???" and have all clients use it. 3. Move code out of the IUtility impls and into FwUtils as extensions of LCM. 4. Move related tests for #3 into FwUtils test assembly. 5. Re-add support for user-defined IUtility impls. 6. Get rid of unused code (e.g., SampleCitationFormTransducer class). Change-Id: I38629bd5929d1fc8c1b851ac13212f4b4f5c69b6
1 parent 9b0b7bc commit aa743e1

File tree

54 files changed

+1494
-2084
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1494
-2084
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<root>
3+
<!-- Add 'utility' child elements for each user defined assembly.
4+
Each 'utility' element will need to have one required attribute named 'assembly',
5+
which is the name of the dll that contins one or more implementations of the IUtility interface.
6+
Each implementation should have a public contructor that takes a UtilityDlg parameter.
7+
-->
8+
</root>

Src/FieldWorks.TestUtilities/FieldWorks.TestUtilities.csproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@
8383
<Reference Include="FwUtils">
8484
<HintPath>..\..\Output\Debug\FwUtils.dll</HintPath>
8585
</Reference>
86+
<Reference Include="Microsoft.Practices.ServiceLocation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
87+
<SpecificVersion>False</SpecificVersion>
88+
<HintPath>..\..\Output\Debug\Microsoft.Practices.ServiceLocation.dll</HintPath>
89+
</Reference>
8690
<Reference Include="nunit.framework">
8791
<HintPath>..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
8892
</Reference>
@@ -93,6 +97,10 @@
9397
<SpecificVersion>False</SpecificVersion>
9498
<HintPath>..\..\Output\Debug\SIL.Core.Desktop.dll</HintPath>
9599
</Reference>
100+
<Reference Include="SIL.LCModel, Version=9.0.0.680, Culture=neutral, processorArchitecture=MSIL">
101+
<SpecificVersion>False</SpecificVersion>
102+
<HintPath>..\..\Output\Debug\SIL.LCModel.dll</HintPath>
103+
</Reference>
96104
<Reference Include="SIL.LCModel.Core, Version=10.0.0.0, Culture=neutral, processorArchitecture=MSIL">
97105
<SpecificVersion>False</SpecificVersion>
98106
<HintPath>..\..\Output\Debug\SIL.LCModel.Core.dll</HintPath>
@@ -123,6 +131,7 @@
123131
<Compile Include="Attributes\DummyKeyboardAdaptor.cs" />
124132
<Compile Include="DisplayType.cs" />
125133
<Compile Include="FontOverride.cs" />
134+
<Compile Include="LexiconTestUtils.cs" />
126135
<Compile Include="MessageBoxStub.cs" />
127136
<Compile Include="Properties\AssemblyInfo.cs" />
128137
<Compile Include="TestBaseForTestsThatCreateTempFilesBasedOnResources.cs" />
@@ -131,6 +140,7 @@
131140
<Compile Include="XmlHelper.cs" />
132141
</ItemGroup>
133142
<ItemGroup>
143+
<WCFMetadata Include="Connected Services\" />
134144
</ItemGroup>
135145
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
136146
</Project>

Src/LanguageExplorerTests/LexiconTestUtils.cs renamed to Src/FieldWorks.TestUtilities/LexiconTestUtils.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
using SIL.LCModel.Core.Text;
88
using SIL.LCModel.Infrastructure;
99

10-
namespace LanguageExplorerTests
10+
namespace FieldWorks.TestUtilities
1111
{
1212
internal static class LexiconTestUtils
1313
{

Src/FwUtils/FwUtils.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@
240240
<Compile Include="IScrCheckInventory.cs" />
241241
<Compile Include="LcmExtensions.cs" />
242242
<Compile Include="LinkProperty.cs" />
243+
<Compile Include="ManagedLgIcuCollator.cs" />
243244
<Compile Include="MsrSysType.cs" />
244245
<Compile Include="ParagraphContinuationType.cs" />
245246
<Compile Include="ProjectId.cs" />

Src/FwUtils/FwUtilsStrings.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Src/FwUtils/FwUtilsStrings.resx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,4 +242,8 @@ Do you want to continue with the export?</value>
242242
<comment>When uploading to webonary if there is an unsupported wav file this message will be shown.
243243
{0} is the target filename, {1} is a newline character, and {2} is an error message about how the file is bad</comment>
244244
</data>
245-
</root>
245+
<data name="ksThreeQuestionMarks" xml:space="preserve">
246+
<value>???</value>
247+
<comment>signals unknown/missing information</comment>
248+
</data>
249+
</root>

Src/FwUtils/LcmExtensions.cs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Collections.Generic;
77
using System.Diagnostics;
88
using System.Globalization;
9+
using System.IO;
910
using System.Linq;
1011
using System.Text.RegularExpressions;
1112
using System.Windows.Forms;
@@ -312,6 +313,65 @@ public static ISilDataAccessManaged GetManagedSilDataAccess(this LcmCache me)
312313
return (ISilDataAccessManaged)me.DomainDataByFlid;
313314
}
314315

316+
public static bool ReplacePOSGuidsWithGoldEticGuids(this LcmCache me)
317+
{
318+
var goldDocument = new XmlDocument();
319+
goldDocument.Load(Path.Combine(FwDirectoryFinder.TemplateDirectory, "GOLDEtic.xml"));
320+
var itemsWithBadGuids = new Dictionary<IPartOfSpeech, string>();
321+
foreach (IPartOfSpeech pos in me.LangProject.PartsOfSpeechOA.PossibilitiesOS)
322+
{
323+
CheckPossibilityGuidAgainstGold(pos, goldDocument, itemsWithBadGuids);
324+
}
325+
if (!itemsWithBadGuids.Any())
326+
{
327+
return false;
328+
}
329+
foreach (var badItem in itemsWithBadGuids)
330+
{
331+
ReplacePosItemWithCloneWithNewGuid(me, badItem);
332+
}
333+
return true;
334+
}
335+
336+
private static void CheckPossibilityGuidAgainstGold(IPartOfSpeech pos, XmlDocument dom, Dictionary<IPartOfSpeech, string> itemsWithBadGuids)
337+
{
338+
if (!string.IsNullOrEmpty(pos.CatalogSourceId))
339+
{
340+
if (dom.SelectSingleNode($"//item[@id='{pos.CatalogSourceId}' and @guid='{pos.Guid}']") == null)
341+
{
342+
var selectNodeWithoutGuid = dom.SelectSingleNode($"//item[@id='{pos.CatalogSourceId}']");
343+
itemsWithBadGuids[pos] = selectNodeWithoutGuid.Attributes["guid"].Value;
344+
}
345+
}
346+
if (pos.SubPossibilitiesOS != null)
347+
{
348+
foreach (IPartOfSpeech subPos in pos.SubPossibilitiesOS)
349+
{
350+
CheckPossibilityGuidAgainstGold(subPos, dom, itemsWithBadGuids);
351+
}
352+
}
353+
}
354+
355+
private static void ReplacePosItemWithCloneWithNewGuid(LcmCache cache, KeyValuePair<IPartOfSpeech, string> badItem)
356+
{
357+
IPartOfSpeech replacementPos;
358+
var badPartOfSpeech = badItem.Key;
359+
var correctedGuid = new Guid(badItem.Value);
360+
var ownerList = badPartOfSpeech.Owner as ICmPossibilityList;
361+
if (ownerList != null)
362+
{
363+
replacementPos = cache.ServiceLocator.GetInstance<IPartOfSpeechFactory>().Create(correctedGuid, ownerList);
364+
ownerList.PossibilitiesOS.Insert(badPartOfSpeech.IndexInOwner, replacementPos);
365+
}
366+
else
367+
{
368+
var badPartOfSpeechOwner = badPartOfSpeech.Owner as IPartOfSpeech;
369+
replacementPos = cache.ServiceLocator.GetInstance<IPartOfSpeechFactory>().Create(correctedGuid, badPartOfSpeechOwner);
370+
badPartOfSpeechOwner.SubPossibilitiesOS.Insert(badPartOfSpeech.IndexInOwner, replacementPos);
371+
}
372+
replacementPos.MergeObject(badPartOfSpeech);
373+
}
374+
315375
public static ILexEntryType Create(this ILexEntryTypeFactory me, ICmPossibilityList owner)
316376
{
317377
Guard.AgainstNull(owner, nameof(owner));
@@ -454,6 +514,27 @@ private static string ChangeName(ICmPossibility obj)
454514
return prefix + " (Copy) (" + max + ")";
455515
}
456516

517+
/// <summary />
518+
public static void SortReversalSubEntriesInPlace(this LcmCache me)
519+
{
520+
var allReversalIndexes = me.ServiceLocator.GetInstance<IReversalIndexRepository>().AllInstances();
521+
foreach (var reversalIndex in allReversalIndexes)
522+
{
523+
using (var comp = new ReversalSubEntryIcuComparer(me, reversalIndex.WritingSystem))
524+
{
525+
foreach (var reversalIndexEntry in reversalIndex.EntriesOC.Where(rie => rie.SubentriesOS.Count > 1))
526+
{
527+
var subEntryArray = reversalIndexEntry.SubentriesOS.ToArray();
528+
Array.Sort(subEntryArray, comp);
529+
for (var i = 0; i < subEntryArray.Length; ++i)
530+
{
531+
reversalIndexEntry.SubentriesOS.Insert(i, subEntryArray[i]);
532+
}
533+
}
534+
}
535+
}
536+
}
537+
457538
public static Guid GetOrCreateWsGuid(this IReversalIndexRepository me, CoreWritingSystemDefinition wsObj, LcmCache cache)
458539
{
459540
var mHvoRevIdx = me.FindOrCreateIndexForWs(wsObj.Handle).Hvo;
@@ -680,5 +761,59 @@ public static XmlNode ConvertElement(this XElement me)
680761
doc.LoadXml(me.GetOuterXml());
681762
return doc.FirstChild;
682763
}
764+
765+
766+
/// <summary />
767+
private sealed class ReversalSubEntryIcuComparer : IComparer<IReversalIndexEntry>, IDisposable
768+
{
769+
private readonly int m_ws;
770+
private ManagedLgIcuCollator m_collator;
771+
772+
/// <summary />
773+
public ReversalSubEntryIcuComparer(LcmCache cache, string ws)
774+
{
775+
m_collator = new ManagedLgIcuCollator();
776+
m_ws = cache.WritingSystemFactory.GetWsFromStr(ws);
777+
m_collator.Open(ws);
778+
}
779+
780+
/// <summary />
781+
public int Compare(IReversalIndexEntry x, IReversalIndexEntry y)
782+
{
783+
var xString = x.ReversalForm.get_String(m_ws);
784+
var yString = y.ReversalForm.get_String(m_ws);
785+
return m_collator.Compare(xString.Text, yString.Text);
786+
}
787+
788+
#region disposal
789+
private bool _isDisposed;
790+
~ReversalSubEntryIcuComparer() { Dispose(false); }
791+
792+
/// <summary />
793+
public void Dispose()
794+
{
795+
Dispose(true);
796+
GC.SuppressFinalize(this);
797+
}
798+
799+
/// <summary />
800+
private void Dispose(bool disposing)
801+
{
802+
Debug.WriteLineIf(!disposing, "****** Missing Dispose() call for " + GetType().Name + ". ****** ");
803+
if (_isDisposed)
804+
{
805+
// No need to run it more than once.
806+
return;
807+
}
808+
if (disposing)
809+
{
810+
m_collator?.Dispose();
811+
}
812+
m_collator = null;
813+
814+
_isDisposed = true;
815+
}
816+
#endregion disposal
817+
}
683818
}
684819
}

Src/LanguageExplorer/ManagedLgIcuCollator.cs renamed to Src/FwUtils/ManagedLgIcuCollator.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2010-2018 SIL International
1+
// Copyright (c) 2010-2020 SIL International
22
// This software is licensed under the LGPL, version 2.1 or later
33
// (http://www.gnu.org/licenses/lgpl-2.1.html)
44

@@ -7,10 +7,10 @@
77
using Icu;
88
using Icu.Collation;
99

10-
namespace LanguageExplorer
10+
namespace SIL.FieldWorks.Common.FwUtils
1111
{
1212
/// <summary />
13-
internal sealed class ManagedLgIcuCollator : IDisposable
13+
public sealed class ManagedLgIcuCollator : IDisposable
1414
{
1515
private string _locale;
1616
private Collator _collator;
@@ -67,13 +67,13 @@ private void DoneCleanup()
6767
}
6868
}
6969

70-
internal int Compare(string value1, string value2)
70+
public int Compare(string value1, string value2)
7171
{
7272
EnsureCollator();
7373
return CompareVariant(_collator.GetSortKey(value1).KeyData, _collator.GetSortKey(value2).KeyData);
7474
}
7575

76-
internal int CompareVariant(object saValue1, object saValue2)
76+
public int CompareVariant(object saValue1, object saValue2)
7777
{
7878
EnsureCollator();
7979

@@ -100,15 +100,15 @@ internal int CompareVariant(object saValue1, object saValue2)
100100
return key1.Length > key2.Length ? 1 : key2.Length > key1.Length ? -1 : 0;
101101
}
102102

103-
internal object SortKeyVariant(string value)
103+
public object SortKeyVariant(string value)
104104
{
105105
EnsureCollator();
106106
var sortKey = _collator.GetSortKey(value).KeyData;
107107

108108
return sortKey;
109109
}
110110

111-
internal void Open(string locale)
111+
public void Open(string locale)
112112
{
113113
if (_collator != null)
114114
{
@@ -119,7 +119,7 @@ internal void Open(string locale)
119119
EnsureCollator();
120120
}
121121

122-
internal void Close()
122+
public void Close()
123123
{
124124
if (_collator != null)
125125
{

Src/LanguageExplorerTests/UtilityTools/CircularRefBreakerTests.cs renamed to Src/FwUtilsTests/CircularReferenceBreakerTests.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
// (http://www.gnu.org/licenses/lgpl-2.1.html)
44

55
using System.Collections.Generic;
6-
using LanguageExplorer.UtilityTools;
6+
using FieldWorks.TestUtilities;
77
using NUnit.Framework;
88
using SIL.LCModel;
9+
using SIL.LCModel.DomainServices;
910

10-
namespace LanguageExplorerTests.UtilityTools
11+
namespace SIL.FieldWorks.Common.FwUtils
1112
{
12-
public class CircularRefBreakerTests : MemoryOnlyBackendProviderTestBase
13+
/// <summary />
14+
public class CircularReferenceBreakerTests : MemoryOnlyBackendProviderTestBase
1315
{
16+
/// <summary />
1417
[Test]
1518
public void BreakCircularEntryRefs()
1619
{
@@ -31,29 +34,34 @@ public void BreakCircularEntryRefs()
3134
LexiconTestUtils.AddComplexFormComponents(Cache, c, new List<ICmObject> { ac.SensesOS[0] });
3235

3336
// SUT
34-
var breaker = new CircularRefBreaker();
37+
var count = int.MinValue;
38+
var circular = int.MinValue;
39+
Assert.DoesNotThrow(() => CircularRefBreakerService.ReferenceBreaker(Cache, out count, out circular, out _), "The CircularRefBreakerService.ReferenceBreaker method does not throw an exception");
3540

3641
// Verify
37-
Assert.DoesNotThrow(() => breaker.Process(Cache), "The BreakCircularRefs.Process(cache) method does not throw an exception");
3842
Assert.AreEqual(0, a.EntryRefsOS.Count, "Invalid LexEntryRef should be be removed from 'a'");
3943
Assert.AreEqual(0, b.EntryRefsOS.Count, "Invalid LexEntryRef should be be removed from 'b'");
4044
Assert.AreEqual(0, c.EntryRefsOS.Count, "Invalid LexEntryRef should be be removed from 'c'");
4145
Assert.AreEqual(0, d.EntryRefsOS.Count, "'d' should never have had any LexEntryRef objects");
4246
Assert.AreEqual(1, ab.EntryRefsOS.Count, "'ab' should have a single LexEntryRef");
4347
Assert.AreEqual(1, ac.EntryRefsOS.Count, "'ac' should have a single LexEntryRef");
4448
Assert.AreEqual(1, abcd.EntryRefsOS.Count, "'abcd' should have a single LexEntryRef");
45-
Assert.AreEqual(6, breaker.Count, "There should have been 6 LexEntryRef objects to process for this test");
46-
Assert.AreEqual(5, breaker.Circular, "There should have been 5 circular references fixed");
47-
Assert.DoesNotThrow(() => breaker.Process(Cache), "The BreakCircularRefs.Process(cache) method still does not throw an exception");
49+
Assert.AreEqual(6, count, "There should have been 6 LexEntryRef objects to process for this test");
50+
Assert.AreEqual(5, circular, "There should have been 5 circular references fixed");
51+
52+
// SUT
53+
Assert.DoesNotThrow(() => CircularRefBreakerService.ReferenceBreaker(Cache, out count, out circular, out _), "The CircularRefBreakerService.ReferenceBreaker method still does not throw an exception");
54+
55+
// Verify
4856
Assert.AreEqual(0, a.EntryRefsOS.Count, "'a' should still not have any LexEntryRef objects");
4957
Assert.AreEqual(0, b.EntryRefsOS.Count, "'b' should still not have any LexEntryRef objects");
5058
Assert.AreEqual(0, c.EntryRefsOS.Count, "'c' should still not have any LexEntryRef objects");
5159
Assert.AreEqual(0, d.EntryRefsOS.Count, "'d' should still not have any LexEntryRef objects");
5260
Assert.AreEqual(1, ab.EntryRefsOS.Count, "'ab' should still have a single LexEntryRef");
5361
Assert.AreEqual(1, ac.EntryRefsOS.Count, "'ac' should still have a single LexEntryRef");
5462
Assert.AreEqual(1, abcd.EntryRefsOS.Count, "'abcd' should still have a single LexEntryRef");
55-
Assert.AreEqual(3, breaker.Count, "There should have been 3 LexEntryRef objects to process for this test");
56-
Assert.AreEqual(0, breaker.Circular, "There should have been 0 circular references fixed");
63+
Assert.AreEqual(3, count, "There should have been 3 LexEntryRef objects to process for this test");
64+
Assert.AreEqual(0, circular, "There should have been 0 circular references fixed");
5765
}
5866
}
5967
}

Src/FwUtilsTests/FwUtilsTests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,10 @@
212212
</Reference>
213213
</ItemGroup>
214214
<ItemGroup>
215+
<Compile Include="CircularReferenceBreakerTests.cs" />
215216
<Compile Include="FontHeightAdjusterTests.cs" />
217+
<Compile Include="ManagedLgIcuCollatorTests.cs" />
218+
<Compile Include="ReplacePOSGuidsWithGoldEticGuidsTests.cs" />
216219
<Compile Include="InterfacesTests.cs" />
217220
<Compile Include="IVwCacheDaTests.cs" />
218221
<Compile Include="LcmExtensionsTests.cs" />
@@ -221,6 +224,7 @@
221224
<DesignTime>True</DesignTime>
222225
<DependentUpon>Resources.resx</DependentUpon>
223226
</Compile>
227+
<Compile Include="SortReversalSubEntriesInPlaceTests.cs" />
224228
<Compile Include="StringTableTests.cs" />
225229
<Compile Include="TempSFFileMaker.cs" />
226230
<Compile Include="TempSFFileMakerTests.cs" />

0 commit comments

Comments
 (0)