Search code examples
c++libreofficeunolibreoffice-writer

Libreoffice API (UNO) : text and data from xTextField


How can I get xTextFields from .odt document properly?

I tried something like that, but it doesn't work (Any returns a nullptr address):

Reference <XTextFieldsSupplier> xTextFieldsSupplier (xTextDoc, UNO_QUERY);
if (!xTextFieldsSupplier.is())
    return { };

Reference<XNameAccess> xTextFieldsInfo = xTextFieldsSupplier->getTextFieldMasters();
if (!xTextFieldsInfo.is())
    return { };

Sequence<OUString> xTextFieldsNames = xTextFieldsInfo->getElementNames();

Any any;
for (::rtl::OUString* field = xTextFieldsNames.begin();
        field != xTextFieldsNames.end();
        field++) {
    std::stringstream field_string;
    field_string << *field;
    QString fieldName = QString::fromStdString(field_string.str());
    any = xTextFieldsInfo->getByName(*field);

    Reference< XTextField > xField(any, UNO_QUERY);

    // other code to work with xField
}

UPD:

I got a solution that helped me here: Libreoffice API (UNO): need to change user's xTextField text


Solution

  • XTextFieldsSupplier has two methods, and it looks like you chose the wrong one. The method to get text fields is getTextFields().

    Example code:

    Reference< XEnumerationAccess > xFieldsEnumAccess = xTextFieldsSupplier->getTextFields();
    Reference< XEnumeration > xFieldsEnum = xFieldsEnumAccess->createEnumeration();
    Reference< XTextRange > xTextRange;
    while ( xFieldsEnum->hasMoreElements() )
    {
        Any aNextElement = xFieldsEnum->nextElement();
        Reference< XTextField > xField(aNextElement, UNO_QUERY);
        OUString presentation = xField->getPresentation(true);
        xTextRange = xText->getEnd();
        xTextRange->setString(presentation + OUString::createFromAscii("\n"));
    }
    

    If you want to deal with text field masters instead, then your code is mostly correct.

    Any aFieldMaster;
    aFieldMaster = xNamedFieldMasters->getByName(*field);
    

    EDIT:

    Here is where xText comes from.

    Reference < XTextDocument > xTextDocument (xComponent,UNO_QUERY);
    Reference< XText > xText = xTextDocument->getText();
    

    EDIT 2:

    Here is an example of changing a text field. Start with a new Writer document and go to Insert -> Field -> More Fields. Under the Functions tab, double-click Input Field. Enter "hello" in the text box area and press OK.

    Then, run the following code.

    Reference< XServiceInfo > xInfo (xField, UNO_QUERY);
    OUString sContent;
    if (xInfo->supportsService("com.sun.star.text.TextField.Input"))
    {
        Reference< XPropertySet > xProps (xField, UNO_QUERY);
        Any aContent = xProps->getPropertyValue(OUString::createFromAscii("Content"));
        aContent >>= sContent;
        sContent += OUString::createFromAscii(" there");
        aContent <<= sContent;
        xProps->setPropertyValue(OUString::createFromAscii("Content"), aContent);
        Reference< XRefreshable > xRefreshable (xFieldsEnumAccess, UNO_QUERY);
        xRefreshable->refresh();
    }
    

    Now, the field contains "hello there".

    For more information, please review Andrew's Macro Document section 5.18 User Fields.