Other Articles‎ > ‎

Getting Started with Components of OpenOffice

As I stare at the screen in front of me, I am overwhelmed. Around 30 megabytes of documentation related to OpenOffice SDK and random browsing shows an amazing wealth of operations and methods available. The examples are predominantly in Java and the usage is complex. Python makes it much easier to use Open Office though getting started is intimidating. I used the beta version of Open Office for my exploration and verified the sample code on the current version as well.

Our aim for this article is to explore enough to convince you that programming OpenOffice through Python is worth pursuing and make the documentation a little more accessible.

When we work with spreadsheets or documents, we do not worry about the data types. We do not declare that a particular cell contains a number, a date or a string. In fact, a great part of the complexity of programming office suites from most languages stems from the data typing constraints of the traditional languages. Python with dynamic typing frees us from those rigidities.

PyUNO, the Python bindings for UNO, are distributed with OpenOffice. UNO is the components model used by OpenOffice, similar to but not identical to COM or CORBA. UNO can interoperate with COM and the work on interoperability with CORBA is in progress. Unfortunately, OpenOffice includes the Python interpreter as well. So, the Python version we will be using is the one which comes with OpenOffice. (Hopefully, this is a temporary phenomenon and in future, PyUNO will be a module which works with the standard Python distribution. In fact, this may be an opportunity for someone among the readers.)

Getting Started

We will need to start OpenOffice with an accept option so that it will take requests from a tcp socket. The port number may be different and on some distributions, the command will be soffice and not ooffice.

$ ooffice '-accept=socket,host=localhost,port=2002;urp;”

This will start up the application as well as enable UNO server to listen on port 2002. We will start the Python interpreter included with OpenOffice, assuming that OpenOffice is installed in /usr/lib/ooo-1.1, as in FC3:

$ /usr/lib/ooo-1.1/program/python

The first step will be to import the module and connect to UNO. (Make sure there are no spaces in the url, 'uno:socket...ComponentContext'.)

>>> import uno

>>> def ConnectOO(host, port):

>>> localContext = uno.getComponentContext()

>>> resolver =
'com.sun.star.bridge.UnoUrlResolver', localContext)

>>> ctx = resolver.resolve('uno:socket,host=' + host + ',
port=' + port + ';urp;StarOffice.ComponentContext')

>>> return ctx.ServiceManager

>>> smgr = ConnectOO('localhost', '2002')

Once we have the service manager object, we can create an instance of the desktop and open a new text document.

>>> desktop = smgr.createInstance('com.sun.star.frame.Desktop')

>>> document = desktop.loadComponentFromURL(
'private:factory/swriter','_blank', 0, ( ))

It is worth looking at the corresponding code from the Java example taken from the FAQ of http://udk.openoffice.org/python/python-bridge.html

oInterface = (XInterface) smgr.createInstance("com.sun.star.frame.Desktop" );

oCLoader = ( XComponentLoader ) UnoRuntime.queryInterface(

XComponentLoader.class, oInterface );

PropertyValue [] szEmptyArgs = new PropertyValue [0];

aDoc = oCLoader.loadComponentFromURL(

"private:factory/swriter" , "_blank", 0, szEmptyArgs );

Python does not require queryInterface calls. It makes the code far more readable. The above rule also makes it fairly easy to translate the Java examples in the documentation to Python.

OpenOffice will now have created an empty text document. To create an empty spreadsheet, we need to replace “private:factory/swriter” by “private:factory/scalc”. Needless to add, we could have created a presentation or a drawing as well.

Working with Text

Let us enter a line of text in it. We will need the text object and a cursor as well.

>>> text = document.getText()

>>> cursor = text.createTextCursor()

>>> text.insertString(cursor, 'The very first line', False)

The text should be visible. Had we ended the line with a '\n', the cursor would have moved on to the next line. But we would like to insert a new paragraph.

>>> from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK

>>> text.insertControlCharacter( cursor, PARAGRAPH_BREAK, False )

Java examples often use expressions like com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK directly. In Python, we need to use the above syntax.

We will now read lines from “test.txt”, a text file, and insert them as a single paragraph. Obviously, this code could be as complex as you need. (The 3rd parameter in insert text has to do with whether to replace/delete the text selected by the cursor and will normally be False.)

>>> for line in open('test.txt'):

...    text.insertString(cursor, line[:-1] + ' ', False)
# :-1 to skip the EOL character

>>> text.insertControlCharacter( cursor, PARAGRAPH_BREAK, False )
As a small example of controlling the way the text looks, we use the setPropertyValue to control the colour of the text and create the shadowing effect.
>>> cursor.setPropertyValue('CharColor',255)

>>> cursor.setPropertyValue('CharShadowed',True)

>>> text.insertString(cursor,'That is Blue, folks' + '\n', False)

>>> cursor.setPropertyValue('CharColor',255*256)

>>> text.insertString(cursor,'That is Green, folks' + '\n', False)

>>> cursor.setPropertyValue('CharColor',255*256*256)

>>> text.insertString(cursor,'That is Red, folks' + '\n', False)

Working with a Table

Now, for something different. Let us create and insert a table with 6 rows and 4 columns. And we program the population of cells.

>>> table=document.createInstance('com.sun.star.text.TextTable')

>>> table.initialize(6,4)

>>> text.insertTextContent(cursor, table, False)

We now enter the headers using a dictionary. Note that for inserting text values, we need to create a cursor for a cell as well, which we do in a helper function, insertIntoCell.

>>> def insertIntoCell(cellName, str, table):

...    cell = table.getCellByName(cellName)

...    cellCursor = cell.createTextCursor()

...    cell.insertString(cellCursor, str, False)

>>> def insertHeaders(hdrs):

...    for cellName in hdrs:

...       insertIntoCell(cellName, hdrs[cellName], table)

>>> insertHeaders({'A1':'Physics', 'B1':'Maths', 'C1':'Chemistry',

We will now insert values into each row. We will create the marks using random numbers and the last column will be a function which sums the first three columns, e.g. 'sum <A2:C2>'.

>>> def insertRow(n, listVal):

...    Cols = ['A', 'B', 'C']

...    Row = str(n)

...    for i in range(3):

...       table.getCellByName(Cols[i] + Row).setValue(listVal[i])

...       table.getCellByName('D' + Row).setFormula('sum <A' +
Row + ':C' + Row + '>')

>>> import random

>>> for i in range(5):

...    insertRow(i+1, [int(100*random.random()) for j in range(3)])
Saving and Loading a File

Finally, you may wish to save your work

>>> document.storeAsURL('file://~/work.sxw',())

To opening a pre-existing file, just assign the appropriate value to the url. Note that 'file://' is the protocol and '~/work.sxw' is the file in the home directory as.

>>> document = desktop.loadComponentFromURL(
"file://~/work.sxw", '_blank', 0, ( ))
For Further Information

Incredible amount of information is available as a part of the Developers Guide in OpenOffice.org SDK. The documentation is oriented towards usage through Java but it is not difficult to use the ideas in Python. Information about Python UNO is available at http://udk.openoffice.org/python/python-bridge.html.

Macros extend the office suites from within. Many of the same ideas are usable for programmatic control of office suites as well. Often recording a macro and looking at the code is the easiest way to learn the syntax for a particular step. You can explore macros further at http://www.ooomacros.org.

We hope that this has wet your appetite for more and that programming OpenOffice can become an element in you repertoire of tools you use to offer solutions. Whenever customer interaction is involved, carefully crafted, customised documents can be the crucial item which differentiates you from the competitors.

Hopefully, your program will avoid the absurd line that “This form is computer generated, hence, does not require any signature”. Hardly a statement to make the client feel comfortable and warm towards the sender. And I hope that you will not send letters addressed to Meena NoData Seth. I suppose that bothers me more because my wife uses Anil as her middle name, so it is I who has been mapped to NoData - not quite good customer service.