Enumerating conditional text fields

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Post Reply
DavidHMcCracken
Posts: 44
Joined: Tue Apr 10, 2018 6:15 am

Enumerating conditional text fields

Post by DavidHMcCracken »

LibreOffice 6.1.5.2 (x64) on W10. Writer. BASIC macro.
I'm trying to enumerate all text fields in a document in order to search for a specific one. Other objects enumerate easily. e.g.ThisComponent.Bookmarks is an array of bookmark objects. ThisComponent.TextFields exists but is not an array and has no iterative mechanism. To try to do this with general text fields I have modified Pitonyak's EnumerateTextSections (Listing 342) to show only text fields but in more detail, i.e. if not IsNull( oParSection.TextField) then inspect the section. For variable type text fields the object is fully constructed and all methods and elements are valid and accessible. But for conditional text fields the object is incomplete. Most elements are <out of scope> and all of the elements that are not like this have the same values as any fully constructed text field. Even the array elements that the BASIC IDE debugger implies are complete because it tells their index range, SupportedServiceName, Types, and ImplementationID, are not complete and expanding them crashes the debugger. Writer itself obviously knows how to make sense of this because Insert > Field > More Fields > Functions tab shows any existing conditional text fields. Does anyone have any idea how to access this same information from a macro?
W10 Libre 6.1.5.2 and Ubuntu-Mate 18.04 Libre 6.0.7.3
User avatar
Zizi64
Volunteer
Posts: 11352
Joined: Wed May 26, 2010 7:55 am
Location: Budapest, Hungary

Re: Enumerating conditional text fields

Post by Zizi64 »

Do you have at least one of the third party object inspection tools? (MRI, XrayTool...)
Tibor Kovacs, Hungary; LO7.5.8 /Win7-10 x64Prof.
PortableApps/winPenPack: LO3.3.0-7.6.2;AOO4.1.14
Please, edit the initial post in the topic: add the word [Solved] at the beginning of the subject line - if your problem has been solved.
DavidHMcCracken
Posts: 44
Joined: Tue Apr 10, 2018 6:15 am

Re: Enumerating conditional text fields

Post by DavidHMcCracken »

Thank you for the suggestion. I do not have these. I will check them out. If you have any additional thoughts, please let me know. Your insights have always been very helpful.
W10 Libre 6.1.5.2 and Ubuntu-Mate 18.04 Libre 6.0.7.3
User avatar
RoryOF
Moderator
Posts: 34586
Joined: Sat Jan 31, 2009 9:30 pm
Location: Ireland

Re: Enumerating conditional text fields

Post by RoryOF »

This thread has some discussion on the matter of User Fields
viewtopic.php?f=45&t=28211
Apache OpenOffice 4.1.15 on Xubuntu 22.04.4 LTS
DavidHMcCracken
Posts: 44
Joined: Tue Apr 10, 2018 6:15 am

Re: Enumerating conditional text fields

Post by DavidHMcCracken »

To RoryOF. Thank you for that reference but it isn't quite what I'm looking for. It provides Perl and Python examples and I would like to avoid the complexity of non-native languages (although I like Python a lot more than BASIC). Also, the moderator in that discussion says that the topic has been moved to the "programming" forum and I can't find it to see if there is anything more that I might be able to use.
W10 Libre 6.1.5.2 and Ubuntu-Mate 18.04 Libre 6.0.7.3
JeJe
Volunteer
Posts: 2763
Joined: Wed Mar 09, 2016 2:40 pm

Re: Enumerating conditional text fields

Post by JeJe »

adapting what I saw here:

https://stackoverflow.com/questions/497 ... e-document

if you install mri you can investigate further:

Code: Select all

Sub Main
paragraphs = thiscomponent.text.createEnumeration()
while paragraphs.hasMoreElements()
    text_portions = paragraphs.nextElement().createEnumeration()
    while text_portions.hasMoreElements()
        text_portion = text_portions.nextElement()
		 if text_portion.TextPortionType = "TextField" then
			msgbox text_portion.string
'			mri text_portion
			 end if
  wend
wend
end sub

Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
DavidHMcCracken
Posts: 44
Joined: Tue Apr 10, 2018 6:15 am

Re: Enumerating conditional text fields

Post by DavidHMcCracken »

Thank you all for responding so quickly and offering good advice.

Per Zizi's suggestion I installed XrayTool and it cleared up everything. I have been having some difficulty determining the scope of UNO things and relying on the BASIC IDE to inspect objects to see what exists and what needs to be constructed. When that crashes, I'm left wondering whether what I'm asking is unknowable or just not yet known.

XrayTool had no trouble at all inspecting the objects. I imagine that MRI is similarly capable. "Get a tool that can inspect objects without crashing" is probably the first answer to any macro problem. The specific question of "enumerating conditional text fields" becomes fairly trivial when you can reliably inspect objects.

However, for anyone whose focus is this specific topic I would like to share what I have learned. For each element (section) of a paragraph, testing for TextField not NULL is a reliable and safe (i.e. it is a reference that exists for all sections) indication of TextField. Under this, all elements are either identical regardless of TextField sub-type or unique to the sub-type, in which case accessing them throws an exception, except for the SupportedServiceNames array.

Inspecting this crashed the native IDE but XrayTool showed clearly that the first element reveals the field type. For example SupportedServiceNames(0) = "com.sun.star.text.TextField.SetExpression" for a variable but "com.sun.star.text.TextField.ConditionalText" for conditional text. A macro that needs to know the specific TextField sub-type must either do a string comparison of this or try to access an element that exists only for the subtype and handle the exception thrown by all others. This works well in my situation.

I just want to know whether a TextField-Variable with the VariableName ShowBookmarks exists. If my macro tries to access the VariableName element of any TextField that is not a VARIABLE (SetExpression) it raises an exception and the handler can simply be to continue (on error resume next). For users who may have other requirements I present some macros based on Pitonyak's EnumerateTextSections (Listing 342) which may be helpful.

showTextFields demonstrates parsing the SupportedServiceNames to determine the sub-type.

Code: Select all

sub showTextFields
    parEnum = ThisComponent.Text.createEnumeration()
    do while parEnum.hasMoreElements()
        oPar = parEnum.nextElement()
        if oPar.supportsService("com.sun.star.text.Paragraph") then
            nPars = nPars + 1
            secEnum = oPar.createEnumeration()
            show = show & nPars & ":"
            do while secEnum.hasMoreElements()
                oSec = secEnum.nextElement()
                if not IsNull(oSec.TextField) then
                    'Xray oSec.TextField
                    ssn = split(oSec.TextField.SupportedServiceNames(0), ".")
                    show = show & "TextField-" & ssn(Ubound(ssn)) & " "
                end if 'Section is TextField
            loop 'while parEnum.hasMoreElements i.e. over all elements in this paragraph
            show = show & CHR$(10) 'Start new line for the next paragraph
        end if 'Paragraph
    loop 'while parEnum.hasMoreElements() i.e. over all paragraphs
    MsgBox show, 0, "Paragraph Text Sections"
end sub
showVarFields shows only the VARIABLE sub-type by throwing a resume next exception for any TextField that doesn't have the VariableName element:

Code: Select all

sub showVarFields
    on error resume next
    parEnum = ThisComponent.Text.createEnumeration()
    do while parEnum.hasMoreElements()
        oPar = parEnum.nextElement()
        if oPar.supportsService("com.sun.star.text.Paragraph") then
            nPars = nPars + 1
            secEnum = oPar.createEnumeration()
            show = show & nPars & ":"
            do while secEnum.hasMoreElements()
                oSec = secEnum.nextElement()
                if not IsNull(oSec.TextField) then
                    show = show & "VariableField-" & oSec.TextField.VariableName & " "
                end if 'Section is TextField
            loop 'while secEnum.hasMoreElements i.e. over all elements in this paragraph
            show = show & CHR$(10) 'Start new line for the next paragraph
        end if 'Paragraph
    loop 'while parEnum.hasMoreElements() i.e. over all paragraphs
    MsgBox show, 0, "Paragraph Text Sections"
end sub
throwFields shows how text field sub-types can be determined by no exception on accessing something unique to that type.

Code: Select all

sub throwFields()
    on error goto TfError
    parEnum = ThisComponent.Text.createEnumeration()
    do while parEnum.hasMoreElements()
        curPar = parEnum.nextElement()
        if curPar.supportsService("com.sun.star.text.Paragraph") then
            nPars = nPars + 1
            secEnum = curPar.createEnumeration()
            show = show & nPars & ":"
            do while secEnum.hasMoreElements()
                curSec = secEnum.nextElement()
                if Not IsNull(curSec.TextField) then
                    tfType = 0
TryAnother:         
                    if tfType = 0 then
                        show = show & "ConditionalText-onVar=" & _
                          curSec.TextField.Condition & "; "
                    elseIf tfType = 1 then 
                        show = show & "SetExpression-VarName=" & _
                          curSec.TextField.VariableName & "; "
                    else
                        show = show & "Other; "
                    end if
                end if 'Section is TextField
            loop ' Over all elements in this paragraph
            show = show & CHR$(10) 'Start new line for the next paragraph
        end if 'Paragraph
    loop ' Over all document elements.
    MsgBox show, 0, "Paragraph Text Sections"
    on error goto 0
    exit sub
TfError:
    tfType = tfType + 1
    resume TryAnother
end sub
Last edited by robleyd on Sat Jun 01, 2019 9:41 am, edited 1 time in total.
Reason: Edit 'wall of text' to add line breaks
W10 Libre 6.1.5.2 and Ubuntu-Mate 18.04 Libre 6.0.7.3
Post Reply