Ask Your Question
0

Macro: combine text frames for faster insertion

asked 2018-07-27 04:47:52 +0200

lomacar gravatar image

updated 2018-07-30 01:34:58 +0200

I have a macro that inserts a lot of text frames and adds text in each frame as it goes along and applies styles to the text and whatnot (see code mockup below). The problem is, it runs rather slowly. It takes about 5 seconds to insert 15-20 frames, and I figure that is because it is manipulating the Writer document as it is going along inserting each frame.

Is there a way to build all the frames and manipulate their contents and then insert them all at once into the document? And would that actually speed things up? I tried moving the insertion command to the end, but then the macro crashed at "oFrame.Text.String =".

(This happens inside a for-loop.)

oFrame = ThisComponent.createInstance( "com.sun.star.text.TextFrame" )
oFrame.widthType = 0
oFrame.FrameStyleName = "My Special Frame"
oFrame.Text.AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER
oFrame.Text.VertOrient = 7
...
...
...
ThisComponent.Text.insertTextContent( viewCursor.Start, oFrame, false )
oFrame.Text.String = "[important stuff]"
[do stuff to the text in the frame]

UPDATE: This question doesn't really matter so much anymore, because it seems like LibreOffice was just being slow for no reason. After restarting, my existing code runs much faster.

edit retag flag offensive close merge delete

1 Answer

Sort by » oldest newest most voted
0

answered 2018-07-27 12:21:42 +0200

Lupp gravatar image

I don't feel sure if I got everything right.
-1- Why do you use the ViewCursor? If you want to make lots of insertions in one run based on the selections you made in the text, you should use the CurrentSelction, imo.
-2- A frame not yet inserted as a TextContent obviously cannot take a string. That's a result of your (and my) experiments. As so often I do not know a place where this is specified explicitly. We should take it as a fact nonetheless. If it actually is a bug you would have to report it and wait about 20 years for the fixing.
-3- With the code posted below I inserted 20 frames into a dummy text within about 1 second. Of course insertions into a very long text may need longer. After all every single insertion should cause a new page-wrap process, shouldn't it? When I still had to use MS Word in the 1990es, it often needed minutes for the page wrap.

Code:

REM  *****  BASIC  *****
' NOT from profound knowledge about specifications
' BUT from my experiences and "research" (reverse engineering?)
' A single selection counts for ONE TextRange.
' With a multiple selection the (next term invented!) 'BlinkCursorPosition'
' counts for an extra TextRange and is returned as the 
' ZEROth range of the CurrentSelection object.
Sub insertManyFramesAtMultiSelectedPositions()
theText = ThisComponent.Text
theSel  = ThisComponent.CurrentSelection
u = theSel.Count - 1
If (u>0) Then
 blinkRg = theSel(0)
 lastRg  = theSel(u)
 h1 = theText.CompareRegionStarts(blinkRg, lastRg)
 h2 = theText.CompareRegionEnds  (blinkRg, lastRg)
 If (h1*h2=0) Then
  u = u-1
 End If
End If
Dim theFrames(0 To u) As Object
ThisComponent.UndoManager.EnterUndoContext("manyFrames")
For j = 0 To u
 oneFr = ThisComponent.createInstance( "com.sun.star.text.TextFrame" )
 oneFr.widthType = 0
 oneFr.FrameStyleName = "MySpecialFrameStyle"
 oneFr.AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER
 theText.InsertTextContent(theSel(j).Start, oneFr, False )
 theFrames(j) = oneFr
Next j
For j = 0 To u
 theFrames(j).Text.String = "" & (j+1) &". Important Stuff"
Next j
ThisComponent.UndoManager.LeaveUndoContext
End Sub
' "MySpecialFrameStyle" was defined in the document used for testing.

You may use this example containing the code.
An attempt to runl the Sub for a multiselection NOT only containing regions within ThisComponent.Text will fail. The Sub does not contain code to test for this.

edit flag offensive delete link more

Comments

It doesn't look like this does anything much different than what I already had. What is the difference between CurrentSelection and getViewCursor?

lomacar gravatar imagelomacar ( 2018-07-30 01:33:42 +0200 )edit

What did I miss? As far as I can see you insert one frame at a time giving the position as viewCursor.Start. How would you iterate through the many positions of a muiltiselection this way?
The CurrentSelection is a collection of the single TextRanges selected at the same time and you can create a frame for each position and insert it while the macro iterates through the selected TextRanges.
This was what I roughly understood as the meaning of "combine" you used in the subject.

Lupp gravatar imageLupp ( 2018-07-30 02:26:53 +0200 )edit

From the API documentation: "A TextViewCursor is a TextRange which can travel within a view of a Text object. " I did a bit of considering and experimenting meanwhile. Results: The above quotet statement is obviously not correct. The CurrentController can Select a ViewCursor saved after multiselection e.g. and the selection will not be "a TextRange", but the multiselection again. You also can access the single TextRanges by index as if the ViewCursor was a textRanges object.

Lupp gravatar imageLupp ( 2018-07-30 10:34:45 +0200 )edit

(Continuation)
However, the Count property of a TextRanges object is not accessible from a ViewCursor, The ViewCursor also cannot CreateEnumeration and there is no hint under SupportedServiceNames. It seems to be another mess.
Well, for the current purpose the CurrentSelection is the much simpler object anyway.

Lupp gravatar imageLupp ( 2018-07-30 10:40:03 +0200 )edit
Login/Signup to Answer

Question Tools

1 follower

Stats

Asked: 2018-07-27 04:47:52 +0200

Seen: 65 times

Last updated: Jul 30 '18