Friday, May 8, 2009

Openoffice.org UNO API


OpenOffice.org offers a language independent Application Programming Interface (API) which allows to program the office in different programming languages (e.g. C++, Java, Python, CLI, StarBasic, JavaScript, OLE). It allows us to use OpenOffice.org as service provider in other applications, extend it with new functionality or simply customize and control OpenOffice.org.

The API is based on the UNO component technology and that makes it really flexible and makes it possible to use one and the same API from different programming languages, all languages which are supported by UNO. Uno stands for Universal Network Objects. Uno is the interface based component model of OpenOffice.org. Uno components may be implemented in and accessed from any programming language for which a Uno implementation (AKA language binding) and an appropriate bridge or adapter exists.

Getting started with OpenOffice API and Java


Before you begin you need to install openoffice.org. You also need the following jar files on the class path:
  1. juh.jar
  2. jurt.jar
  3. ridl.jar
  4. unoil.jar

You can find these jar files in the installation directory in the subfolder program/classes. On linux for example a folder similar to /opt/openoffice.org 2.4/program/classes (on OOo 1.x.x and OOo 2.x.x).

The folder structure of OOo 3.0.0 changed a lot. The jars juh.jar, jurt.jar and ridl.jar are available at openoffice.org/ure/share/java
and unoil.jar is available at openoffice.org/basis3.0/program/classes.

You also need the program directory on your class path ( eg: /opt/openoffice.org3/program ), otherwise you’ll get the following error message: com.sun.star.comp.helper.BootstrapException: no office executable found!

First thing to do is to connect to the OpenOffice. They following code will start an instance of OpenOffice.

// Get the remote office component context
XComponentContext xContext = Bootstrap.bootstrap();

// Get the remote office service manager
XMultiComponentFactory xMCF = xContext.getServiceManager();

// Get the root frame (i.e. desktop) of openoffice framework.
Object oDesktop = xMCF.createInstanceWithContext("com.sun.star.frame.Desktop", xContext);

// Desktop has 3 interfaces. The XComponentLoader interface provides ability to load components.
XComponentLoader xCLoader = ( XComponentLoader ) UnoRuntime.queryInterface(XComponentLoader.class, oDesktop);

Now, we have to create an empty document in the new writer window.

// Create a document
XComponent document = xCLoader.loadComponentFromURL("private:factory/swriter", "_blank", 0, new PropertyValue[0]);

// Get the textdocument
XTextDocument aTextDocument = ( XTextDocument )UnoRuntime.queryInterface(com.sun.star.text.XTextDocument.class, document);

// Get its text
XText xText = aTextDocument.getText();

Now i can append my first piece text to the document

// Adding text to document
xText.insertString(xText.getEnd(), "My First OpenOffice Document", false);


Changing Font Styles and size


To set font family, style and size, we should set the property values CharFontName, CharFontStyleName and CharHeight of the XTextRange

XTextRange xTextRange = xText.createTextCursor();
((XTextCursor)xTextRange).gotoEnd(true);

XPropertySet xTextProps = (XPropertySet) UnoRuntime.queryInterface(
XPropertySet.class, xTextRange);
xTextProps.setPropertyValue("CharFontName", "Times New Roman");
xTextProps.setPropertyValue("CharFontStyleName", "Regular");
xTextProps.setPropertyValue("CharHeight", new Float(size));


Creating Table in OpenOffice


To create a table we need to create an instance of XMultiServiceFactory. And also the table ahould be initialize with total rows and columns before it can be inserted into the document

XMultiServiceFactory xMSF = ( XMultiServiceFactory ) UnoRuntime.queryInterface(XMultiServiceFactory.class, document);

// Creating a table with 3 rows and 4 columns
XTextTable xTextTable = ( XTextTable ) UnoRuntime.queryInterface(XTextTable.class, xMSF.createInstance( "com.sun.star.text.TextTable" ) );
xTextTable.initialize( 2, 2); // rows, cols

// insert table in the xText
xText.insertTextContent(xText.getEnd(), xTextTable, false);

Now to add data to the cells in table

XCellRange xCellRangeHeader = (XCellRange) UnoRuntime.queryInterface(XCellRange.class, table);
XCell xCellHeader = null;
XText xHeaderText = null;

xCellHeader = xCellRangeHeader.getCellByPosition(0, 0); // cols, rows
xHeaderText = (XText) UnoRuntime.queryInterface(XText.class, xCellHeader);
xHeaderText.setString("A1");

xCellHeader = xCellRangeHeader.getCellByPosition(1, 0); // cols, rows
xHeaderText = (XText) UnoRuntime.queryInterface(XText.class, xCellHeader);
xHeaderText.setString("A2");

xCellHeader = xCellRangeHeader.getCellByPosition(0, 1); // cols, rows
xHeaderText = (XText) UnoRuntime.queryInterface(XText.class, xCellHeader);
xHeaderText.setString("B1");

xCellHeader = xCellRangeHeader.getCellByPosition(1, 1); // cols, rows
xHeaderText = (XText) UnoRuntime.queryInterface(XText.class, xCellHeader);
xHeaderText.setString("B2");

Paper Formating


The default paper format and orientation is A4 and portrait. To change paper orientation

XPrintable xPrintable = ( XPrintable ) UnoRuntime.queryInterface(XPrintable.class, document);
PropertyValue[] printerDesc = new PropertyValue[2];

// Paper Orientation
printerDesc[0] = new PropertyValue();
printerDesc[0].Name = "PaperOrientation";
printerDesc[0].Value = PaperOrientation.LANDSCAPE;

// Paper Format
printerDesc[1] = new PropertyValue();
printerDesc[1].Name = "PaperFormat";
printerDesc[1].Value = PaperFormat.A3;

xPrintable.setPrinter(printerDesc);

Saving the Document


The final task is to save the document. Here is the code to do that

// the url where the document is to be saved
String storeUrl = “file:///tmp/OOo_doc.odt";

// Save the document
XStorable xStorable = ( XStorable )UnoRuntime.queryInterface(XStorable.class, document);
PropertyValue[] storeProps = new PropertyValue[0];
xStorable.storeAsURL(storeUrl, storeProps);

When you want to export it to PDF, you need to specify a filter name: writer_pdf_Export. Also note that you need to call storeToUrl instead of storeAsUrl, otherwise you’ll get the following exception: com.sun.star.task.ErrorCodeIOException.

// export document to pdf
storeProps = new PropertyValue[1];
storeProps[0] = new PropertyValue();
storeProps[0].Name = "FilterName";
storeProps[0].Value = "writer_pdf_Export";

xStorable.storeToURL(“file:///tmp/OOo_doc.pdf", storeProps);


We can also save the document in other formats by specifying the filter name. For example, to save to rich text format

// the url where the document is to be saved
String storeUrl = “file:///tmp/OOo_doc.rtf ";

// Save the document
XStorable xStorable = ( XStorable )UnoRuntime.queryInterface(XStorable.class, document);
PropertyValue[] storeProps = new PropertyValue[0];
storeProps[0] = new PropertyValue();
storeProps[0].Name = "FilterName";
storeProps[0].Value = "Rich Text Format";

xStorable.storeAsURL(storeUrl, storeProps);

Printing the Document


Of course the document could be send to a printer. Here is the code to do that

XPrintable xPrintable = (XPrintable)UnoRuntime.queryInterface(XPrintable.class, document);
PropertyValue[] printerDesc = new PropertyValue[1];
printerDesc[0] = new PropertyValue();
printerDesc[0].Name = "Name";
printerDesc[0].Value = "PDFCreator";
xPrintable.setPrinter(printerDesc);

PropertyValue[] printOpts = new PropertyValue[1];
printOpts[0] = new PropertyValue();
printOpts[0].Name = "Pages";
printOpts[0].Value = "1";
xPrintable.print(printOpts);

Now we can close the document
// close document
XCloseable xcloseable = (XCloseable) UnoRuntime.queryInterface(XCloseable.class, document);
xcloseable.close(false);

34 comments:

  1. Nice one for a start... hope u add more to this

    ReplyDelete
  2. agree. this is very useful. You could replace about 50 pages of javadoc at openoffice.org. Ever thought of contributing. This is useful stuff.

    Becuase the API is so generic/flexible, the javadoc is writen very generically - which is very difficult to understand. Your blog cuts to the chase. nice work.

    ReplyDelete
  3. Thanks. I would like to ask you for a complete source download and a description of the procedure to compile and run the code. Thanks.

    MRamirez

    ReplyDelete
  4. Nice example. Thanks a lot. I could not find all these in one place. However, close document did not work for my oocalc document. Would like to see oocalc example. Specifically seting row and column attributes.

    ReplyDelete
  5. Very helpful as first steps to OOo programming.
    Cheers

    Alex

    ReplyDelete
  6. very useful. thank you

    ReplyDelete
  7. If anyone is still watching this post. First of all, great post, it allowed me to start programming OOo from Java.

    But I do have a problem, I cannot get the program to run outside of Eclipse - it runs great within Eclipse. I continue to get the om.sun.star.comp.helper.BootstrapException: no office executable found! error when I try to run it outside of Eclipse. I do not know how to get Java to recognize the classpath.

    Rodney

    ReplyDelete
  8. Thanks for this post!
    Writing a PDF converter is always got the error:
    com.sun.star.task.ErrorCodeIOException.
    Thanks to you i found out that i had to change the export call from saveAsURL to saveToURL.
    Is there any known reason you have to change it for PDF?

    ReplyDelete
  9. Hi Rodney,

    If you are still looking for a solution. I had the same problem, know i'm using 'BootStrapConnector'
    You can find more information here:
    http://user.services.openoffice.org/en/forum/viewtopic.php?f=44&t=2520

    ReplyDelete
  10. Good day,

    I'm having a problem with event handling in Open Office, particularly with regards to Key Events.

    Firstly, if anyone has ever wondered how to get it done (I was a bit confused about this, so I thought I might share the one answer that made sense), follow this link to see a simple example of how to add a KeyListener

    http://ashanshare.blogspot.com/2009/11/open-office-extension-development.html

    My problem is this. When I add key event listeners for OOWriter, the text no longer appears in Writer, only the commands in the keyPressed/keyReleased methods are executed. From my limited experience with Java, listeners aren't supposed to interfere with the natural running of the program/application, so it means that I'm doing something wrong. I wanted to post the code here but I noticed no one else has before so I'm asking

    1) IF I can post the code
    2) For help from anyone (would really appreciate it)

    ReplyDelete
  11. This has been the most useful UNO API tutorial I've seen so far. Even better than the OOo documentation. Thank you!

    ReplyDelete
  12. can i convert office documents without install the OpenOffice.org...

    any other conversion doc to pdf can u share...

    asap

    ReplyDelete
  13. non English character are not displaying on linux platform(Cent Os 5)

    ReplyDelete
  14. Thanks for this. OpenOffice is huge, and the API is very complex. There is a real shortage of example code. The snippets are often not complete enough to get a working method up and going fast. As a developer, I'm under the gun and I don't really have time for hacking my way into opaque interfaces anymore. So I appreciate your contribution here. Thanks :)

    ReplyDelete
  15. Nice post..It would be very useful if you post the entire source code also.

    ReplyDelete
  16. Hello,

    can you please print the complete code and how to compile it?

    Thanks in advance!!

    ReplyDelete
  17. This comment has been removed by the author.

    ReplyDelete
  18. Nice work, UNO is a great piece of software
    regards

    ReplyDelete
  19. How to edit the existing word document using this api.

    ReplyDelete
  20. I had following error:

    java.lang.UnsatisfiedLinkError: jpipe (Not found in java.library.path)

    Fixed it by added \URE\bin to path, in my case:

    JavaUserClasses=c:\Progra~1\OpenOf~1.org\program;c:\Progra~1\OpenOf~1.org\URE\bin

    ReplyDelete
  21. it works!!!! wonderful!

    ReplyDelete
  22. Do you know how to open Writer inside a form?

    ReplyDelete
  23. Awesome tutorial... I am trying to create a new theme and add images to it... Can you help me with that??... thanks in advance...

    ReplyDelete
  24. Most useful, but I have a problem with printing, my java application does not terminate as it should, and the Open office Writer instance no longer responds ans refuses to close (I am running Windows 7 with eclipse and jre7).

    Any hint ?

    ReplyDelete
  25. Please tell me how to add a string to the OO calc document after the cell A5.
    I am sorry for my english.

    ReplyDelete
  26. Yes. It work. I hope you write another UNO sample. Thks

    ReplyDelete
  27. Thanks a lot ,it helped me to create pdf with hindi font...Where can I find more examples...Hope you will write more examples for Using UNO specially for PDF creation.

    ReplyDelete
  28. I tried implementing your solution, but it doesn't work for me. I suppose it could be due to jar files (incorrect versions). So, it would be great if you could let us know the versions of the following jars.
    juh.jar
    jurt.jar
    ridl.jar
    unoil.jar

    I got an error while trying to retrieve the remote office component context.

    Exception in thread "main" java.lang.NoSuchMethodError: com.sun.star.loader.CannotActivateFactoryException.(Ljava/lang/Throwable;Ljava/lang/String;)V
    at com.sun.star.comp.loader.JavaLoader.activate(JavaLoader.java:331)
    at com.sun.star.comp.helper.Bootstrap.createInitialComponentContext(Bootstrap.java:108)
    at com.sun.star.comp.helper.Bootstrap.bootstrap(Bootstrap.java:227)

    ReplyDelete
    Replies
    1. hey , try this : http://user.services.openoffice.org/en/forum/viewtopic.php?f=44&t=2520

      Delete
  29. Your article is too good and informative.Keep writing and sharing educational article like this which can help us to grow our knowledge.

    JAVA Training In Pune

    ReplyDelete
  30. I recently came across your article and have been reading along. I want to express my admiration of your writing skill and ability to make readers read from the beginning to the end.
    Java Classes in Pune

    ReplyDelete