[Java][Word] Incorrect anchor point for TextBox objects

Hello,

I have some problem with the placement anchor of TextBox at the correct place in the document.

In the attachment, I added the current result of generation by library document, and my expected example.

anhor_test.zip (45.0 KB)

If I have a page filled with newline characters (documentBuilder.writeln())
this expects that when a TextBox is added, its anchor point will be in the same line as the upper left corner of the textbox.

If, on the other hand, adding a new object corresponds to the last paragraph each time, then I need information on how to determine the height of the paragraph with the default settings.

In the current situation, this causes the items contained in the TOC to be displayed in the wrong order.
Additionally, if both TextBox and FieldToc have an anchor in the same place then TOC does not detect text contained in TexBox (if it has Heading 1-9 style).

@aolo23,

You can first determine the height/top of Paragraph mark character and then insert Textbox with content at that position:

Document doc = new Document("C:\\temp\\anhor_test\\input.docx");

LayoutCollector collector = new LayoutCollector(doc);
LayoutEnumerator enumerator = new LayoutEnumerator(doc);

// Suppose you want to anchor a TextBox at a Paragraph around 4.34" height/top position
double top = 4.34 * 72; // 1 inch equals 72 points
Paragraph targetPara = null;
for (Paragraph para : doc.getFirstSection().getBody().getParagraphs()) {
    enumerator.setCurrent(collector.getEntity(para));
    if (enumerator.getRectangle().getY() < top) {
        continue;
    } else {
        targetPara = para;
        break;
    }
}

if (targetPara != null) {
    DocumentBuilder builder = new DocumentBuilder(doc);
    // move cursor to that Paragarph
    builder.moveTo(targetPara);

    Shape textBox = builder.insertShape(ShapeType.TEXT_BOX, (3.94 * 72), (0.64 * 72));
    textBox.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
    textBox.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
    textBox.setWrapType(WrapType.NONE);
    textBox.setTop(top);
    textBox.setLeft(doc.getFirstSection().getPageSetup().getLeftMargin() + 0);
}

doc.save("C:\\temp\\anhor_test\\awjava-21.2.docx");
1 Like

@awais.hafeez

Thank You for your example code which helps me to create some dynamic solution.
I write there again because I have a problem with setting italic property style for paragraphs in this way that italic should be also included as an entry in TOC.

Example code:

import com.aspose.words.Shape;
import com.aspose.words.*;

import java.awt.*;
import java.io.File;
import java.util.Random;

public class Example {

    public static void main(String[] args) throws Exception {
        insertTableOfContent();
    }

    public static void insertTableOfContent() {
        try {// 8.1.0.15
            Document doc = new Document();
            DocumentBuilder builder = new DocumentBuilder(doc);

            final Random random = new Random(System.currentTimeMillis());

            final Paragraph currentParagraph = builder.getCurrentParagraph();

            Shape shape = new Shape(builder.getDocument(), ShapeType.TEXT_BOX);
            shape.setWidth(200);
            shape.setHeight(150);
            shape.setLeft(50);
            shape.setTop(80);
            shape.setWrapType(WrapType.NONE);
            shape.setRelativeHorizontalPosition(RelativeHorizontalPosition.MARGIN);
            shape.setRelativeVerticalPosition(RelativeVerticalPosition.MARGIN);

            final Paragraph lastParagraph = new Paragraph(builder.getDocument());
            shape.appendChild(lastParagraph);
            Run run = new Run(builder.getDocument(), "TEST TOC");
            lastParagraph.appendChild(run);
            builder.insertNode(shape);
            builder.moveTo(lastParagraph);

            FieldToc currentGeneratedTOC = (FieldToc) builder.insertTableOfContents("\\h \\z \\u ");
            builder.moveToDocumentStart();
            
            for (int i = 1; i < 6; i++) {

                final Shape textBox = builder.insertShape(ShapeType.TEXT_BOX, RelativeHorizontalPosition.MARGIN,
                        10, RelativeVerticalPosition.MARGIN, 250 + 50 * i,
                        100, 50, WrapType.NONE);

                final Paragraph para = textBox.getLastParagraph();
                para.getParagraphFormat().setStyleIdentifier(i);
                para.getParagraphFormat().getStyle().getFont().setColor(new Color(random.nextInt(256),random.nextInt(256),random.nextInt(256)));
                para.appendChild(new Run(doc,"HEADING"+i));
                para.getParagraphFormat().getStyle().getFont().setItalic(true);
                textBox.setAnchorLocked(false);
            }
            currentGeneratedTOC.update();
            doc.updateFields();

            doc.save(System.getProperty("user.dir") + File.separator + "InsertATableOfContentsUsingHeadingStyles"+ random.nextInt(100000) +".docx");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

As you can see I call

currentGeneratedTOC.update();
doc.updateFields();

and non of them does not change the result of the document.

My expectation:
After calling this method I should have all entries in TOC with set italic property.
Ps: I know that to set a global style for TOC I can use TOC_1, TOC_2, …, but want to recreate the same behaviour of MSWord

@aolo23,

How can you fix Aspose.Words generated output (awjava-21.2.zip (7.7 KB)) by using MS Word? Please also ZIP and attach your expected DOCX file showing the desired output here for our reference. You can create this expected document manually by using MS Word. Please also list the complete steps that you performed in MS Word to create the expected document on your end.

Aspose_expected_toc.zip (21.7 KB)

Steps to recreate:

  1. Create an empty word file
  2. Create a few TextBoxes
  3. I each textbox add some text, add one of style Heading1,…,Heading9
  4. Again in each textbox select text and set italic style for the paragraph
  5. Create another textbox above the rest. Move the cursor inside the text box and generate a table of content (Reference tab in ms word)

I hope that it will help you.

@aolo23,

Please check the following Java code should apply italic formatting to some TOC entries:

public static void insertTableOfContent() {
    try {// 8.1.0.15
        Document doc = new Document();
        DocumentBuilder builder = new DocumentBuilder(doc);

        final Random random = new Random(System.currentTimeMillis());

        for (int i = 1; i < 6; i++) {
            final Shape textBox = builder.insertShape(ShapeType.TEXT_BOX, RelativeHorizontalPosition.MARGIN,
                    10, RelativeVerticalPosition.MARGIN, 250 + 50 * i,
                    100, 50, WrapType.NONE);

            final Paragraph para = textBox.getLastParagraph();
            para.getParagraphFormat().setStyleIdentifier(i);
            para.getParagraphFormat().getStyle().getFont().setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
            para.appendChild(new Run(doc, "HEADING" + i));

            for (Run runNodes : para.getRuns())
                runNodes.getFont().setItalic(true);

            textBox.setAnchorLocked(false);
        }

        builder.moveToDocumentStart();
        builder.writeln();
        builder.moveToDocumentStart();

        final Paragraph currentParagraph = builder.getCurrentParagraph();

        Shape shape = new Shape(builder.getDocument(), ShapeType.TEXT_BOX);
        shape.setWidth(200);
        shape.setHeight(150);
        shape.setLeft(50);
        shape.setTop(80);
        shape.setWrapType(WrapType.NONE);
        shape.setRelativeHorizontalPosition(RelativeHorizontalPosition.MARGIN);
        shape.setRelativeVerticalPosition(RelativeVerticalPosition.MARGIN);

        final Paragraph lastParagraph = new Paragraph(builder.getDocument());
        shape.appendChild(lastParagraph);
        Run run = new Run(builder.getDocument(), "TEST TOC");
        lastParagraph.appendChild(run);
        builder.insertNode(shape);
        builder.moveTo(lastParagraph);

        FieldToc currentGeneratedTOC = (FieldToc) builder.insertTableOfContents("\\o \\h \\z \\u ");

        doc.updateFields();
        doc.save("C:\\Temp\\awjava-21.2.docx");
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

I understand that is not possible in the first order to create the text box with some text treated as
a TOC entry and after then create a text box with TOC which will contain previously created text form other text boxes in this way that will be correctly set italic style?

I tested this case (with the creation TOC as the last element of the generated document) and every time I had to update TOC manually to get the effect of italic style in TOC entry.

@aolo23,

The following code does not reflect custom Font formatting to TOC entries.

Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);

for (int i = 0; i < 20; i++)
    builder.writeln();

Insert_TextBox_Headings(builder, StyleIdentifier.HEADING_1, doc.getFirstSection().getBody().getParagraphs().get(8),
        72 * 2, 72 * 3, 72 * 3, 72);
Insert_TextBox_Headings(builder, StyleIdentifier.HEADING_2, doc.getFirstSection().getBody().getParagraphs().get(10),
        72 * 2, 72 * 4, 72 * 3, 72);
Insert_TextBox_Headings(builder, StyleIdentifier.HEADING_3, doc.getFirstSection().getBody().getParagraphs().get(12),
        72 * 2, 72 * 5, 72 * 3, 72);
Insert_TextBox_Headings(builder, StyleIdentifier.HEADING_4, doc.getFirstSection().getBody().getParagraphs().get(14),
        72 * 2, 72 * 6, 72 * 3, 72);

builder.moveToDocumentStart();
builder.insertTableOfContents("\\o \\h \\z \\u ");

doc.updateFields();

doc.save("C:\\Temp\\awjava-21.2.docx");

public static void Insert_TextBox_Headings(DocumentBuilder document_builder, int style_Identifier, Paragraph para,
                                           double left, double top, double width, double height) throws Exception {

    document_builder.moveTo(para);

    Shape textBox = document_builder.insertShape(ShapeType.TEXT_BOX, width, height);
    textBox.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
    textBox.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
    textBox.setWrapType(WrapType.NONE);
    textBox.setLeft(left);
    textBox.setTop(top);

    document_builder.moveTo(textBox.getFirstParagraph());
    document_builder.getParagraphFormat().setStyleIdentifier(style_Identifier);
    document_builder.getParagraphFormat().getStyle().getFont().setItalic(true);
    document_builder.getFont().setItalic(true);

    document_builder.writeln("Heading " + style_Identifier);
}

For the sake of any corrections in Aspose.Words API, we have logged this problem in our issue tracking system. The ID of this issue is WORDSNET-21941. We will further look into the details of this problem and will keep you updated on the status of linked issue. We apologize for your inconvenience.