Using Python with OpenOffice.org - Part 1/3

I wanted to write a modified version of the envelope creation macro described here, thinking that I would use Python to learn the OpenOffice.org API. OpenOffice.org developer documentation is horrible. Written by and for architecture astronauts, it is also not very complete for Python.

Background Reading

These are some useful places to start your education:

Debugging

The talk page tells you where to edit the file to get debugging on Linux. You have to restart OpenOffice to see the logging in the file, which is found by:

find ~/.openoffice* -name log.txt

So far I have found this log file to be utterly useless, even when on DEBUG level. It seems that output does not go there, but if you do not catch exceptions then they come up in OpenOffice dialogues anyway, which is more useful.

So the first task was to be able to do simple error handling and debugging. Initially printf into the document may be useful:

model = XSCRIPTCONTEXT.getDocument()
text = model.Text
cursor = text.createTextCursor()
text.insertString(cursor, "START", 0)
# do stuff
text.insertString(cursor, "END", 0)

Message Boxes

After reading for hours and pasting together from various documentation sources, this seems like a reasonable, modern message box function:

import uno
import traceback
from com.sun.star.awt.MessageBoxButtons import (BUTTONS_OK,
                                                BUTTONS_OK_CANCEL,
                                                BUTTONS_YES_NO,
                                                BUTTONS_YES_NO_CANCEL,
                                                BUTTONS_RETRY_CANCEL,
                                                BUTTONS_ABORT_IGNORE_RETRY,
                                                DEFAULT_BUTTON_OK,
                                                DEFAULT_BUTTON_CANCEL,
                                                DEFAULT_BUTTON_RETRY,
                                                DEFAULT_BUTTON_YES,
                                                DEFAULT_BUTTON_NO,
                                                DEFAULT_BUTTON_IGNORE)

def messageBox(message="", title="", msgtype="messbox", buttons=BUTTONS_OK, parentWin=None, rect=None):
    model = XSCRIPTCONTEXT.getDocument()
    context = XSCRIPTCONTEXT.getComponentContext()
    toolkit = context.ServiceManager.createInstanceWithContext("com.sun.star.awt.Toolkit", context)

    if not parentWin:
        parentWin = model.CurrentController.Frame.ContainerWindow

    if not rect:
        rect = uno.createUnoStruct('com.sun.star.awt.Rectangle') 

    msgtypes = ("messbox", "infobox", "errorbox", "warningbox", "querybox")
    msgtype = msgtype.lower()
    if msgtype not in msgtypes:
        msgtype = "messbox"

    msgbox = toolkit.createMessageBox(parentWin, rect, msgtype, buttons, title, message)

    if msgbox:
        result = msgbox.execute()
        return result
    else:
        raise Exception("Unable to create message box")

Phew. Another option is to make a class, although I don’t like the constant-hacking done in that example. Some key gotchas are that import uno must come first, you cannot import constants directly (or using *), and you must supply a valid parent window.

So now on to getting the address(es) from the document…