Python (pyuno) "Hello World" Addon for OpenOffice
February 6th, 2009 by Mitch Frazier in
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:
If you select the option the add-on should modify the spreadsheet and you should now have:
If you select the option again you should get:
__________________________
Mitch Frazier is an Associate Editor for Linux Journal and the Web Editor for linuxjournal.com.
| Attachment | Size |
|---|---|
| addon-menu.jpg | 55.07 KB |
| addon-exec1.jpg | 8.36 KB |
| addon-exec2.jpg | 8.45 KB |
| addon-code.zip | 3 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.
Subscribe now!
The Latest
Newsletter
Tech Tip Videos
- Nov-19-09
- Nov-04-09
Recently Popular
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.
Delicious
Digg
StumbleUpon
Reddit
Facebook








$unopkg_bin remove
On May 18th, 2009 piR (not verified) says:
$unopkg_bin remove $zip_filedoesn't work, because you need to give the id of the add-on, not the file
example
unopkg add ImpressRunner-1.0.oxtunopkg remove org.openoffice.legacy.ImpressRunner-1.0.oxt
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!
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.
Is it too complex or just unfamiliar?
On February 9th, 2009 Mitch Frazier says:
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:
pretty simple, right? So, what did it take to get there:
Not so easy after all.
__________________________Mitch Frazier is an Associate Editor for Linux Journal and the Web Editor for linuxjournal.com.
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.
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.
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.
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...
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.
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