Enumerating conditional text fields

The Application Programming Interface and the OASIS Open Document Format

Enumerating conditional text fields

Postby DavidHMcCracken » Fri May 31, 2019 6:48 am

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?
OpenOffice 4.1.5 on Ubuntu 16.04
DavidHMcCracken
 
Posts: 12
Joined: Tue Apr 10, 2018 6:15 am

Re: Enumerating conditional text fields

Postby Zizi64 » Fri May 31, 2019 4:50 pm

Do you have at least one of the third party object inspection tools? (MRI, XrayTool...)
Tibor Kovacs, Hungary; LO6.1.6 on Win7-10 x64Prof.
PortableApps, winPenPack: LO3.3.0-6.2.5; AOO4.1.6
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.
User avatar
Zizi64
Volunteer
 
Posts: 8331
Joined: Wed May 26, 2010 7:55 am
Location: Budapest, Hungary

Re: Enumerating conditional text fields

Postby DavidHMcCracken » Fri May 31, 2019 6:40 pm

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.
OpenOffice 4.1.5 on Ubuntu 16.04
DavidHMcCracken
 
Posts: 12
Joined: Tue Apr 10, 2018 6:15 am

Re: Enumerating conditional text fields

Postby RoryOF » Fri May 31, 2019 6:47 pm

This thread has some discussion on the matter of User Fields
https://forum.openoffice.org/en/forum/viewtopic.php?f=45&t=28211
Apache OpenOffice 4.1.7 on Xubuntu 18.04.3 (mostly 64 bit version) and very infrequently on Win2K/XP
User avatar
RoryOF
Moderator
 
Posts: 29569
Joined: Sat Jan 31, 2009 9:30 pm
Location: Ireland

Re: Enumerating conditional text fields

Postby DavidHMcCracken » Fri May 31, 2019 7:19 pm

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.
OpenOffice 4.1.5 on Ubuntu 16.04
DavidHMcCracken
 
Posts: 12
Joined: Tue Apr 10, 2018 6:15 am

Re: Enumerating conditional text fields

Postby JeJe » Fri May 31, 2019 10:36 pm

adapting what I saw here:

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

if you install mri you can investigate further:

Code: Select all   Expand viewCollapse view
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

Openoffice 4.1.2
Windows 8
JeJe
Volunteer
 
Posts: 581
Joined: Wed Mar 09, 2016 2:40 pm

Re: Enumerating conditional text fields

Postby DavidHMcCracken » Sat Jun 01, 2019 7:24 am

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   Expand viewCollapse view
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   Expand viewCollapse view
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   Expand viewCollapse view
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
OpenOffice 4.1.5 on Ubuntu 16.04
DavidHMcCracken
 
Posts: 12
Joined: Tue Apr 10, 2018 6:15 am


Return to UNO API and ODF

Who is online

Users browsing this forum: No registered users and 4 guests