Geertjan's Blog

  • June 22, 2006

OpenOffice.org API (Part 3)

Geertjan Wielenga
Product Manager
The next steps in my OpenOffice.org generation function are to (a) set the background color of the header cells, (b) set the background color of every other row (for scanability), and, finally, (c) set the color and width of the borders of the cells in the table. Here's the result:

By the way, this blog entry also describes, maybe even more interestingly, how to get the content of a Swing jTable into a text table in the OpenOffice.org Writer document.

This is all made possible by my createExampleTable(xTextDocument) method, which is called in the last line of the Report button's ActionPerformed event (see OpenOffice.org API (Part 1), if you're interested in that event). Here's the createExampleTable(xTextDocument) method, which includes all the code for creating and formatting the "Contacts Report" header, which I discussed in yesterday's blog entry. Virtually every line below is commented within the code. The main parts of this method, in relation to the creation of the table, are highlighted:

private XTextTable createExampleTable(XTextDocument xTextDocument)
throws UnknownPropertyException, PropertyVetoException,
WrappedTargetException, com.sun.star.uno.Exception {
//Document's internal service manager:
com.sun.star.lang.XMultiServiceFactory xDocMSF =
(com.sun.star.lang.XMultiServiceFactory) UnoRuntime.queryInterface(
com.sun.star.lang.XMultiServiceFactory.class, xTextDocument);
//Order a new table from the internal service manager:XTextTable xTable = (XTextTable) UnoRuntime.queryInterface(XTextTable.class,

//Initialize the text table with 3 columns and as many rows as records in database.
//Remember to add one row, because OpenOffice.org API creates a row for the header:int rows = rowSetTableModel1.getRowCount() + 1;

XText xText = xTextDocument.getText();
//Create a text cursor for selecting and formatting:
xTCursor = xText.createTextCursor();
//Create a property set for the cursor:
XPropertySet xCursorProps = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xTCursor);
//Select 15 characters, which is the length of "Contacts Report":
xTCursor.goRight((short)15, true);
xCursorProps.setPropertyValue("CharPosture", com.sun.star.awt.FontSlant.ITALIC);
xCursorProps.setPropertyValue("CharWeight", new Float(com.sun.star.awt.FontWeight.BOLD));
xCursorProps.setPropertyValue("CharHeight", 20);
//Blue is 255, White is 16777215, Black is 65536
xCursorProps.setPropertyValue("CharColor", 255);
xCursorProps.setPropertyValue("CharShadowed", true);
//Create text in the Writer document:
xText.setString("\\t\\t\\t\\t\\tContacts Report\\n");
//Insert the table into the Writer document.
//The method expects xTextContent, which is inherited by xTextTable:xText.insertTextContent(xTCursor, xTable, false);
//Set the text (and text color) of all the cells in the first row of the table (the header):insertHeadersIntoCell("A1", "Nick Name", xTable);
insertHeadersIntoCell("B1", "First Name", xTable);
insertHeadersIntoCell("C1", "Last Name", xTable);

//Get the value of the selected cell (the cell is selected automatically, as explained later below)
//and assign it to a variable, depending on the column in which it is found.
//This is within a for loop, so that each row will be traversed, with each cell in each row
//being assigned to a variable.
//The variable, together with a number for the current iteration, is sent to a method that
//assigns a letter, representing the column (either A, B, or C) to the variable.
//Then the value is assigned to the column represented by the letter A, B, or C,
//together with the position. For example, A1 or C7 or B9, etc.for (int i = 0; i < rowSetTableModel1.getRowCount(); i++) {
int position = 2 + i;
selectedValue = (String) jTable1.getValueAt(jTable1.getSelectedRow(),jTable1.getSelectedColumn());
firstNextToSelectedCell = (String) jTable1.getValueAt(jTable1.getSelectedRow(),1);
secondNextToSelectedCell = (String) jTable1.getValueAt(jTable1.getSelectedRow(),2);
insertValuesIntoCell(selectedValue, firstNextToSelectedCell, secondNextToSelectedCell, position, xTable);

return xTable;

The key line in the method above is this one near the end:

selectedValue = (String) jTable1.getValueAt(jTable1.getSelectedRow(),jTable1.getSelectedColumn());

Here, we set the currently selected column and row as the starting point. Importantly, we also get the values in the cell. And for that reason this is added to the ActionPerformed event:

//Here we select the first cell in the table,
//just so that we have a starting point, so that we know for
//sure where we are when the createExampleTable() method assigns
//each cell to a variable, which is later mapped to a column letter:
int col = 0;
int row = 0;
boolean toggle = false;
boolean extend = true;
jTable1.changeSelection(row, col, toggle, extend);

The above ensures that when the Report button is clicked, the first cell is selected. The row is not important, but the column is very important—we know for sure that we are in the first column (column A). We now move to the next column (which we know for sure has to be the second column) and assign that value to a variable. Then we move to the next column (which must be the third column) and assign that value to a variable. We do this in a for loop, until we've looped through all the rows in our table. At the same time, the position, which iterates from "2" onwards ("1" would cause the text to appear in the header cell) is sent to the insertValuesIntoCell() method, which is described later below, where it is put into the row matching the current position.

In the above method you can see that, for the headers, with hardcoded cell contents, the insertHeadersIntoCell() method is called:

public static void insertHeadersIntoCell(String sCellName, String sText,
XTextTable xTable) throws UnknownPropertyException, PropertyVetoException,
com.sun.star.lang.IllegalArgumentException, WrappedTargetException {
// Access the XText interface of the cell referred to by sCellName (e.g., A1):
XText xCellText = (XText) UnoRuntime.queryInterface(XText.class, xTable.getCellByName(sCellName));
// Set the text in the cell to sText (e.g., "Nick Name"):
// Select the table headers and get the cell properties:
XCellRange xCellRange = ( XCellRange )UnoRuntime.queryInterface( XCellRange.class, xTable );
XCellRange xSelectedCells = xCellRange.getCellRangeByName("A1:C1");
XPropertySet xCellProps = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xSelectedCells);
// Format the color of the table headers (page 56 and 57):
xTableProps = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xCellRange);
xCellProps.setPropertyValue("BackColor", new Integer(0x000052));
// Define a border line, then assign a color and a width:
BorderLine theLine = new BorderLine();
theLine.Color = 0x000099;
theLine.OuterLineWidth = 1;
// Apply the line definition to all cell borders and make them valid:
TableBorder bord = new TableBorder();
bord.VerticalLine = bord.HorizontalLine =
bord.LeftLine = bord.RightLine =
bord.TopLine = bord.BottomLine =
bord.IsVerticalLineValid = bord.IsHorizontalLineValid =
bord.IsLeftLineValid = bord.IsRightLineValid =
bord.IsTopLineValid = bord.IsBottomLineValid =
xTableProps.setPropertyValue("TableBorder", bord);

For the cells, the insertValuesIntoCell() method is called:

private void insertValuesIntoCell(String selectedCell, String firstNextToSelectedCell,
String secondNextToSelectedCell, int position, XTextTable xTable)
throws UnknownPropertyException, PropertyVetoException, com.sun.star.lang.IllegalArgumentException,
WrappedTargetException {
XText xCellText1 = (XText) UnoRuntime.queryInterface(XText.class, xTable.getCellByName("A" + position));
XText xCellText2 = (XText) UnoRuntime.queryInterface(XText.class, xTable.getCellByName("B" + position));
XText xCellText3 = (XText) UnoRuntime.queryInterface(XText.class, xTable.getCellByName("C" + position));
//Choose all odd numbered rows:
if (position%2 != 0) {
//Then choose the cell range, from column A to column C, with the given row as
//the second part of the string. So, if the received position is "3", the selected
//range is from A3 to C3:
XCellRange xCellRange = ( XCellRange )UnoRuntime.queryInterface( XCellRange.class, xTable );
XCellRange xSelectedCells = xCellRange.getCellRangeByName("A" +position+ ":C" +position + "/");
XPropertySet xCellProps = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xSelectedCells);
//Now get the table properties for the selected range and change the backcolor property:
xTableProps = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xCellRange);
xCellProps.setPropertyValue("BackColor", new Integer(0xFF9933));

And that's it. That's how we end up with formatted back colors and borders for the cells in our table. Plus, more importantly, that's how we get the values from our Swing jTable into our OpenOffice.org Writer document.

Join the discussion

Comments ( 5 )
  • Emilian Thursday, June 22, 2006
    A nice thing would be to be able to use openoffice with the help of an embedded lib (no ports, sockets and such stuff).
  • Wouter van Reeven Thursday, June 22, 2006
    Emilian: I don't think this is possible. OOo is way too large to put in a couple of jars. Besides that, it's mostly written in C, not Java. It is possible to connect to OOo without a port, but that requires a local install.
    Geertjan: very nicely done. There are a few things that can be improved. The "Contacts Report" should be center aligned instead of positioning it with a bunch of tabs. Also, instead of going right 15 positions with an XTextCursor, you should use an XSentenceCursor or an XParagraphcursor. Besides that, it's looking great!
    Greets, Wouter
  • Geertjan Thursday, June 22, 2006
    Thanks for the tips, Wouter! I'll work on those points. One thing I don't understand is how to move the cursor back to the top of the page. Currently, when the report is produced, the cursor ends up right below the table, while I'd like it to be in the top left corner of the document. I've tried moving the cursor back, even creating a new cursor, but nothing seems to work. Can you (or someone else) advise on this point?
  • Ken Thursday, June 22, 2006
    Your efforts here are impressive! It is really nice to see how to integrate other, non-netbeans applications into the IDE (using java libs of course) so that the IDE becomes a one-stop shop for all a developer's needs. However, IMHO, this seems like its starting to become more like a tutorial on OOo instead of Netbeans.
    There is a lot of merit for this tutorial: i.e. Mailing lists to customers of feature requests implemented in their next product, or developing reports using the profiler to be delivered to various staff in M$ Word/Excel format, etc.
  • Wouter van Reeven Thursday, June 22, 2006
    Geertjan, every Writer object has two types of cursors (remember my presentation at J-Spring?). The cursor you have been using so far is INVISIBLE. The fact that the VISIBLE cursor keeps track is just coincidence.
    Have a look at chapter 7 of the Developer's Guide. In 7.1.2 the XTextViewcursor is explained. Copy some of the code (starting with querying the XDesktop and end by getViewCursor()) and then call xViewcursor.gotoStart(false) et voilá!
    Greets, Wouter
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.