dispatcher.executeDispatch with headless pyuno for wrap in background

Hello!

I have regular text and I have a textframe, which I want to send “wrap in background”.
Apparently this cannot be set via setPropertyValue.
Difficulty is I invoke writer headless.
Macro recording suggest the use of dispatcher.executeDispatch.
My suspicion is the problem is with line:
dispatcher.executeDispatch(model.CurrentController.Frame, “.uno:WrapThroughTransparencyToggle”, “”, 0, ())

Any help appreciated,
Robert

#!/bin/python
# -*- coding: utf-8 -*-
# coding: utf8

import uno
import unohelper
import os
import time

from com.sun.star.text.WrapTextMode import THROUGHT as WrapTextModeTHROUGHT
from com.sun.star.text.TextContentAnchorType import AT_PARAGRAPH
from com.sun.star.beans import PropertyValue
from com.sun.star.awt import Size

def rgb(r, g, b):
    return 256*256*r + 256*g + b

os.system("libreoffice --headless --accept='socket,host=localhost,port=2002,tcpNoDelay=1;urp' --nodefault --nofirststartwizard --nolockcheck --nologo --norestore --invisible &")
time.sleep(1)

localContext = uno.getComponentContext()

resolver = localContext.ServiceManager.createInstanceWithContext( "com.sun.star.bridge.UnoUrlResolver", localContext )

smgr = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ServiceManager" )
remoteContext = smgr.getPropertyValue( "DefaultContext" )


desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",remoteContext)
dispatcher = smgr.createInstanceWithContext("com.sun.star.frame.DispatchHelper", remoteContext)
ccontext = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")

doc = desktop.loadComponentFromURL( "private:factory/swriter","_blank", 0, () )

text = doc.Text
cursor = text.createTextCursor()

cursor.CharColor = rgb(0, 0, 0)

textFrame = doc.createInstance( "com.sun.star.text.TextFrame" )
textFrame.setSize( Size(17000,17000))

model = desktop.getCurrentComponent()

textFrame.setPropertyValue( "AnchorType" , AT_PARAGRAPH )
textFrame.setPropertyValue( "AnchorPageNo", 1 )
textFrame.HoriOrient = 0
textFrame.HoriOrientPosition = 5
textFrame.HoriOrientRelation = 6
textFrame.setPropertyValue( "TextWrap", WrapTextModeTHROUGHT )
# Functionality wrap "in background" needs to be invoked
dispatcher.executeDispatch(model.CurrentController.Frame, ".uno:WrapThroughTransparencyToggle", "", 0, ())
#
noLine = uno.createUnoStruct( "com.sun.star.table.BorderLine2" )
noLine.LineStyle = uno.getConstantByName("com.sun.star.table.BorderLineStyle.NONE")
noLine.LineWidth = 0
text.insertTextContent( cursor, textFrame, 0 )
textFrame.TopBorder = textFrame.RightBorder = textFrame.BottomBorder = textFrame.LeftBorder = noLine

solidLine = uno.createUnoStruct( "com.sun.star.table.BorderLine2" )
solidLine.LineStyle = uno.getConstantByName("com.sun.star.table.BorderLineStyle.SOLID")
solidLine.LineWidth = 10
textInTextFrame = textFrame.getText()
cursorInTextFrame = textInTextFrame.createTextCursor()
cursorInTextFrame.CharHeight = 9
cursorInTextFrame.CharColor = rgb(0, 0, 255)

text.insertString(cursor, "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.", 0)

textInTextFrame.insertString( cursorInTextFrame, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus sed dolor pellentesque nunc accumsan cursus at ac risus. Sed tincidunt erat a metus rutrum, nec vestibulum nisl vulputate. Donec eu elit vel dui dictum bibendum. Ut quis iaculis tortor. Sed efficitur, elit vel fringilla ullamcorper, elit tortor rutrum purus, eu dapibus risus mi quis sem. Integer elementum turpis eu vehicula porta. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla pharetra id lorem a ultrices. Aliquam ante mauris, luctus porta mollis ac, laoreet id leo. Vivamus a molestie est, et tempor purus. Nam eget accumsan lacus. Nullam consequat convallis lectus, eu commodo tellus lobortis non.",0)


properties = (PropertyValue("FilterName", 0, "writer8", 0), PropertyValue("Overwrite", 0, True, 0),)
doc.storeToURL('file:///tmp/test.odt', properties )

doc.dispose()
os.system("killall soffice.bin &")

Use subprocess instead os.system !!

import uno
from subprocess import Popen
from pythonscript import ScriptContext

from com.sun.star.text.WrapTextMode import THROUGHT as WrapTextModeTHROUGHT
from com.sun.star.text.TextContentAnchorType import AT_PARAGRAPH
from com.sun.star.beans import PropertyValue
from com.sun.star.awt import Size
from com.sun.star.table.BorderLineStyle import NONE, SOLID

PIPENAME = "abraxas" ## CHANGE_ME

officepath = 'soffice'
writer = '--writer'
pipe = f"--accept=pipe,name={PIPENAME};urp;StarOffice.Servicemanager"

Popen([officepath,
       "--headless",
       "--invisible",
       #writer,        
       pipe]); 



local = uno.getComponentContext()
resolver = local.ServiceManager.createInstance("com.sun.star.bridge.UnoUrlResolver")
client = resolver.resolve( "uno:pipe,"
                           f"name={PIPENAME};"
                           "urp;"
                           "StarOffice.ComponentContext")
createUnoService = client.ServiceManager.createInstance

XSCRIPTCONTEXT = ScriptContext(client, None, None)

desktop = XSCRIPTCONTEXT.getDesktop()
hide_me = PropertyValue("Hidden", 0, True, 0)
doc = desktop.loadComponentFromURL( "private:factory/swriter","_blank", 0, (hide_me,) )

text = doc.Text
cursor = text.createTextCursor()

cursor.CharColor = int('000000', 16)

textFrame = doc.createInstance( "com.sun.star.text.TextFrame" )
textFrame.setSize( Size(17000,17000))

textFrame.setPropertyValue( "AnchorType" , AT_PARAGRAPH )
textFrame.setPropertyValue( "AnchorPageNo", 1 )
textFrame.HoriOrient = 0
textFrame.HoriOrientPosition = 5
textFrame.HoriOrientRelation = 6
textFrame.setPropertyValue( "TextWrap", WrapTextModeTHROUGHT )
# Functionality wrap "in background" needs to be invoked
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
dispatcher.executeDispatch(doc.CurrentController.Frame, ".uno:WrapThroughTransparencyToggle", "", 0, ())

noLine = uno.createUnoStruct( "com.sun.star.table.BorderLine2" )
noLine.LineStyle = NONE
noLine.LineWidth = 0
text.insertTextContent( cursor, textFrame, 0 )
textFrame.TopBorder = textFrame.RightBorder = textFrame.BottomBorder = textFrame.LeftBorder = noLine

solidLine = uno.createUnoStruct( "com.sun.star.table.BorderLine2" )
solidLine.LineStyle = SOLID
solidLine.LineWidth = 10
textInTextFrame = textFrame.getText()
cursorInTextFrame = textInTextFrame.createTextCursor()
cursorInTextFrame.CharHeight = 9
cursorInTextFrame.CharColor = int("0000ff", 16) #blue

text.insertString(cursor, "Lorem Ipsum is simply dummy text of the printing and"
                  " typesetting industry. Lorem Ipsum has been the industry's"
                  " standard dummy text ever since the 1500s, when an unknown"
                  " printer took a galley of type and scrambled it to make a type"
                  " specimen book. It has survived not only five centuries, but"
                  " also the leap into electronic typesetting, remaining essentially unchanged."
                  " It was popularised in the 1960s with the release of Letraset sheets containing"
                  " Lorem Ipsum passages, and more recently with desktop publishing software like"
                  " Aldus PageMaker including versions of Lorem Ipsum.", 0)

textInTextFrame.insertString( cursorInTextFrame, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
                             " Phasellus sed dolor pellentesque nunc accumsan cursus at ac risus."
                             " Sed tincidunt erat a metus rutrum, nec vestibulum nisl vulputate."
                             " Donec eu elit vel dui dictum bibendum. Ut quis iaculis tortor."
                             " Sed efficitur, elit vel fringilla ullamcorper, elit tortor rutrum purus,"
                             " eu dapibus risus mi quis sem. Integer elementum turpis eu vehicula porta."
                             " Lorem ipsum dolor sit amet, consectetur adipiscing elit."
                             " Nulla pharetra id lorem a ultrices."
                             " Aliquam ante mauris, luctus porta mollis ac, laoreet id leo."
                             " Vivamus a molestie est, et tempor purus. Nam eget accumsan lacus."
                             " Nullam consequat convallis lectus, eu commodo tellus lobortis non.",0)

properties = (PropertyValue("FilterName", 0, "writer8", 0), PropertyValue("Overwrite", 0, True, 0),)
doc.storeAsURL('file:///tmp/test.odt', properties )
doc.close(True)

Super refactoring! Nice!
Although blue “Lorem ipsum” is still in the foreground. It runs and no errors occur.
I still need the blue texted textframe hide behind black text.

Hallo
Does it work with additional:

#…
from com.sun.star.drawing.FillStyle import NONE as F_NONE
#…

textFrame.BackColorTransparency = 100
textFrame.BackTransparent = True
textFrame.FillTransparence = 100
textFrame.FillStyle = F_NONE
textFrame.FillBackground = False

the »dispatcher…« -lines seems unrelated?

That is not it.
The best way to test it is having textframe textcolor white and then it disappears.
While your answer result drawing into base text “font on font” rendering.
But still thank you for your efforts! :slight_smile:

For clarification: in Writer in the actual Writer gui clicking on the textframe border the right click menu has a menu entry under “wrap” that says “In Background”, that is the thing I am hunting for.

I figured it out! But I still need help!

The problem is with:
dispatcher.executeDispatch(doc.CurrentController.Frame, ".uno:WrapThroughTransparencyToggle", "", 0, ())

This is the wrong “frame”.
I made the following experiment. The original post creates a test.odt, well I continued to edit it after I generated it. I added some text to the base text, then I selected the textframe, changed the background color of the textframe to yellow, while the background color of the base text remained white. All this was recorded as a macro, which is:

rem ----------------------------------------------------------------------
rem define variables
dim document   as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

rem ----------------------------------------------------------------------
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Text"
args1(0).Value = "foo bar baz"

dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args1())

rem ----------------------------------------------------------------------
dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "BackgroundColor"
args2(0).Value = 16776960

dispatcher.executeDispatch(document, ".uno:BackgroundColor", "", 0, args2())


end sub

Next I have undone all these changes and then I ran the macro to see what happens.
Different result (!): the background color of the base text and the background color of the textframe have been both set to yellow.

I beleive:
dispatcher.executeDispatch(document, ".uno:BackgroundColor", "", 0, args2())
should have a different agrument than document to be able to address the textframe as target for .uno:backgroundColor dispatch.

Any idea how to correctly reference the textframe in the dispatch?

So much posting, but I got it! :smiley:

targetframe = doc.TextFrames.getByIndex(0)
doc.CurrentController.select(targetframe)
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
dispatcher.executeDispatch(doc.CurrentController.Frame, ".uno:WrapThroughTransparent", "", 0, ()) 

This poster had something unrelated but quite uneful:

Welcome @dr488 .

I have already written a working example for this.
See Dispatch Commands Example of the Live LibreOffice Python UNO Examples.

In order to run headless set Line 29 to include headless=True

loader = Lo.load_office(Lo.ConnectPipe(headless=True))

See the Lo.ConnectPipe() documentation for more options.
Hope this helps.

See Also: OOO Development Tools - Chapter 4. Listening, and Other Techniques

This whole another level including things I have never heard of (OOO Dev Tools) before.
Thank you for pointing that out!
I need some time time to rework my code.
Thanks a lot!