Ask Your Question

writer:macro search in selection

asked 2019-10-30 18:35:56 +0200

torreone gravatar image

updated 2020-09-03 16:07:31 +0200

Alex Kemp gravatar image

Greetings to all, I'm new to the forum , sorry for my poor english. I'm designing a macro to search for text in writers but only within a selected text The purpose is to search for a text, select the instances found, perform a new search on the new selected text to perform nested searches

From the menu it is sufficient to activate the "search only in selection" checkbox.

Using the macro recorder the output is:

document = ThisComponent.CurrentController.Frame 
dispatcher = createUnoService ("") 
dim args1 (21) as new 
args1 (0) .Name = "SearchItem.StyleFamily" 
args1 (0) .Value = 2 
args1 (1) .Name = "SearchItem.CellType" 
args1 (1) .Value = 0 
args1 (2) .Name = "SearchItem.RowDirection" 
args1 (2) .Value = true 
args1 (3) .Name = "SearchItem.AllTables" 
args1 (3) .Value = false 
args1 (4) .Name = "SearchItem.SearchFiltered" 
args1 (4) .Value = false
args1 (19) .Value = false 
args1 (20) .Name = "SearchItem.AlgorithmType2" 
args1 (20) .Value = 1 
args1 (21) .Name = "Quiet" 
args1 (21) .Value = true  
dispatcher.executeDispatch (document, ".uno: ExecuteSearch", "", 0, args1 ())

The property involved should be SearchFiltered or something similar, but I can't find any documentation about it.

Furthermore, SearchFiltered does not appear in the properties of the createSearchDescriptor object.

I tried to make the following macro run on the current document with a selected text segment:

oDoc = ThisComponent
oDesc = oDoc.createSearchDescriptor ()
oDesc.searchWords = TRUE
oDesc.SearchString = "little"
Dim q (0) as new
q (0) .Name = "SearchFiltered"
q (0) .Value = true oDesc.SetSearchAttributes (q ())
oFound = oDoc.findAll (oDesc)

The oDesc.SetSearchAttributes (q ()) statement causes the runtime error due to an exception with the unexplained message Type: Message:.

I searched for a long time on the net but I didn't find any examples, i don't understand how to search for text in a selection with a macro, while I didn't have any problem searching for texts and styles with macros

How to solve the problem?

edit retag flag offensive close merge delete


Why not search directly?, why nested?

mauricio gravatar imagemauricio ( 2019-10-30 19:11:27 +0200 )edit

I have to search for text contained in the headins. If I look for the paragraphs associated with a given style (for example heading 3) I cannot search for text at the same time.

The text searched is the name of the style, not the textual search key

If it were possible to select only the headings with a macro, it is very fast by selecting all the instances with

oView = ThisComponent.getCurrentController ()
fnd = ThisComponent.findAll (oSearch) (fnd)

and then perform the search only on the selection (a very small text segment) of the only text search key Using a macro already prepared to search in the heading (or in paragraphs with well-defined styles), just pass the text key.

Moreover it seems strange to me that by means of macros it is possible to define through the properties substantially all the values ​​of the attributes but not that ...(more)

torreone gravatar imagetorreone ( 2019-10-30 19:53:44 +0200 )edit

I'm new to the forum, but I've been following Mike's and Villeroy's posts for a long time, I know their availability and knowledge well. The whole community helped me find many solutions since, a few months ago, I started working with OO and LO macros, but their answers were among the most important. I take advantage of Mike's reply referring to Villeroy to thank both of them for all the help they gave me together with the community. In practice, I use writers as a simplified database to perform queries and subqueries on text content to avoid involving a database For this I need to automate the nesting of searches. I am considering a possible alternative route, if it works I will propose it eventually in the answers, I hope soon. Thanks again to everyone

torreone gravatar imagetorreone ( 2019-10-31 17:18:18 +0200 )edit

If it can be useful, I found this article very recent on this topic, although it seems to refer only to calc

torreone gravatar imagetorreone ( 2019-10-31 17:45:22 +0200 )edit

The 2048 value (the one of the two used in the question I linked to) is used to mean "selection only". It is used in Writer's code as well. So I suppose that you should just use that value in your "SearchItem.SearchFlags" value.

Mike Kaganski gravatar imageMike Kaganski ( 2019-10-31 18:32:41 +0200 )edit

Your hypothesis seems to be working !!! . A macro containing

dispatcher = createUnoService ("")
dim args1 (21) as new
args1 (10) .Name = "SearchItem.SearchFlags"
args1 (10) .Value = 2048
args1 (11) .Name = "SearchItem.SearchString"
args1 (11). Value = "structure"
dispatcher.executeDispatch (document, ".uno: ExecuteSearch", "", 0, args1 ())

registered by activating the findAll button selects all instances of "structure" but only in the selected text .

The indication that gave the article on : "The sum of these flags: 16 -> search f ...... 2048 -> search only the selected cells, 4096 -> seems not be used, ..... etc "therefore does not apply only to calc, but as you would have hypothesized also in writer.

torreone gravatar imagetorreone ( 2019-10-31 20:28:22 +0200 )edit

I haven't hypothesized; I had read the code before passing you the link where the question stated clearly how to make it search in selection.

Mike Kaganski gravatar imageMike Kaganski ( 2019-10-31 20:37:08 +0200 )edit

Yes, from your last answer I understood only now that your phrase "the one of the two used" meant 6144 = 2048 + 4096, and therefore why I didn't see 2048 in the post of your link

Now I think that it is possible to obtain the nested search that I wanted to get.

If each instance of "structure" identifies a text area (paragraph group, section, etc.) on which to refine the search, starting from the textRange of the instances rendered by thisComponent.currentSelection you can derive from these the new search areas to be selected that contain these instances and on these perform new searches and so on until the required data is found.

Very thanks!

torreone gravatar imagetorreone ( 2019-10-31 21:06:19 +0200 )edit

The other more cumbersome solution that I was considering for to use SearchDescriptor (more flexible) consisted in filtering with a macro all the text defined by particular styles (es heading) in which to perform the search, select it, temporarily modify an attribute with the macro (for example fontfamily attribute) using a font not used in the rest of the document, use searchDescriptor to search for the requested text in the only areas formatted with this new font-family. After completing searches, the initial formatting was restored

SearchDescriptor allows you to find a string in a text formatted with specific attributes, but not search in texts with a given style, because the search string is the name of the style, not the text to be found.

One last important question, if possible: which parameter of the array arguments passed to the dispatcher (or other parameter) distinguishes findAll from findFirst? The macro recorder ...(more)

torreone gravatar imagetorreone ( 2019-10-31 21:08:15 +0200 )edit

2 Answers

Sort by » oldest newest most voted

answered 2019-10-31 23:16:06 +0200

torreone gravatar image

updated 2019-10-31 23:26:17 +0200

The purpose of this thread is to perform nested searches within a writer document using the instances of each search as the starting point for new research, working directly on the instances or starting from these to derive new areas within which to execute new ones research The result is obtained by delimiting the research area more and more in successive phases. The research should speed up more and more after each phase as the search area is increasingly limited. The increasingly fragmented search area should be selected to use the search option "search only in the selection".

The discussion was opened because the searchdescriptor object does not support a property or method that allows searching on only selected text, which is possible, on the contrary, by activating the menu search, without using macros.

But the menu search does not make the array of instances produced by thisComponent.findAll (instanceSearchDescriptor), from which all instances can be selected with a single statement.

The solution identified consists in using the UNO Dispatch Command ('.uno: ExecuteSearch') understanding both how to execute the findAll command and which argument to use to set the search on the selected text only, two other questions I didn't know how to answer.

The basic code is obtained with the macro recorder, recording the commands (only from the keyboard) after activating the menu function "search & repkace (ctrl H), moving to the relative form with tab / shift tab and using the space key to activate / deactivate the required checkbutton. In the list of properties (name-value pairs) obtained from the macro recorder the most important are "SearchFlags" and "Command" as well as of course all those specific to the search to be automated.

dispatcher = createUnoService ("")

dim args1 (20) as new
args1 (0) .Name = "SearchItem.StyleFamily"
args1 (0) .Value = 2
args1 (10) .Name = "SearchItem.SearchFlags"
args1 (10) .Value = 2048
args1 (11) .Name = "SearchItem.SearchString"
args1 (11) .Value = "text to search"
args1 (18) .Name = "SearchItem.Command"
args1 (18) .Value = 1
dispatcher.executeDispatch (document, ".uno: ExecuteSearch", "", 0, args1 ())

The first search can also be performed on the whole current document. Instances of the text to be searched are selected as the result of the research. The selection (usually multiple), if necessary, is accessed with thisComponent.currentSelection

On this selection (or on text areas that can be obtained from the selection and subsequently all selected) the search is performed on the selected text only, and so for subsequent searches until the required result is obtained.

Thanks for the help.

Sorry, I don't have the twenty points required to set the correct mark

edit flag offensive delete link more

answered 2019-11-01 17:00:43 +0200

Lupp gravatar image

updated 2019-11-01 20:19:03 +0200


Sub getFoundRanges(Optional pRgs As Object)
IF IsMissing(pRgs) Then pRgs = ThisComponent.CurrentSelection
If NOT pRgs.supportsService("") Then Exit Sub

doc            = ThisComponent
currC          = doc.CurrentController

selQuoAnte     = doc.CurrentSelection

dispProvider   = doc.CurrentController.Frame
dispHelper     = createUnoService("")
Dim args(21) As New
args(0).Name   = "SearchItem.StyleFamily"
args(0).Value  = 2
REM ... as found in the recorded macro ...
args(10).Name  = "SearchItem.SearchFlags"
args(10).Value = 71680
REM The SearchFlags value actually depends on the "Current selection only". 
REM ...
args(21).Name  = "Quiet"
args(21).Value = true

u = pRgs.Count - 1
Dim results(u)
For j = 0 To u
 rg_j = pRgs(j)
 If rg_j.String="" Then
  results(j) = Null
  dispHelper.executeDispatch(dispProvider, ".uno:ExecuteSearch", "", 0, args())
  found_j = doc.CurrentSelection
  results(j) = found_j
 End If
Next j

REM Process the results ...

End Sub

It works for me roughly as expected.
Expectations include that the sub cannot work if a TextTableCursor is selected.

Why only "roughly"? That's because the selection for F&R will not be changed if 0 (zero) occurrences were found. The used way to get a partial result will therefore always count at least 1 (one) TextRange. We would need to check for an actual match in case of .Count=1, and I cannot tell you a really simple way top do so if RegEx or Wildcards were searched.

Anyway this is just bullshit as Villeroy already stated.
Lupp, on the other hand, doesn't actually understand for what reason the API doesn't support XReplaceable for TextRanges (and also for TextTableCursors probably). After all the interface is supported for SheetCellRange_s in Calc.

===Edit1 2019-11-01 19:00 UTC===
Had a nap and dreamt the solution. the function executeDispatch returns an event object.

For j = 0 To u
 rg_j = pRgs(j)
 execEvent = _
 dispHelper.executeDispatch(dispProvider, ".uno:ExecuteSearch", "", 0, args())
 If execEvent.Result Then
  found_j = doc.CurrentSelection
  found_j = Null
 End If
 results(j) = Array(rg_j, found_j)
Next j
edit flag offensive delete link more


I'm Italian, I write with google translate. The villeroy's statement "bullshit" is synonymous with "useless application"? If so, no application is useless if it requires techniques that can be used as functional architectures in other less useless applications. The Star Basic language has limits, it must be known very well to solve specific problems. Your final edit gave me the key piece of information, that the executeDispatch made an output Is it possible to concatenate in a single textranges the textranges produced by a search that makes multiple instance in output? This would make it possible to perform a single search for a more extended textrange rather than a search for each individual texture. Otherwise, you should select each textRange in each textRanges, accessing in sequence, adding each new selection to the currentSelection. But how can a macro add a new selection to the currentSelection without deselecting the previous selections?

torreone gravatar imagetorreone ( 2019-11-01 22:25:27 +0200 )edit

I thought this code could be the solution to sequentially select the text Ranges of a textRanges. Iterating on other textranges in the same way I thought I would get a single selection of all the instances produced by subsequent searches. But I see that it always selects only the last instance accessed

oFound = thisComponent.findAll (oFind):
oVC = thisComponent.getCurrentController.getViewCursor

xx0 = oFound.getByIndex (0)
oVC.gotoRange (xx0.start, false)
oVC.gotoRange (xx0.end, true)
xx1 = oFound.getByIndex (1)
oVC.gotoRange (xx1.start, false)
oVC.gotoRange (xx1.end, true)

Clearly the final code should use a loop.

Where am I doing wrong ?

torreone gravatar imagetorreone ( 2019-11-01 23:18:03 +0200 )edit

The search itself selects the occurrences with FindAll ...
Quoting @torreone: "Is it possible to concatenate in a single textranges the textranges produced by a search..."
I don't know a way. There also seems not to be a way to create a (empty) instance of TextRanges or to remove a specific TextRange from a TextRanges container.
The relevant service is not at all comparable to SheetCellRanges which has lots of useful features.
Quoting @torreone: "But how can a macro add a new selection to the currentSelection..." Don't know.

Lupp gravatar imageLupp ( 2019-11-02 01:01:42 +0200 )edit

Thanks for the reply. The FindAll method returns all instances (multiple) of a single search. But to search for a string in all the paragraphs formatted with a heading 1-2-3 I would have to do 3 single searches, the 1st to filter the paragraphs with heading 1, the 2nd to filter the heading 2, the 3rd to filter the heading 3. I was wondering if it was possible to link the 3 textranges rendered by findAll Having found neither methods nor useful properties in textanges on the net nor with debugging and breakpoints, I had concluded like you that there was no method to add a new textrange to an existing textranges. But it seemed to me possible to use a viewcursor to select one by one all the single textrange found. But the code I proposed in a previous post that would solve the problem does not work I ...(more)

torreone gravatar imagetorreone ( 2019-11-03 00:06:16 +0200 )edit
Login/Signup to Answer

Question Tools

1 follower


Asked: 2019-10-30 18:35:56 +0200

Seen: 891 times

Last updated: Nov 01 '19