Skip to content

Commit

Permalink
[API] LT-8457: Sort References Properly
Browse files Browse the repository at this point in the history
* Add IStTxtPara.ReferenceForSorting(ISegment, int) to
 compute a computer-sortable reference string

Part of https://jira.sil.org/browse/LT-8457
  • Loading branch information
papeh committed Mar 25, 2022
1 parent f955c06 commit 73cf047
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 6 deletions.
7 changes: 7 additions & 0 deletions src/SIL.LCModel/DomainImpl/ScrTxtPara.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2136,6 +2136,13 @@ public override ITsString Reference(ISegment seg, int ich)
}
return Cache.MakeUserTss("unknown"); // should never happen, I think?
}

/// <inheritdoc/>
public override ITsString ReferenceForSorting(ISegment seg, int ich)
{
throw new NotImplementedException();
}

/// ------------------------------------------------------------------------------------
/// <summary>
/// Gets the footnote sequence.
Expand Down
47 changes: 47 additions & 0 deletions src/SIL.LCModel/DomainImpl/StTxtPara.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,53 @@ public virtual ITsString Reference(ISegment seg, int ich)
return bldr.GetString();
}

/// <inheritdoc/>
public virtual ITsString ReferenceForSorting(ISegment seg, int ich)
{
if (!(Owner is IStText stText))
{
return TsStringUtils.EmptyString(Cache.DefaultUserWs);
}

ITsString tssName = null;
// TODO: Abbr
//var fUsingAbbr = false;
//if (stText.Owner is IText text)
//{
// tssName = text.Abbreviation.BestVernacularAnalysisAlternative;
// if (!TsStringUtils.IsNullOrEmpty(tssName))
// {
// fUsingAbbr = true;
// }
//}
tssName = stText.Title.BestVernacularAnalysisAlternative;
var bldr = tssName.GetBldr();
// TODO: Props?
var props = bldr.get_Properties(0);
// TODO: *** check?

bldr.Append(" ", props);

// Insert paragraph number.
int iPara = stText.ParagraphsOS.IndexOf(this) + 1;
bldr.Replace(bldr.Length, bldr.Length, iPara.ToString(), props);

// And a period...
bldr.Replace(bldr.Length, bldr.Length, ".", props);

// And now the segment number
int iseg = SegmentsOS.IndexOf(seg) + 1;
bldr.Replace(bldr.Length, bldr.Length, iseg.ToString(), props);
return bldr.GetString();
}

/// <summary>Pads the given int with zeroes to the max length of an int</summary>
protected internal static string ZeroPadForStringComparison(int i)
{
// because int.MaxValue.ToString().Length is 10
return i.ToString("D10");
}

/// ------------------------------------------------------------------------------------
/// <summary>
/// Finds the ORC of the specified picture and deletes it from the paragraph and any
Expand Down
22 changes: 16 additions & 6 deletions src/SIL.LCModel/InterfaceAdditions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3136,15 +3136,25 @@ IStTxtPara PreviousParagraph
List<IConstChartWordGroup> GetChartCellRefs();

/// ------------------------------------------------------------------------------------
/// <summary>
/// Return a Reference (e.g., Scripture reference, or text abbreviation/para #/sentence#) for the specified character
/// position (in the whole paragraph), which is assumed to belong to the specified segment.
/// (For now, ich is not actually used, but it may become important if we decide not to split segements for
/// verse numbers.)
/// </summary>
/// <summary>
/// Return a Reference (e.g., Scripture reference, or text abbreviation+para #+sentence #) for the specified character
/// position (in the whole paragraph), which is assumed to belong to the specified segment.
/// (For now, ich is not actually used, but it may become important if we decide not to split segments for
/// verse numbers.)
/// </summary>
/// ------------------------------------------------------------------------------------
ITsString Reference(ISegment seg, int ich);

/// ------------------------------------------------------------------------------------
/// <summary>
/// Return a Reference (e.g., Scripture reference, or text abbreviation+para #+sentence #) for the specified character
/// position (in the whole paragraph), which is assumed to belong to the specified segment.
/// To allow greater accuracy and precision in sorting, numbers are zero-padded to the length of <see cref="int.MaxValue"/> and ich
/// is included at the end.
/// </summary>
/// ------------------------------------------------------------------------------------
ITsString ReferenceForSorting(ISegment seg, int ich);

/// ------------------------------------------------------------------------------------
/// <summary>
/// Splits the paragraph at the specified character index.
Expand Down
32 changes: 32 additions & 0 deletions tests/SIL.LCModel.Tests/DomainImpl/ScrTxtParaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,38 @@ public void Reference()
// segments in the previous section.
Assert.That(para3.Reference(v2seg4, v2seg4.BeginOffset + 1).Text, Is.EqualTo("MAT 1:2"));
}

/// <summary>
/// Test the ReferenceForSorting method for Scripture paragraphs.
/// </summary>
[Test]
public void ReferenceForSorting()
{
AddDataToMatthew();
var para1 = (IStTxtPara) m_book.SectionsOS[1].ContentOA.ParagraphsOS[0]; // Actually ScrTxtPara
var seg = para1.SegmentsOS[1]; // first content ref, after the chapter and verse number stuff.
Assert.That(para1.ReferenceForSorting(seg, seg.BeginOffset + 1).Text, Is.EqualTo("41_MAT 0000000001:0000000001"));
AddRunToMockedPara(para1, "Verse two second sentence.", null);
var v2seg1 = para1.SegmentsOS[3]; // first segment of two-sentence verse
Assert.That(para1.ReferenceForSorting(v2seg1, v2seg1.BeginOffset + 1).Text, Is.EqualTo("41_MAT 0000000001:0000000002a"));
var v2seg2 = para1.SegmentsOS[4]; // first segment of two-sentence verse
Assert.That(para1.ReferenceForSorting(v2seg2, v2seg2.BeginOffset + 1).Text, Is.EqualTo("41_MAT 0000000001:0000000002b"));
IStTxtPara para2 = AddParaToMockedSectionContent((IScrSection)para1.Owner.Owner, ScrStyleNames.NormalParagraph);
AddRunToMockedPara(para2, "Verse 2 seg 3", null);
var v2seg3 = para2.SegmentsOS[0]; // third segment of three-sentence verse split over two paragraphs.
Assert.That(para2.ReferenceForSorting(v2seg3, v2seg3.BeginOffset + 1).Text, Is.EqualTo("41_MAT 0000000001:0000000002c"));
var newSection = AddSectionToMockedBook(m_book);
IStTxtPara para3 = AddParaToMockedSectionContent(newSection, ScrStyleNames.NormalParagraph);
AddRunToMockedPara(para3, "Verse 2 seg 4", null);
var v2seg4 = para3.SegmentsOS[0]; // fourth segment of four-sentence verse split over two sections(!).
// JohnT: arguably this should give 41_MAT 0000000001:0000000002d. The current implementation does not detect the
// segments in the previous section.
Assert.That(para3.ReferenceForSorting(v2seg4, v2seg4.BeginOffset + 1).Text, Is.EqualTo("41_MAT 0000000001:0000000002"));

var scrBook1Samuel = CreateBookData(9, "1 Samuel");
var scrBookSusanna = CreateBookData(76, "Susanna");
// TODO (Hasso) 2022.03: Enoch or some other >100 book
}
#endregion

#region Moving paragraphs between books tests
Expand Down
27 changes: 27 additions & 0 deletions tests/SIL.LCModel.Tests/DomainImpl/StTxtParaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,33 @@ protected override void CreateTestData()
}
#endregion

#region ReferenceForSorting method tests
[Test]
public void ReferenceForSorting()
{
var para1 = AddParaToMockedText(m_stText, null);
AddRunToMockedPara(para1, "This text is indexed. It is also segmented.", null);

var para2 = AddParaToMockedText(m_stText, null);
AddRunToMockedPara(para2, "This is the second paragraph. It is runny. It has three sentences.", null);

// SUT
var result = para1.ReferenceForSorting(para1.SegmentsOS[0], 10);
Assert.That(result, Is.EqualTo("My Interlinear Text 0000000001.0000000001 0000000010"));
result = para1.ReferenceForSorting(para1.SegmentsOS[1], 25);
Assert.That(result, Is.EqualTo("My Interlinear Text 0000000001.0000000002 0000000025"));
result = para1.ReferenceForSorting(para2.SegmentsOS[0], 5);
Assert.That(result, Is.EqualTo("My Interlinear Text 0000000002.0000000001 0000000005"));
}

[TestCase(0, ExpectedResult = "0000000000")]
[TestCase(1, ExpectedResult = "0000000001")]
[TestCase(12, ExpectedResult = "0000000012")]
[TestCase(512, ExpectedResult = "0000000512")]
[TestCase(int.MaxValue, ExpectedResult = "2147483647")]
public string ZeroPadForStringComparison(int i) => StTxtPara.ZeroPadForStringComparison(i);
#endregion ReferenceForSorting method tests

#region ReplaceTextRange method tests
///--------------------------------------------------------------------------------------
/// <summary>
Expand Down

0 comments on commit 73cf047

Please sign in to comment.