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?
Enumerating conditional text fields
-
- Posts: 44
- Joined: Tue Apr 10, 2018 6:15 am
Enumerating conditional text fields
W10 Libre 6.1.5.2 and Ubuntu-Mate 18.04 Libre 6.0.7.3
Re: Enumerating conditional text fields
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.
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.
-
- Posts: 44
- Joined: Tue Apr 10, 2018 6:15 am
Re: Enumerating conditional text fields
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
Re: Enumerating conditional text fields
This thread has some discussion on the matter of User Fields
viewtopic.php?f=45&t=28211
viewtopic.php?f=45&t=28211
Apache OpenOffice 4.1.15 on Xubuntu 22.04.4 LTS
-
- Posts: 44
- Joined: Tue Apr 10, 2018 6:15 am
Re: Enumerating conditional text fields
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
Re: Enumerating conditional text fields
adapting what I saw here:
https://stackoverflow.com/questions/497 ... e-document
if you install mri you can investigate further:
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)
-
- Posts: 44
- Joined: Tue Apr 10, 2018 6:15 am
Re: Enumerating conditional text fields
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.
showVarFields shows only the VARIABLE sub-type by throwing a resume next exception for any TextField that doesn't have the VariableName element:
throwFields shows how text field sub-types can be determined by no exception on accessing something unique to that type.
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
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
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
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