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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,40 @@ public virtual void IncorrectChildTypeDoesntThrowTest() {
}
}

[NUnit.Framework.Test]
public virtual void NestedListDirectChildDoesNotThrowOnLayoutTest() {
using (Document document = CreateDummyDocument()) {
List nestedList = new List(ListNumberingType.ENGLISH_LOWER).Add("nested-1").Add("nested-2");
List parentList = new List(ListNumberingType.DECIMAL);
parentList.Add(new ListItem("parent-1"));
parentList.Add(nestedList);
parentList.Add(new ListItem("parent-2"));
NUnit.Framework.Assert.DoesNotThrow(() => document.Add(parentList));
}
}

[NUnit.Framework.Test]
public virtual void NestedListIndentAppliedToDirectNestedListRendererTest() {
List nestedList = new List(ListNumberingType.ENGLISH_LOWER).SetMarginLeft(7).Add("nested-1");
List parentList = new List(ListNumberingType.DECIMAL).SetListIndent(15);
parentList.Add(new ListItem("parent-1"));
parentList.Add(nestedList);
parentList.Add(new ListItem("parent-2"));
ListRenderer parentRenderer = (ListRenderer)parentList.CreateRendererSubTree();
using (Document document = CreateDummyDocument()) {
parentRenderer.SetParent(document.GetRenderer());
LayoutResult result = parentRenderer.Layout(CreateLayoutContext(400, 400));
NUnit.Framework.Assert.AreNotEqual(LayoutResult.NOTHING, result.GetStatus());
}
NUnit.Framework.Assert.AreEqual(3, parentRenderer.GetChildRenderers().Count);
IRenderer nestedRenderer = parentRenderer.GetChildRenderers()[1];
NUnit.Framework.Assert.IsTrue(nestedRenderer is ListRenderer);
UnitValue nestedMarginLeft = nestedRenderer.GetProperty<UnitValue>(Property.MARGIN_LEFT);
NUnit.Framework.Assert.IsNotNull(nestedMarginLeft);
NUnit.Framework.Assert.IsTrue(nestedMarginLeft.IsPointValue());
NUnit.Framework.Assert.AreEqual(22f, nestedMarginLeft.GetValue(), 0.0001f);
}

private static ListRenderer CreateInsideListRenderer() {
List list = new List();
list.SetListSymbol(new iText.Layout.Element.Text("*"));
Expand Down
42 changes: 42 additions & 0 deletions itext/itext.layout/itext/layout/element/List.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,30 @@ public virtual iText.Layout.Element.List Add(ListItem listItem) {
return this;
}

/// <summary>
/// Adds a new
/// <see cref="iText.Layout.Element.List"/>
/// (nested list) to the bottom of the List.
/// </summary>
/// <param name="list">a nested list</param>
/// <returns>this list.</returns>
public virtual iText.Layout.Element.List Add(iText.Layout.Element.List list) {
childElements.Add(list);
return this;
}

/// <summary>
/// Adds a new
/// <see cref="IBlockElement"/>
/// to the bottom of the List.
/// </summary>
/// <param name="element">a block element (e.g. Paragraph)</param>
/// <returns>this list.</returns>
public virtual iText.Layout.Element.List Add(IBlockElement element) {
childElements.Add(element);
return this;
}

/// <summary>
/// Adds a new
/// <see cref="ListItem"/>
Expand Down Expand Up @@ -234,6 +258,24 @@ public virtual iText.Layout.Element.List SetSymbolIndent(float symbolIndent) {
return this;
}

/// <summary>
/// Gets the indent (left margin) applied to nested lists that are direct children of this list.
/// </summary>
/// <returns>the nested list indent as a <c>float</c>, or <c>null</c> if not set.</returns>
public virtual float? GetListIndent() {
return this.GetProperty<float?>(Property.LIST_INDENT);
}

/// <summary>
/// Sets the indent (left margin) applied to nested lists that are direct children of this list.
/// </summary>
/// <param name="listIndent">the indent offset for nested lists.</param>
/// <returns>this list.</returns>
public virtual iText.Layout.Element.List SetListIndent(float listIndent) {
SetProperty(Property.LIST_INDENT, listIndent);
return this;
}

/// <summary>
/// Gets the piece of text that is added after the
/// <see cref="ListItem"/>
Expand Down
5 changes: 5 additions & 0 deletions itext/itext.layout/itext/layout/properties/Property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,11 @@ public sealed class Property {

private const int MAX_INHERITED_PROPERTY_ID = 165;

/// <summary>
/// The indent (left margin) applied to nested lists that are direct children of a parent list.
/// </summary>
public const int LIST_INDENT = 166;

static Property() {
INHERITED_PROPERTIES = new bool[MAX_INHERITED_PROPERTY_ID + 1];
INHERITED_PROPERTIES[iText.Layout.Properties.Property.APPEARANCE_STREAM_LAYOUT] = true;
Expand Down
33 changes: 32 additions & 1 deletion itext/itext.layout/itext/layout/renderer/ListRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,11 @@ private LayoutResult CorrectListSplitting(IRenderer splitRenderer, IRenderer ove
// Notice that placed item is a son of the first ListItemRenderer (otherwise there would be now
// FORCED_PLACEMENT applied)
IRenderer firstListItemRenderer = splitRenderer.GetChildRenderers()[0];
if (!(firstListItemRenderer is ListItemRenderer) && firstListItemRenderer is BlockRenderer) {
// If the first child is not a ListItemRenderer, fall back to default behaviour
return new LayoutResult(null == overflowRenderer ? LayoutResult.FULL : LayoutResult.PARTIAL, occupiedArea,
splitRenderer, overflowRenderer, this);
}
iText.Layout.Renderer.ListRenderer newOverflowRenderer = (iText.Layout.Renderer.ListRenderer)CreateOverflowRenderer
(LayoutResult.PARTIAL);
newOverflowRenderer.DeleteOwnProperty(Property.FORCED_PLACEMENT);
Expand Down Expand Up @@ -366,6 +371,11 @@ private LayoutResult InitializeListSymbols(LayoutContext layoutContext) {
IList<IRenderer> symbolRenderers = new List<IRenderer>();
int listItemNum = (int)this.GetProperty<int?>(Property.LIST_START, 1);
foreach (IRenderer renderer in childRenderers) {
if (!(renderer is ListItemRenderer) && (renderer is ParagraphRenderer || renderer is iText.Layout.Renderer.ListRenderer)) {
// Non-ListItem children (e.g. Paragraph, nested List) do not get list symbols
symbolRenderers.Add(null);
continue;
}
renderer.SetParent(this);
listItemNum = (renderer.GetProperty<int?>(Property.LIST_SYMBOL_ORDINAL_VALUE) != null) ? (int)renderer.GetProperty
<int?>(Property.LIST_SYMBOL_ORDINAL_VALUE) : listItemNum;
Expand Down Expand Up @@ -406,8 +416,30 @@ private LayoutResult InitializeListSymbols(LayoutContext layoutContext) {
}
}
float? symbolIndent = this.GetPropertyAsFloat(Property.LIST_SYMBOL_INDENT);
float? nestedListIndent = this.GetPropertyAsFloat(Property.LIST_INDENT);
listItemNum = 0;
foreach (IRenderer childRenderer in childRenderers) {
IRenderer symbolRenderer = symbolRenderers[listItemNum++];
if (!(childRenderer is ListItemRenderer)) {
// Non-ListItem children (e.g. Paragraph, nested List) do not get list symbols
// Apply indent to nested lists so they are visually offset from the parent list
if (childRenderer is iText.Layout.Renderer.ListRenderer) {
if (nestedListIndent != null) {
bool isRtlNested = BaseDirection.RIGHT_TO_LEFT == childRenderer.GetProperty<BaseDirection?>(Property.BASE_DIRECTION);
int nestedMarginToSet = isRtlNested ? Property.MARGIN_RIGHT : Property.MARGIN_LEFT;
UnitValue existingMargin = childRenderer.GetProperty<UnitValue>(nestedMarginToSet, UnitValue.CreatePointValue(0f));
float nestedCalculatedMargin = existingMargin.IsPointValue() ? existingMargin.GetValue() : 0f;
nestedCalculatedMargin += (float)nestedListIndent;
childRenderer.SetProperty(nestedMarginToSet, UnitValue.CreatePointValue(nestedCalculatedMargin));
}
continue;
}
else if (childRenderer is ParagraphRenderer) {
// Paragraphs - no list symbol
continue;
}
// Other non-ListItem types (e.g. DivRenderer) will fall through to the throw below
}
// Symbol indent's value should be summed with the margin's value
bool isRtl = BaseDirection.RIGHT_TO_LEFT == childRenderer.GetProperty<BaseDirection?>(Property.BASE_DIRECTION
);
Expand All @@ -426,7 +458,6 @@ private LayoutResult InitializeListSymbols(LayoutContext layoutContext) {
calculatedMargin += maxSymbolWidth + (float)(symbolIndent != null ? symbolIndent : 0f);
}
childRenderer.SetProperty(marginToSet, UnitValue.CreatePointValue(calculatedMargin));
IRenderer symbolRenderer = symbolRenderers[listItemNum++];
if (childRenderer is ListItemRenderer) {
((ListItemRenderer)childRenderer).AddSymbolRenderer(symbolRenderer, maxSymbolWidth);
}
Expand Down