package nota.oxygen.common.table; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathException; import nota.oxygen.common.BaseAuthorOperation; import nota.oxygen.common.Utils; import nota.oxygen.dtbook.v2005.Dtbook2005UniqueAttributesRecognizer; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import ro.sync.ecss.extensions.api.ArgumentDescriptor; import ro.sync.ecss.extensions.api.ArgumentsMap; import ro.sync.ecss.extensions.api.AuthorDocumentController; import ro.sync.ecss.extensions.api.AuthorOperationException; import ro.sync.ecss.extensions.api.node.AuthorElement; import ro.sync.ecss.extensions.commons.id.DefaultUniqueAttributesRecognizer; /** * Fixes the headers attribute of the cell in the selected table * @author Ole Holst Andersen (oha@nota.nu) */ public class FixTableHeadersOperation extends BaseAuthorOperation { private XPath xpath; private String prefix; private void initXPath(Element tableElement) { String ns = tableElement.getNamespaceURI(); if (ns != null) { xpath = Utils.getXPath("d", ns); prefix = "d:"; } else { xpath = Utils.getXPath(); prefix = ""; } } private int getAttributeAsInt(Element elem, String attrName, int defVal) { if (elem.hasAttribute(attrName)) { try { return Integer.parseInt(elem.getAttribute(attrName)); } catch (NumberFormatException e) {} } return defVal; } private int getColumnIndex(Node tableCell) { if (tableCell instanceof Element) { Element tcElement = (Element)tableCell; int span = 0; if (tcElement.getLocalName()=="td" || tcElement.getLocalName()=="th") { span = getAttributeAsInt(tcElement, "cols", 1); } return getColumnIndex(tcElement.getPreviousSibling())+span; } return 0; } private String getHeadersAttributeValue(Element tdElement, Element tableElement) { String headers = ""; String expr = prefix+"thead/"+prefix+"tr|"+prefix+"tbody/"+prefix+"tr|"+prefix+"tr"; try { Node rowNode = (Node)xpath.evaluate(expr, tableElement, XPathConstants.NODE); int columnIndex = getColumnIndex(tdElement); if (rowNode instanceof Element) { NodeList firstRow = rowNode.getChildNodes(); for (int i=0; i<columnIndex; i++) { if (i>=firstRow.getLength()) break; if (firstRow.item(i) instanceof Element) { Element e = (Element)firstRow.item(i); if (e.getLocalName()=="td" || e.getLocalName()=="th") { if (getColumnIndex(firstRow.item(i))==columnIndex) { headers = e.getAttribute("id"); break; } } } } } } catch (XPathException e) {} if (tdElement.getParentNode().hasChildNodes()) { Element firstRowCellElement = (Element)tdElement.getParentNode().getFirstChild(); if (firstRowCellElement.getLocalName()=="th") headers += " "+firstRowCellElement.getAttribute("id"); } return headers.trim(); } @Override public void doOperation() throws AuthorOperationException { try { AuthorDocumentController docCtrl = getAuthorAccess().getDocumentController(); AuthorElement tableAElem = getNamedCommonParentElementOfSelection("table", null); if (tableAElem == null) { throw new AuthorOperationException( "The current selection is not inside a table"); } DefaultUniqueAttributesRecognizer uaReq = new Dtbook2005UniqueAttributesRecognizer(); uaReq.activated(getAuthorAccess()); uaReq.assignUniqueIDs(tableAElem.getStartOffset(), tableAElem.getEndOffset(), false); String tableXml = docCtrl.serializeFragmentToXML(docCtrl.createDocumentFragment(tableAElem, true)); Element tableXmlElem = Utils.deserializeElement(tableXml); if (tableXmlElem==null) throw new AuthorOperationException("Could not deserialize table Element to DOM"); initXPath(tableXmlElem); String expr = "//"+prefix+"tr/"+prefix+"td"; NodeList tableCells = (NodeList) xpath.evaluate(expr, tableXmlElem, XPathConstants.NODESET); if (tableCells==null) throw new AuthorOperationException("Found no td table cells"); for (int i = 0; i < tableCells.getLength(); i++) { showMessage("Before item retrieval i="+i); Element td = (Element) tableCells.item(i); String headers = getHeadersAttributeValue(td, tableXmlElem); if (headers == null) { if (td.hasAttribute("headers")) td.removeAttribute("headers"); } else { td.setAttribute("headers", headers); } } tableXml = Utils.serialize(tableXmlElem); docCtrl.deleteNode(tableAElem); docCtrl.insertXMLFragment(tableXml, getAuthorAccess().getEditorAccess().getCaretOffset()); } catch (Exception e) { if (e instanceof AuthorOperationException) { throw (AuthorOperationException)e; } else { String msg = "Unexpected "+e.getClass().getSimpleName()+" occured"; if (e.getMessage()!=null) msg += ": "+e.getMessage(); // + "\nStack Trace:\n" + e.getStackTrace().toString(); throw new AuthorOperationException(msg, e); } } } @Override public ArgumentDescriptor[] getArguments() { return new ArgumentDescriptor[] {}; } @Override public String getDescription() { return "Fix table header attributes"; } @Override protected void parseArguments(ArgumentsMap args) throws IllegalArgumentException { // No arguments to parse } }