In our documentation framework the table
element and the
table columns can have specified widths. In order for these widths to
be considered by <oXygen/> Author we need to provide the means to
determine them. As explained in the Styling the Table
Element section which describes the CSS properties needed
for defining a table, if we use the table element attribute width <oXygen/> can determine the table width
automatically. In our example the table has col
elements
with width attributes that are not
recognized by default. We will need to implement a Java extension
class for determining the column widths.
Create the class
simple.documentation.framework.TableColumnWidthProvider
.
This class must implement the
ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider
interface.
import ro.sync.ecss.extensions.api.AuthorAccess; import ro.sync.ecss.extensions.api.AuthorOperationException; import ro.sync.ecss.extensions.api.AuthorTableColumnWidthProvider; import ro.sync.ecss.extensions.api.WidthRepresentation; import ro.sync.ecss.extensions.api.node.AuthorElement; public class TableColumnWidthProvider implements AuthorTableColumnWidthProvider {
The method init
is taking as argument the
AuthorElement
that represents the XML
table
element. In our case the column widths are
specified in col
elements from the table
element. In such cases you must collect the span information by
analyzing the table
element.
public void init(AuthorElement tableElement) { this.tableElement = tableElement; AuthorElement[] colChildren = tableElement.getElementsByLocalName("customcol"); if (colChildren != null && colChildren.length > 0) { for (int i = 0; i < colChildren.length; i++) { AuthorElement colChild = colChildren[i]; if (i == 0) { colsStartOffset = colChild.getStartOffset(); } if (i == colChildren.length - 1) { colsEndOffset = colChild.getEndOffset(); } // Determine the 'width' for this col. AttrValue colWidthAttribute = colChild.getAttribute("width"); String colWidth = null; if (colWidthAttribute != null) { colWidth = colWidthAttribute.getValue(); // Add WidthRepresentation objects for the columns this 'customcol' specification // spans over. colWidthSpecs.add(new WidthRepresentation(colWidth, true)); } } } }
The method isTableAcceptingWidth
should
check if the table cells are td
.
public boolean isTableAcceptingWidth(String tableCellsTagName) { return "td".equals(tableCellsTagName); }
The method isTableAndColumnsResizable
should
check if the table cells are td
. This method determines
if the table and columns can be resized by dragging with the mouse the
edge of a column.
public boolean isTableAndColumnsResizable(String tableCellsTagName) { return "td".equals(tableCellsTagName); }
The methods getTableWidth
and
getCellWidth
are used for determining
the table width and the column width. The table layout engine will ask
this AuthorTableColumnWidthProvider
implementation what is the table width for each table element and the
cell width for each cell element from the table that was marked as
cell in the CSS using the property display:table-cell
.
The implementation is simple and just parses the value of the
width attribute. The methods
must return null
for the tables/cells that do not have a
specified width.
public WidthRepresentation getTableWidth(String tableCellsTagName) { WidthRepresentation toReturn = null; if (tableElement != null && "td".equals(tableCellsTagName)) { AttrValue widthAttr = tableElement.getAttribute("width"); if (widthAttr != null) { String width = widthAttr.getValue(); if (width != null) { toReturn = new WidthRepresentation(width, true); } } } return toReturn; }
public List<WidthRepresentation> getCellWidth(AuthorElement cellElement, int colNumberStart, int colSpan) { List<WidthRepresentation> toReturn = null; int size = colWidthSpecs.size(); if (size >= colNumberStart && size >= colNumberStart + colSpan) { toReturn = new ArrayList<WidthRepresentation>(colSpan); for (int i = colNumberStart; i < colNumberStart + colSpan; i ++) { // Add the column widths toReturn.add(colWidthSpecs.get(i)); } } return toReturn; }
The methods commitTableWidthModification
and
commitColumnWidthModifications
are used
for committing changes made to the width of the table or its columns
when using the mouse drag gestures.
public void commitTableWidthModification(AuthorDocumentController authorDocumentController, int newTableWidth, String tableCellsTagName) throws AuthorOperationException { if ("td".equals(tableCellsTagName)) { if (newTableWidth > 0) { if (tableElement != null) { String newWidth = String.valueOf(newTableWidth); authorDocumentController.setAttribute( "width", new AttrValue(newWidth), tableElement); } else { throw new AuthorOperationException("Cannot find the element representing the table."); } } } }
public void commitColumnWidthModifications(AuthorDocumentController authorDocumentController, WidthRepresentation[] colWidths, String tableCellsTagName) throws AuthorOperationException { if ("td".equals(tableCellsTagName)) { if (colWidths != null && tableElement != null) { if (colsStartOffset >= 0 && colsEndOffset >= 0 && colsStartOffset < colsEndOffset) { authorDocumentController.delete(colsStartOffset, colsEndOffset); } String xmlFragment = createXMLFragment(colWidths); int offset = -1; AuthorElement[] header = tableElement.getElementsByLocalName("header"); if (header != null && header.length > 0) { // Insert the cols elements before the 'header' element offset = header[0].getStartOffset(); } if (offset == -1) { throw new AuthorOperationException("No valid offset to insert the columns width specification."); } authorDocumentController.insertXMLFragment(xmlFragment, offset); } } } private String createXMLFragment(WidthRepresentation[] widthRepresentations) { StringBuffer fragment = new StringBuffer(); String ns = tableElement.getNamespace(); for (int i = 0; i < widthRepresentations.length; i++) { WidthRepresentation width = widthRepresentations[i]; fragment.append("<customcol"); String strRepresentation = width.getWidthRepresentation(); if (strRepresentation != null) { fragment.append(" width=\"" + width.getWidthRepresentation() + "\""); } if (ns != null && ns.length() > 0) { fragment.append(" xmlns=\"" + ns + "\""); } fragment.append("/>"); } return fragment.toString(); }
The following three methods are used to determine what type of column width specifications the table column width provider support. In our case all types of specifications are allowed:
public boolean isAcceptingFixedColumnWidths(String tableCellsTagName) { return true; } public boolean isAcceptingPercentageColumnWidths(String tableCellsTagName) { return true; } public boolean isAcceptingProportionalColumnWidths(String tableCellsTagName) { return true; }
The complete source code of our implementation is found in the Example Files Listings, the Java Files section.
In the listing below, the XML document contains the table element:
<table width="300"> <customcol width="50.0px"/> <customcol width="1*"/> <customcol width="2*"/> <customcol width="20%"/> <header> <td>C1</td> <td>C2</td> <td>C3</td> <td>C4</td> </header> <tr> <td>cs=1, rs=1</td> <td>cs=1, rs=1</td> <td row_span="2">cs=1, rs=2</td> <td row_span="3">cs=1, rs=3</td> </tr> <tr> <td>cs=1, rs=1</td> <td>cs=1, rs=1</td> </tr> <tr> <td column_span="3">cs=3, rs=1</td> </tr> </table>
When no table column width provider is specified, the table has the following layout:
When the above implementation is configured, the table has the correct layout: