Python (pyuno) "Hello World" Addon for OpenOffice

February 6th, 2009 by Mitch Frazier in

Your rating: None Average: 4.7 (10 votes)

In my last few posts about pyuno (SSConverter, OORunner) we used pyuno to convert spreadsheets to CSV files by running OpenOffice from Python using pyuno as the bridge between the two processes. In this post we're going to get inside OpenOffice and use pyuno as the bridge between OpenOffice and an embedded Python interpreter (embedded inside OpenOffice).

As is the law, our first program when doing something new has to be a "Hello World" program. The idea here is to add an option to the OpenOffice menu which will insert "Hello World" into the first cell of a spreadsheet. As a starting point for this example I used an example from the pyuno udk site (the second "Hello World" example on the page).

The example there does essentially the same thing as the example here except there it inserts "Hello World" into a Writer (Word Processor) document rather than a spreadsheet. One would assume that it would be a fairly easy conversion, and once I knew the answer it was. The hard part was figuring out how to get the "spreadsheet" object and then how to get a "cell" object from it. And it wasn't so much hard as just time consuming trying to find the right information in the documentation.

After a few hours of searching and a few false starts I came across the two needed interfaces: XSpreadsheetDocument and XCell. These gave me what I needed to modify the example to work with a spreadsheet:

 1 import uno
 2 import unohelper
 3 
 4 from com.sun.star.task import XJobExecutor
 5 
 6 # Implement an UNO component by deriving from the standard
 7 # unohelper.Base class and from the interface(s) you want to implement.
 8 class HelloWorldJob(unohelper.Base, XJobExecutor):
 9     def __init__(self, ctx):
10         # store the component context for later use
11         self.ctx = ctx
12 
13     def trigger(self, args):
14         # Retrieve the desktop object
15         desktop = self.ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", self.ctx)
16 
17         # Get the spreadsheet.
18         spreadsheet = desktop.getCurrentComponent()
19 
20         # Get the collection of sheets in the spreadsheet.
21         sheets = spreadsheet.getSheets()
22 
23         # Get the first cell in the first sheet.
24         cell = sheets.getByIndex(0).getCellByPosition(0, 0)
25 
26         # Modify its contents.
27         if cell.getFormula():
28             cell.setFormula("Hello " + cell.getFormula())
29         else:
30             cell.setFormula("Hello world")
31 
32 
33 # pythonloader looks for a static g_ImplementationHelper variable
34 g_ImplementationHelper = unohelper.ImplementationHelper()
35 
36 g_ImplementationHelper.addImplementation( \
37         HelloWorldJob,                                # UNO object class
38         "org.openoffice.comp.pyuno.demo.HelloWorld",  # Implementation name
39         ("com.sun.star.task.Job",),)                  # List of implemented services

The meat of the example is the trigger method of the HelloWorldJob class. This method is called when the add-on is invoked. Trigger performs the following steps:

  • It gets the top-level desktop object.
  • From the desktop object it gets the current component. The current component in this case is a SpreadsheetDocument.
  • From the spreadsheet object it gets the collection of all the sheets in the spreadsheet.
  • From the sheets collection it gets the first sheet and then the first Cell from that sheet.
  • Using the cell, if the cell is empty it inserts "Hello World". If the sheet contains something then it prefixes the old contents with "Hello ".

The rest of the code is essentially a copy of the code from the original example.

Now that we have the code we need to integrate it into OpenOffice. We do that by creating a zip file of the code and a XML file that describes the add-on. The XML file is, again, essentially just a copy from the original example:

<?xml version="1.0" encoding="UTF-8"?>
<oor:node xmlns:oor="http://openoffice.org/2001/registry"
             xmlns:xs="http://www.w3.org/2001/XMLSchema"
             oor:name="Addons" oor:package="org.openoffice.Office">
  <node oor:name="AddonUI">
    <node oor:name="AddonMenu">
      <node oor:name="org.openoffice.comp.pyuno.demo.HelloWorld" oor:op="replace">
        <prop oor:name="URL" oor:type="xs:string">
          <value>service:org.openoffice.comp.pyuno.demo.HelloWorld?insert</value>
        </prop>
        <prop oor:name="ImageIdentifier" oor:type="xs:string">
          <value>private:image/3216</value>
        </prop>
        <prop oor:name="Title" oor:type="xs:string">
          <value xml:lang="en-US">Insert Hello World</value>
        </prop>
      </node>
    </node>
  </node>
</oor:node>

In addition to creating the zip file containing these two files you need to run unopkg to register the add-on with OpenOffice. The following bash script does the zipping and the packaging and then runs OpenOffice so that you can test it:

#!/bin/bash

unopkg_bin=/usr/bin/unopkg
oocalc_bin=/usr/bin/oocalc

addons=Addons.xcu
python_file=hello_world_oocalc.py
zip_file=hello_world.zip

rm $zip_file
zip $zip_file $addons $python_file
$unopkg_bin remove $zip_file
$unopkg_bin add $zip_file

#export PYUNO_LOGLEVEL=CALL
export PYUNO_LOGLEVEL=ARGS
export PYUNO_LOGTARGET=stdout

$oocalc_bin

When you run the script it will start OpenOffice and you should see the following option in the "Tools" menu:

addon-menu.jpg

If you select the option the add-on should modify the spreadsheet and you should now have:

addon-exec1.jpg

If you select the option again you should get:

addon-exec2.jpg __________________________

Mitch Frazier is an Associate Editor for Linux Journal and the Web Editor for linuxjournal.com.

AttachmentSize
addon-menu.jpg55.07 KB
addon-exec1.jpg8.36 KB
addon-exec2.jpg8.45 KB
addon-code.zip3 KB


Special Magazine Offer -- Free Gift with Subscription
Receive a free digital copy of Linux Journal's System Administration Special Edition as well as instant online access to current and past issues. CLICK HERE for offer

Linux Journal: delivering readers the advice and inspiration they need to get the most out of their Linux systems since 1994.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
piR's picture

$unopkg_bin remove

On May 18th, 2009 piR (not verified) says:

$unopkg_bin remove $zip_file
doesn't work, because you need to give the id of the add-on, not the file

example
unopkg add ImpressRunner-1.0.oxt
unopkg remove org.openoffice.legacy.ImpressRunner-1.0.oxt

Justin Mitchell's picture

Fun...

On March 21st, 2009 Justin Mitchell (not verified) says:

I never thought that using Excel's COM interface could be easier than using OO/Python!

John Fabiani's picture

Need more articles on using uno from python

On February 10th, 2009 John Fabiani (not verified) says:

Yes using UNO is like pulling teeth - it hurts. I don't see SUN doing anything about it. So we need more articles using python to simplify the process. Soon we will have better classes that will be easier to use. Keep up the good work.

Assuming you've never done it before: quick write a pyGTK or pyQt "Hello World" application. Takes a fair bit of study and work to get those going the first time also. And that's true of almost any "useful" development tool these days.

And remember what UNO is: a language independent interface to OpenOffice. Its language independent nature pretty much assures that it won't be super Pythonic. And the size and complexity of OpenOffice pretty much assures it won't be small or simple.

That's not to say that improvements can't be made, that's why there are libraries and other forms of abstraction: to hide the details. Take Python for instance, this is "Hello World" in Python:

  print "Hello world"

pretty simple, right? So, what did it take to get there:

  • Write a Python interpreter
  • Write a C compiler to compile the Python interpreter
  • Write an assembler to assemble the C compiler
  • Write an operating system to run the assembler
  • Create semi-conductors to create the computer
  • Create binary numbers

Not so easy after all.

__________________________

Mitch Frazier is an Associate Editor for Linux Journal and the Web Editor for linuxjournal.com.

geoff_f's picture

Uno is gibberish as well

On February 8th, 2009 geoff_f (not verified) says:

Sun isn't going to set the programming world on fire if it persists with using gibberish as its language. Uno suffers from the same problems as Java: too much extraneous input that the application should know about. Also, why should I have to declare the variable type with every use? I have a computer; can't it keep track of what types of variables are used?

In this case, the spreadsheet application should know it's a spreadsheet application. It should know what desktop it's running on. Why should the programmer have to specify something that's already known? So, the code returning the 'desktop' and 'spreadsheet' objects is superfluous.

What's wrong with:

sheet=Sheets("Name-of-Sheet")
(The spreadsheet should know the name of the sheets it contains)

sheet.cell(Col, Row).Value = "Hello World"

It should be that simple. Much more work needs to be done by the computer to ease the load of the programmer. Otherwise, 'OOo Basic' is a misnomer. This is why users who rely on macros shun OOo.

Anonymous's picture

oh my goodness that's hard...

On February 8th, 2009 Anonymous (not verified) says:

It's really great to see an article that pulls it all together.
I had looked at it, and gotten hopelessly confused, so this article is really helpful... On the other hand, this example is so ridiculously complicated, that it is an existence proof of why openoffice has difficulty attracting people to work on it. It really needs to be easier than this.

Anonymous's picture

Re: Comparison

On February 7th, 2009 Anonymous (not verified) says:

@Xan: you can do the same in OOs with OOBasic. The target is is different, it's not casual users but extension developers. No point comparing oranges and apples.

Xan's picture

Comparison

On February 6th, 2009 Xan (not verified) says:

Compare this to MS Excel. Click record macro, type "hello world" in cell A1. Click stop recording macro. Done.
All that xml gibberish? WTF? How can you possibly port all the Excel VBA cruft that every office has and is reliant on if this is the best that can be done for "Hello World" Seriously. We don't need automagic conversion of macros just something at least half way sane, this nonsense, 5 years after I last looked at it, still just isn't even close. Sun could even build a sane scripting interface to OOo and, gasp, sell it. The market exists...

Anonymous's picture

OpenOffice has macros too

On February 7th, 2009 Anonymous (not verified) says:

Open Office also has a "one click macro recorder". The point of the article is to introduce what is involved in using python with OOo, not to type "Hello World" in A1.

Anonymous's picture

The problem of OOo

On February 8th, 2009 Anonymous (not verified) says:

The problem of OOo macro-recorder, that its output is not readily editable.

Average M$O user normally records macro and then adjust it to their needs. Most common use of macros (regardless of what many developers believe) is to access some exotic function/formatting/style. Higher level automation comes much later.

Also note that OOo macro-recorder doesn't record all things. Can't recall precisely what was missing, on most occasions I have tried to do anything to OOo macro-recorder, it missed many things. Since then I have it labeled as "useless" and do not try it anymore.

Post new comment

Please note that comments may not appear immediately, so there is no need to repost your comment.
The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <pre> <ul> <ol> <li> <dl> <dt> <dd> <i> <b>
  • Lines and paragraphs break automatically.

More information about formatting options

Newsletter

Each week Linux Journal editors will tell you what's hot in the world of Linux. You will receive late breaking news, technical tips and tricks, and links to in-depth stories featured on www.linuxjournal.com.
Sign up for our Email Newsletter

Tech Tip Videos

From the Magazine

December 2009, #188

If last month's Infrastrucuture issue was too "big" for you then try on this month's Embedded issue. Find out how to use Player for programming mobile robots, build a humidity controller for your root cellar, find out how to reduce the boot time of your embedded system, and if you're new to embedded systems find out the basics that go into one. You can also read about the Beagle Board, the Mesh Potato and a spate of other interestingly named items. And along with our regular columns don't miss our new monthly column: Economy Size Geek.







Read this issue