Paste html content using API

Hello

Hope some can help me here

Here is my problem

We are developing our software using the uno api python

We re trying to copy a string formatted in html in a libreoffice odt

We manage to do it but using dispatcher
The problem is that dispatcher not working in headless mode so il force us to use a xserver (xvfb) et Xclip.

It work but it’s far from being optimized.

here is the code lotemplate/classes.py at html_formatting · Probesys/lotemplate · GitHub line 349-355

We have try using XTransferable but without any success.

Thanks in advance for your help

Hi,

this is a workaround. It stores the html into a temporary doc, and then imports this doc into the target doc.
It should also work with the target doc in hidden mode

Good luck,

ms777

sub TestInsertHTML
s = ""
s = s & "<P></P>" 
s = s & "<P>Paragraph1</P>" 
s = s & "Hello from ms777" 
s = s & "<b>Bold</b>" 
s = s & "<H1>Header 1</H1>" 
s = s & "<P>Paragraph2</P>" 
s = s & "<CENTER>Center</CENTER>" 
s = s & "<TABLE>"
s = s & "<TR><TD bgcolor=#336699>Cell 1</TD><TD bgcolor=#663399>Cell 2</TD></TR>"
s = s & "<TR><TD bgcolor=#123456>the third cell</TD><TD bgcolor=#654321>Cell 4</TD></TR>"
s = s & "</TABLE>"

oDoc   = StarDesktop.LoadComponentFromUrl("private:factory/swriter","_default",0,Array())

call InsertHTML2Writer(oDoc, s)
end sub

sub InsertHTML2Writer(oDoc as Object, sHTML as String)
'oDoc contains the writer document, into which we want to insert the HTML
oContr = oDoc.CurrentController

'create a temporary storage
oStorageFac = createUnoService("com.sun.star.embed.StorageFactory")
oStorage    = oStorageFac.createInstance
oStream     = oStorage.openStreamElement("ms777", com.sun.star.embed.ElementModes.READWRITE)

'now write the HTML String to the stream
oTextOutputStream = createUNOService ("com.sun.star.io.TextOutputStream") 
oTextOutputStream.setOutputStream(oStream)
oTextOutputStream.writeString(sHTML)

'create the to-be-inserted doc (=doc1) from the stream
Dim aProps(2) as new com.sun.star.beans.PropertyValue
aProps(0).Name  = "FilterName"
aProps(0).Value = "HTML (StarWriter)"
aProps(1).Name  = "InputStream"
aProps(1).Value = oStream
aProps(2).Name  = "Hidden"
aProps(2).Value = true
oDoc1 = StarDesktop.loadComponentFromURL("private:stream", "_default", 0, aProps) 

'select all of doc1
oContr1 = oDoc1.CurrentController 
oVC1 = oContr1.ViewCursor
oVC1.gotoStart(false)
oVC1.gotoEnd(true)

'insert the selection of doc1 into doc
'note that it is not necessary to involve the clipboard
'for copying
oContr.insertTransferable(oContr1.Transferable)
oDoc1.close(true)

'redraw the ComponentWindow, because sometimes the changes are not
'immediately reflected
oCompWin = oContr.Frame.ComponentWindow
with com.sun.star.awt.InvalidateStyle 
  oCompWin.invalidate(.CHILDREN+.UPDATE+.NOCLIPCHILDREN)
  end with

End Sub

1 Like

@ms777, maybe additionally use insertDocumentFromURL ?

@sokol92, you are right. And the code gets a bit shorter. Now in python:

import uno
from subprocess import Popen

from com.sun.star.beans import PropertyValue # type:ignore

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

lo_proc = Popen('"C:\Program Files\LibreOffice\program\soffice.exe" -accept=socket,host=localhost,port=2002;urp;', shell=True)
ctx = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" )

smgr = ctx.ServiceManager
desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx)
doc = desktop.loadComponentFromURL('private:factory/swriter', '_default', 0, ())

sHtml = """<P></P>
<P>Paragraph1</P> 
Hello from ms777
<b>Bold</b>
<H1>Header 1</H1>
<P>Paragraph2</P>
<CENTER>Center</CENTER>
<TABLE>
<TR><TD bgcolor=#336699>Cell 1</TD><TD bgcolor=#663399>Cell 2</TD></TR>
<TR><TD bgcolor=#123456>the third cell</TD><TD bgcolor=#654321>Cell 4</TD></TR>
</TABLE>"""


def xray(target):
    global ctx
    mspf = ctx.ServiceManager.createInstanceWithContext("com.sun.star.script.provider.MasterScriptProviderFactory", ctx)
    script_provider = mspf.createScriptProvider("")
    script = script_provider.getScript("vnd.sun.star.script:XrayTool._Main.Xray?language=Basic&location=application")
    script.invoke((target,), (), ())

def InsertHtml2Odt_1(sHTML, doc):
#create a temporary storage
    oStorageFac = ctx.ServiceManager.createInstanceWithContext("com.sun.star.embed.StorageFactory", ctx)
    oStorage    = oStorageFac.createInstance()
    oStream     = oStorage.openStreamElement("ms777", uno.getConstantByName("com.sun.star.embed.ElementModes.READWRITE"))

#now write the HTML String to the stream
    oTextOutputStream = ctx.ServiceManager.createInstanceWithContext("com.sun.star.io.TextOutputStream", ctx) 
    oTextOutputStream.setOutputStream(oStream)
    oTextOutputStream.writeString(sHTML)

    prop1 = PropertyValue()
    prop1.Name  = "FilterName"
    prop1.Value = "HTML (StarWriter)"
    prop2 = PropertyValue()
    prop2.Name = "InputStream" 
    prop2.Value = oStream
    prop3 = PropertyValue()
    prop3.Name = "Hidden" 
    prop3.Value = False

    oDoc1 = desktop.loadComponentFromURL("private:stream", "_default", 0, (prop1, prop2, prop3)) 

    oContr1 = oDoc1.CurrentController 
    oVC1 = oContr1.ViewCursor
    oVC1.gotoStart(False)
    oVC1.gotoEnd(True)

#insert the selection of doc1 into doc
#note that it is not necessary to involve the clipboard
#for copying
    doc.CurrentController.insertTransferable(oContr1.Transferable)
    oDoc1.close(True)

def InsertHtml2Odt_2(sHTML, doc):
#create a temporary storage
    oStorageFac = ctx.ServiceManager.createInstanceWithContext("com.sun.star.embed.StorageFactory", ctx)
    oStorage    = oStorageFac.createInstance()
    oStream     = oStorage.openStreamElement("ms777", uno.getConstantByName("com.sun.star.embed.ElementModes.READWRITE"))

#now write the HTML String to the stream
    oTextOutputStream = ctx.ServiceManager.createInstanceWithContext("com.sun.star.io.TextOutputStream", ctx) 
    oTextOutputStream.setOutputStream(oStream)
    oTextOutputStream.writeString(sHTML)

    prop1 = PropertyValue()
    prop1.Name  = "FilterName"
    prop1.Value = "HTML (StarWriter)"
    prop2 = PropertyValue()
    prop2.Name = "InputStream" 
    prop2.Value = oStream
    
    doc.Text.createTextCursor().insertDocumentFromURL("private:stream", (prop1, prop2))

#InsertHtml2Odt_1(sHtml, doc)
InsertHtml2Odt_2(sHtml, doc)

1 Like

… and again a bit shorter:

def InsertHtml2Odt_3(sHTML, doc):
    oStream = ctx.ServiceManager.createInstanceWithContext("com.sun.star.io.SequenceInputStream", ctx)
    oStream.initialize((uno.ByteSequence(sHTML.encode()),))

    prop1 = PropertyValue()
    prop1.Name  = "FilterName"
    prop1.Value = "HTML (StarWriter)"
    prop2 = PropertyValue()
    prop2.Name = "InputStream" 
    prop2.Value = oStream
    
    doc.Text.createTextCursor().insertDocumentFromURL("private:stream", (prop1, prop2))
2 Likes

@ms777 please avoid to post the whole boilerplate-code to run and connect soffice from »outside«

And half of the boilerplate you dont need in the future if you… ( ! close Libreoffice before ! )…open your »registrymodifications.xcu« with your favourite texteditor and insert somewhere between </item> and <item:

<item oor:path="/org.openoffice.Setup/Office">
<prop oor:name="ooSetupConnectionURL" oor:op="fuse">
<value>pipe,name=name_of_your_choice;urp;StarOffice.ServiceManager"</value></prop></item>

remove linebreaks!
so the first part for starting Libreoffice is omitted, that is:

#from subprocess import Popen # obsolete
#↓↓↓obsolete
#lo_proc = Popen('"C:\Program Files\LibreOffice\program\soffice.exe" -accept=socket,host=localhost,port=2002;urp;', shell=True)


##but changed:
PIPENAME = 'name_of_your_choice'

local = uno.getComponentContext()
resolver = local.ServiceManager.createInstance("com.sun.star.bridge.UnoUrlResolver")

ctx = resolver.resolve( "uno:pipe,"
                           f"name={PIPENAME};"
                           "urp;"
                           "StarOffice.ComponentContext")

createUnoService = ctx.ServiceManager.createInstance

@ms777 Thanks a lot for this solution ! it works great in my project !