Skip to content

Commit

Permalink
Fix LT-21870 and LT-21872 and boundary markers (#311)
Browse files Browse the repository at this point in the history
* Fix LT-21872 (Import Phonology crashes) and boundary marker problem
* Add DeletePhonology, fix LT-21870 (Import phonology crash)
* Fix duplicate GUID problem
  • Loading branch information
jtmaxwell3 authored Aug 26, 2024
1 parent 81f2eae commit aa682dd
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 41 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ artifacts/
lib/downloads/
.idea/
.vs/
*.bak

src/SIL.LCModel.Core/KernelInterfaces/Kernel.cs
src/SIL.LCModel/Infrastructure/Impl/Generated*.cs
Expand Down
17 changes: 16 additions & 1 deletion src/SIL.LCModel/Application/ApplicationServices/XmlImportData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,18 @@ private void ReadXmlObject(XmlReader xrdr, FieldInfo fi, ICmObject objToUse)
cmo = m_cache.LangProject.LexDbOA;
Debug.Assert(cmo != null);
break;
case "PhBdryMarker":
IPhBdryMarkerRepository repository = m_cache.ServiceLocator.GetInstance<IPhBdryMarkerRepository>();
IPhBdryMarkerFactory factory = m_cache.ServiceLocator.GetInstance<IPhBdryMarkerFactory>();
Guid guid = Guid.Parse(xrdr.GetAttribute("Guid"));
IPhBdryMarker marker;
if (repository.TryGetObject(guid, out marker))
cmo = marker;
else
cmo = factory.Create(guid, (IPhPhonemeSet)fi.Owner);
// Remove the default code added by PhTerminalUnit.SetDefaultValuesAfterInit in OverridesLing_Lex.
(cmo as PhBdryMarker).CodesOS.Clear();
break;
case "PhPhonData":
cmo = m_cache.LangProject.PhonologicalDataOA;
Debug.Assert(cmo != null);
Expand All @@ -1003,6 +1015,10 @@ private void ReadXmlObject(XmlReader xrdr, FieldInfo fi, ICmObject objToUse)
cmo = m_cache.LangProject.PhFeatureSystemOA;
Debug.Assert(cmo != null);
break;
case "PhPhonemeSet":
cmo = m_cache.LangProject.PhonologicalDataOA.GetPhonemeSet();
Debug.Assert(cmo != null);
break;
default:
int clid = m_mdc.GetClassId(sClass);
if (fi != null)
Expand Down Expand Up @@ -1048,7 +1064,6 @@ private void ReadXmlObject(XmlReader xrdr, FieldInfo fi, ICmObject objToUse)
cmo = m_repoCmObject.GetObject(hvo);
// Remove the default code added by PhTerminalUnit.SetDefaultValuesAfterInit in OverridesLing_Lex.
(cmo as PhPhoneme)?.CodesOS.Clear();
(cmo as PhBdryMarker)?.CodesOS.Clear();
// Remove default values.
(cmo as PhRegularRule)?.RightHandSidesOS.Clear();
}
Expand Down
15 changes: 15 additions & 0 deletions src/SIL.LCModel/DomainImpl/OverridesLing_Lex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6858,6 +6858,21 @@ public List<string> AllPhonemes()
return phReps;
}

/// <summary>
/// Get the PhonemeSet.
/// Hides the fact that multiple PhonemeSets used to be allowed.
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public IPhPhonemeSet GetPhonemeSet()
{
if (this.PhonemeSetsOS.Count == 0)
throw new Exception("Missing PhonemeSet.");
if (this.PhonemeSetsOS.Count > 1)
throw new Exception("Too many PhonemeSets.");
return this.PhonemeSetsOS[0];
}

/// <summary>
/// Return the list of abbreviations for all the natural classes defined, each in the
/// default analysis writing system.
Expand Down
16 changes: 10 additions & 6 deletions src/SIL.LCModel/DomainServices/M3ModelExportServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -591,12 +591,16 @@ select ExportItemAsReference(constraint, constraints.IndexOf(constraint), "Featu
new XAttribute("Id", rhs.Hvo),
new XElement("StrucChange", from structChange in rhs.StrucChangeOS
select ExportContext(structChange)),
new XElement("InputPOSes", from pos in rhs.InputPOSesRC
select ExportItemAsReference(pos, "RequiredPOS")),
new XElement("ReqRuleFeats", from rrf in rhs.ReqRuleFeatsRC
select ExportItemAsReference(rrf, "RuleFeat")),
new XElement("ExclRuleFeats", from erf in rhs.ExclRuleFeatsRC
select ExportItemAsReference(erf, "RuleFeat")),
// RuleFeats and POS are not part of the phonology.
phonology ? null
: new XElement("InputPOSes", from pos in rhs.InputPOSesRC
select ExportItemAsReference(pos, "RequiredPOS")),
phonology ? null
: new XElement("ReqRuleFeats", from rrf in rhs.ReqRuleFeatsRC
select ExportItemAsReference(rrf, "RuleFeat")),
phonology ? null
: new XElement("ExclRuleFeats", from erf in rhs.ExclRuleFeatsRC
select ExportItemAsReference(erf, "RuleFeat")),
new XElement("LeftContext", ExportContext(rhs.LeftContextOA)),
new XElement("RightContext", ExportContext(rhs.RightContextOA)))));
break;
Expand Down
54 changes: 20 additions & 34 deletions src/SIL.LCModel/DomainServices/PhonologyServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using SIL.LCModel.Core.Text;
using SIL.LCModel.Infrastructure.Impl;
using static Icu.Normalization.Normalizer2;
using SIL.LCModel.Core.KernelInterfaces;

namespace SIL.LCModel.DomainServices
{
Expand Down Expand Up @@ -74,42 +75,27 @@ public void ImportPhonologyFromXml(TextReader rdr)
// () => AssignVernacularWritingSystemToDefaultPhPhonemes(Cache));
}

private void AssignVernacularWritingSystemToDefaultPhPhonemes(LcmCache cache)
/// <summary>
/// Clear PhonologicalData and Phonological Features.
/// Don't clear boundary markers.
/// </summary>
public void DeletePhonology()
{
// For all PhCodes in the default phoneme set, change the writing system from "en" to icuLocale
if (cache.LanguageProject.PhonologicalDataOA.PhonemeSetsOS.Count == 0)
return;
var phSet = cache.LanguageProject.PhonologicalDataOA.PhonemeSetsOS[0];
int wsVern = m_wsVernId == null
? cache.DefaultVernWs
: cache.ServiceLocator.WritingSystemManager.Get(m_wsVernId).Handle;
foreach (var phone in phSet.PhonemesOC)
{
foreach (var code in phone.CodesOS)
{

if (code.Representation.VernacularDefaultWritingSystem.Length == 0)
code.Representation.VernacularDefaultWritingSystem =
TsStringUtils.MakeString(code.Representation.UserDefaultWritingSystem.Text, wsVern);
}
if (phone.Name.VernacularDefaultWritingSystem.Length == 0)
phone.Name.VernacularDefaultWritingSystem =
TsStringUtils.MakeString(phone.Name.UserDefaultWritingSystem.Text, wsVern);
}
foreach (var mrkr in phSet.BoundaryMarkersOC)
NonUndoableUnitOfWorkHelper.Do(Cache.ServiceLocator.GetInstance<IActionHandler>(), () =>
{
foreach (var code in mrkr.CodesOS)
{
if (code.Representation.VernacularDefaultWritingSystem.Length == 0)
code.Representation.VernacularDefaultWritingSystem =
TsStringUtils.MakeString(code.Representation.UserDefaultWritingSystem.Text, wsVern);
}
if (mrkr.Name.VernacularDefaultWritingSystem.Length == 0)
mrkr.Name.VernacularDefaultWritingSystem =
TsStringUtils.MakeString(mrkr.Name.UserDefaultWritingSystem.Text, wsVern);
}
IPhPhonData phonData = Cache.LangProject.PhonologicalDataOA;
// Delete what is covered by ImportPhonology.
phonData.ContextsOS.Clear();
phonData.EnvironmentsOS.Clear();
phonData.FeatConstraintsOS.Clear();
phonData.NaturalClassesOS.Clear();
phonData.GetPhonemeSet().PhonemesOC.Clear();
// Don't clear phonData.GetPhonemeSet().BoundaryMarkersOC!
// They have GUIDs known to the code.
phonData.PhonRulesOS.Clear();
Cache.LanguageProject.PhFeatureSystemOA.TypesOC.Clear();
Cache.LanguageProject.PhFeatureSystemOA.FeaturesOC.Clear();
});
}


}
}
6 changes: 6 additions & 0 deletions src/SIL.LCModel/InterfaceAdditions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5626,6 +5626,12 @@ public partial interface IPhPhonData
/// </summary>
List<string> AllNaturalClassAbbrs();

/// <summary>
/// Get the PhonemeSet.
/// Hides the fact that the data structure used to allow more than one.
/// </summary>
IPhPhonemeSet GetPhonemeSet();

/// <summary>
/// Rebuild the list of PhonRuleFeats
/// </summary>
Expand Down
34 changes: 34 additions & 0 deletions tests/SIL.LCModel.Tests/DomainServices/PhonologyServicesTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ private void TestProject(string projectsDirectory, string dbFileName)
using (var cache = LcmCache.CreateCacheFromExistingData(projectId, "en", m_ui, m_lcmDirectories, new LcmSettings(),
new DummyProgressDlg()))
{
// Create PhonemeSet if necessary.
NonUndoableUnitOfWorkHelper.Do(m_cache.ActionHandlerAccessor, () =>
{
if (m_cache.LangProject.PhonologicalDataOA.PhonemeSetsOS.Count == 0)
{
var phonemeset = m_cache.ServiceLocator.GetInstance<IPhPhonemeSetFactory>().Create();
m_cache.LangProject.PhonologicalDataOA.PhonemeSetsOS.Add(phonemeset);
}
});
// Export project as XML.
var services = new PhonologyServices(cache);
XDocument xdoc = services.ExportPhonologyAsXml();
Expand All @@ -109,6 +118,7 @@ private void TestProject(string projectsDirectory, string dbFileName)
var vernWs = cache.ServiceLocator.WritingSystemManager.Get(cache.DefaultVernWs);
SetDefaultVernacularWritingSystem(m_cache, vernWs);
var services2 = new PhonologyServices(m_cache, vernWs.Id);
services2.DeletePhonology();
services2.ImportPhonologyFromXml(rdr);
xdoc2 = services2.ExportPhonologyAsXml();
}
Expand All @@ -125,15 +135,39 @@ private void TestXml(string xml, string vernWs)
{
m_cache.ServiceLocator.WritingSystems.DefaultVernacularWritingSystem =
m_cache.ServiceLocator.WritingSystemManager.Get(vernWs);
if (m_cache.LangProject.PhonologicalDataOA.PhonemeSetsOS.Count == 0)
{
var phonemeset = m_cache.ServiceLocator.GetInstance<IPhPhonemeSetFactory>().Create();
m_cache.LangProject.PhonologicalDataOA.PhonemeSetsOS.Add(phonemeset);
}
});
ILcmOwningSequence<IPhPhonemeSet> phonemeList = m_cache.LangProject.PhonologicalDataOA.PhonemeSetsOS;
IPhPhonemeSet phonemeSet = m_cache.LangProject.PhonologicalDataOA.GetPhonemeSet();
var services = new PhonologyServices(m_cache);
services.DeletePhonology();
using (var rdr = new StringReader(xml))
{
services.ImportPhonologyFromXml(rdr);
var xdoc2 = services.ExportPhonologyAsXml();
var xml2 = xdoc2.ToString();
TestXml(xdoc, xdoc2);
}
// Verify that the references to the PhonemeSet didn't change.
Assert.IsTrue(ReferenceEquals(phonemeList, m_cache.LangProject.PhonologicalDataOA.PhonemeSetsOS));
Assert.IsTrue(ReferenceEquals(phonemeSet, m_cache.LangProject.PhonologicalDataOA.GetPhonemeSet()));
// Verify that the boundary markers exist with the right GUIDs.
bool hasMorphBdry = false;
bool hasWordBdry = false;
foreach (var marker in m_cache.LangProject.PhonologicalDataOA.GetPhonemeSet().BoundaryMarkersOC)
{
if (marker.Guid == LangProjectTags.kguidPhRuleMorphBdry)
hasMorphBdry = true;
if (marker.Guid == LangProjectTags.kguidPhRuleWordBdry)
hasWordBdry = true;
}
Assert.IsTrue(hasMorphBdry);
Assert.IsTrue(hasWordBdry);
Assert.IsTrue(m_cache.LangProject.PhonologicalDataOA.GetPhonemeSet().BoundaryMarkersOC.Count == 2);
}

private void TestXml(XDocument xdoc, XDocument xdoc2)
Expand Down

0 comments on commit aa682dd

Please sign in to comment.