Applied lining in word with tab stops, it breaks the words for custom list items and adds extra space for the line item beneath/child of the custom line item

Applied lining in word with tab stops it works fine, but when the file has custom list items it was breaking the words

thus had applied following solution to fix

Document doc = new Document("C:\\Temp\\Final_linedDoc.docx");
for(Paragraph p : (Iterable<Paragraph>)doc.getChildNodes(NodeType.PARAGRAPH, true))
{
    if(p.isListItem())
        p.getListFormat().getListLevel().setTrailingCharacter(ListTrailingCharacter.SPACE);
}
doc.save("C:\\Temp\\out.docx");

although after applying this there was another issue introduced as adding extra space for the list items as below

to check if the trailing space was causing issue, I have changed the above solution and replaced with following code to add tabstops

Document doc = new Document("C:\\Temp\\Final_linedDoc.docx");
for(Paragraph p : (Iterable<Paragraph>)doc.getChildNodes(NodeType.PARAGRAPH, true)) {
    if (p.isListItem()) {
        p.getParagraphFormat().getTabStops().add(doc.getDefaultTabStop(), TabAlignment.LEFT, TabLeader.NONE);
        p.getParagraphFormat().getTabStops().add(doc.getDefaultTabStop() * 2, TabAlignment.LEFT, TabLeader.NONE);
        p.getParagraphFormat().getTabStops().add(doc.getDefaultTabStop() * 3, TabAlignment.LEFT, TabLeader.NONE);
    }
}
doc.save("C:\\Temp\\out_tab.docx");

Even with this solution the additional space is still available.

here is the Original document without lining
T-1-Original-Document-1.en.docx (21.4 KB)
Document without any solution after applying lining with word breaking -
T-1-Original-Document-1.nl.en Minuut (1)-With-Word-Break.docx (24.8 KB)

Document after lining with trailing space solution -
T-1-Original-Document-1.nl.en Minuut (2)-Space-Trailing-Solution.docx (24.8 KB)

Document after lining with adding additional tab stop solution -
T-1-Original-Document-1.en Minuut - with-extra-tab-stop-solution.docx (24.8 KB)

Thus even with either additional tab stop or space trailing solution the extra space is added. so we need a combined solution which doesn’t break the word and doesn’t add extra space either.

We are using a license version with library aspose-words:21.2:jdk17

@nobilex As I can see the problem occurs in the document without applying any workarounds. So the problem is caused by your mechanism that adds the lines, and not by the applied workaround.

Hello @alexey.noskov I am sharing the code snippet and two files that are mostly used in our app for lining one is with custom line items (custom ordered number list ) and other is with nested tables.

I have also added the space trailing code which was applied for ordered number list.
Can you suggest what changes we should make so that our lining in ordered number also works fine?

Thanks
Docx_Aligment_Issue.zip (8.6 MB)
This was original issue when ordered number list was used and lining was applied it was breaking the words.


After applying the space trailing solution - extra space is showing.

So need a fix for lining list items without extra space and still not breaking the words or lines going outside the nested tables [if this is used in the nested table structure]

Hope this code snippet can help us to achieve the solution

@nobilex Please try using the following solution:

Document doc = new Document("C:\\Temp\\Doc-Type-2.docx");
DocumentBuilder builder = new DocumentBuilder(doc);

// Split all Run nodes to make them not more than one word.
doc.getRange().replace(Pattern.compile("[ ]+"), " ",);
doc.getRange().replace(Pattern.compile("-"), "-");

// Wrap all runs in the paragraph with bookmarks to make it possible to work with LayoutCollector and LayoutEnumerator
Node[] runs = doc.getChildNodes(NodeType.RUN, true).toArray();
int bkIndex = 0;
for (Node r : runs)
{
    // LayoutCollector and LayoutEnumerator does not work with nodes in header/footer or in textboxes.
    if (r.getAncestor(NodeType.HEADER_FOOTER) != null || r.getAncestor(NodeType.SHAPE) != null)
        continue;

    String bkName = "_r" + bkIndex;
    r.getParentNode().insertBefore(new BookmarkStart(doc, bkName), r);
    r.getParentNode().insertAfter(new BookmarkEnd(doc, bkName), r);
    bkIndex++;
}

// Now we can use collector and enumerator to determine where line breaks.
LayoutCollector collector = new LayoutCollector(doc);
LayoutEnumerator enumerator = new LayoutEnumerator(doc);

Object currentLine = null;
String prevBookmarkName = "";
for (Paragraph p : (Iterable<Paragraph>)doc.getChildNodes(NodeType.PARAGRAPH, true))
{

    // Skip right aligned paragraphs.
    if (p.getParagraphFormat().getAlignment() == ParagraphAlignment.RIGHT)
        continue;

    TabStopCollection tabStops = p.getParagraphFormat().getTabStops();
    // Apply workaround:
    if (p.isListItem())
    {
        // Calculate max tab stop position that the paragraph already have.
        double maxTabStopPosition = 0;
        for (int i = 0; i < tabStops.getCount(); i++)
            maxTabStopPosition = Math.max(maxTabStopPosition, tabStops.get(i).getPosition());
        maxTabStopPosition = Math.max(maxTabStopPosition, p.getListFormat().getListLevel().getTabPosition());
        maxTabStopPosition = Math.max(maxTabStopPosition, p.getListFormat().getListLevel().getTextPosition());
        // Add additional tab stops.
        for (int i = 0; i < 4; i++)
        {
            double position = doc.getDefaultTabStop() * i;

            if (position > maxTabStopPosition)
                tabStops.add(position, TabAlignment.LEFT, TabLeader.NONE);
        }
    }

    // Add line tab stop.
    PageSetup ps = p.getParentSection().getPageSetup();
    double rightMarginPos = ps.getPageWidth() - ps.getRightMargin() - ps.getLeftMargin();
    tabStops.add(rightMarginPos + 0.0, TabAlignment.LEFT, TabLeader.LINE);

    for (Bookmark bk : p.getRange().getBookmarks())
    {
        if (!bk.getName().startsWith("_r"))
            continue;

        enumerator.setCurrent(collector.getEntity(bk.getBookmarkStart()));
        while (enumerator.getType() != LayoutEntityType.LINE)
            enumerator.moveParent();

        if (currentLine != enumerator.getCurrent())
        {
            if (!prevBookmarkName.equals(""))
            {
                builder.moveToBookmark(prevBookmarkName, false, false);
                builder.write("\t");
                if (bk.getBookmarkStart().getParentNode() == builder.getCurrentParagraph())
                    builder.insertBreak(BreakType.LINE_BREAK);
            }
            currentLine = enumerator.getCurrent();
        }
        prevBookmarkName = bk.getName();
    }
}

// Remove temporary bookmarks.
for (Bookmark bk : doc.getRange().getBookmarks())
{
    if (bk.getName().startsWith("_r"))
        bk.remove();
}

doc.save("C:\\Temp\\out.docx");

I have used the workaround with tabs, but improved it by calculating the maximum tab position that the paragraph already has.

Hi @alexey.noskov I tried applying the lining to the document, but it fails for many scenarios for our requirement
Basic requirement for adding lining to our document is that we need to add lining to document so that there is no white space available in the deed.
Here is the comparison between new output after the code change provided by you and before with original code snippet shared earlier.

Let me know if you need more details from our end. Specific to lines where there are long line and it is wrapped to next line or ends just before the page width, etc. For other points I believe we can use existing code. so I believe for list items following piece is working but for one specific items in the list item’s paragraph as below keyword is no line is there. so want understand this logic of calculating the position, in loop is only 4 times.


Can you elaborate on following part of code: specific where position is calculated in the loop only 4 times, any reason why it is 4 times?

  double position = doc.getDefaultTabStop() * i;

 // Apply workaround:
    if (p.isListItem())
    {
        // Calculate max tab stop position that the paragraph already have.
        double maxTabStopPosition = 0;
        for (int i = 0; i < tabStops.getCount(); i++)
            maxTabStopPosition = Math.max(maxTabStopPosition, tabStops.get(i).getPosition());
        maxTabStopPosition = Math.max(maxTabStopPosition, p.getListFormat().getListLevel().getTabPosition());
        maxTabStopPosition = Math.max(maxTabStopPosition, p.getListFormat().getListLevel().getTextPosition());
        // Add additional tab stops.
        for (int i = 0; i < 4; i++)
        {
            double position = doc.getDefaultTabStop() * i;

            if (position > maxTabStopPosition)
                tabStops.add(position, TabAlignment.LEFT, TabLeader.NONE);
        }
    }

@nobilex The code above was provided to demonstrate the technique. You can use your old code to add lines or modify the provided one.

The value is experimental. I am afraid there is no silver bullet solution.

1 Like

We tried applying a solution, but the with this sample code that we have it somehow treats two listItems differently. for one the additional space is no longer there for list items of 1.1 but then for ListVal1. listItem why the tab with line is added before the text and not for 1.1 list item, want to understand the gap between two different behaviour for the listitem only.
sharing the code snippet and sample original document, lined document as well.

CodeSample.zip (47.8 KB)

@nobilex The problem is with tab size and I am afraid there is no silver bullet solution. Actual position of ListVal1. label is on the right from the default tab position, so the next tab is used, i.e. tab with the line filling. 1.1 list label position is on the left from the default tab position, so default tab is used first.