blob: 257ee16c620d2160cbfc5aca1c1e0d73eeffa615 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 IBM Corporation and Others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Tatsuya ISHIHARA - initial API and implementation
*******************************************************************************/
package org.eclipse.actf.model.dom.odf.util.accessibility;
import java.util.List;
import org.eclipse.actf.model.dom.odf.ODFConstants.ContentType;
import org.eclipse.actf.model.dom.odf.base.DrawingObjectBaseElement;
import org.eclipse.actf.model.dom.odf.base.DrawingObjectElement;
import org.eclipse.actf.model.dom.odf.base.EmbedDrawingObjectElement;
import org.eclipse.actf.model.dom.odf.base.ODFDocument;
import org.eclipse.actf.model.dom.odf.base.ODFElement;
import org.eclipse.actf.model.dom.odf.content.IStylable;
import org.eclipse.actf.model.dom.odf.draw.ControlElement;
import org.eclipse.actf.model.dom.odf.draw.DrawConstants;
import org.eclipse.actf.model.dom.odf.draw.FrameElement;
import org.eclipse.actf.model.dom.odf.draw.TextBoxElement;
import org.eclipse.actf.model.dom.odf.form.FormConstants;
import org.eclipse.actf.model.dom.odf.form.FormControlElement;
import org.eclipse.actf.model.dom.odf.office.DocumentContentElement;
import org.eclipse.actf.model.dom.odf.office.OfficeConstants;
import org.eclipse.actf.model.dom.odf.office.SpreadSheetElement;
import org.eclipse.actf.model.dom.odf.presentation.NotesElement;
import org.eclipse.actf.model.dom.odf.presentation.PresentationConstants;
import org.eclipse.actf.model.dom.odf.style.StyleConstants;
import org.eclipse.actf.model.dom.odf.style.StyleElement;
import org.eclipse.actf.model.dom.odf.style.StylePropertiesBase;
import org.eclipse.actf.model.dom.odf.style.TableCellPropertiesElement;
import org.eclipse.actf.model.dom.odf.svg.SVGConstants;
import org.eclipse.actf.model.dom.odf.table.CoveredTableCellElement;
import org.eclipse.actf.model.dom.odf.table.TableCellElement;
import org.eclipse.actf.model.dom.odf.table.TableColumnElement;
import org.eclipse.actf.model.dom.odf.table.TableConstants;
import org.eclipse.actf.model.dom.odf.table.TableElement;
import org.eclipse.actf.model.dom.odf.table.TableRowElement;
import org.eclipse.actf.model.dom.odf.text.PElement;
import org.eclipse.actf.model.dom.odf.text.SequenceElement;
import org.eclipse.actf.model.dom.odf.text.TextConstants;
import org.eclipse.actf.util.xpath.XPathService;
import org.eclipse.actf.util.xpath.XPathServiceFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
/**
* Utility class to fix ODF accessibility problems
*/
public class AccessibilityFixEngine {
private static final String COLON = ":"; //$NON-NLS-1$
private static final XPathService xpathService = XPathServiceFactory
.newService();
@SuppressWarnings("nls")
private static final Object EXP1 = xpathService
.compile("./ancestor::*[namespace-uri()='"
+ TextConstants.TEXT_NAMESPACE_URI + "' and local-name()='"
+ TextConstants.ELEMENT_SECTION + "']"
+ "[attribute::*[namespace-uri()='"
+ TextConstants.TEXT_NAMESPACE_URI + "' and local-name()='"
+ TextConstants.ATTR_DISPLAY + "']='"
+ TextConstants.ATTR_DISPLAY_VALUE_NONE + "']");
@SuppressWarnings("nls")
private static final Object EXP2 = xpathService
.compile("./ancestor::*[(namespace-uri()='"
+ TableConstants.TABLE_NAMESPACE_URI
+ "' and local-name()='"
+ TableConstants.ELEMENT_TABLE_CELL + "')"
+ " or (namespace-uri()='"
+ TableConstants.TABLE_NAMESPACE_URI
+ "' and local-name()='"
+ TableConstants.ELEMENT_COVERED_TABLE_CELL + "')]");
@SuppressWarnings("nls")
private static final Object EXP3 = xpathService
.compile("./ancestor::*[namespace-uri()='"
+ TableConstants.TABLE_NAMESPACE_URI
+ "' and local-name()='" + TableConstants.ELEMENT_TABLE
+ "']" + "[parent::*[namespace-uri()='"
+ OfficeConstants.OFFICE_NAMESPACE_URI
+ "' and local-name()='"
+ OfficeConstants.ELEMENT_SPREADSHEET + "']]");
private double odfVersion = -1.0;
public AccessibilityFixEngine() {
}
public AccessibilityFixEngine(double odfVersion) {
this.odfVersion = odfVersion;
}
public boolean fixShortDesc(ODFElement target, String shortDesc) {
if ((shortDesc == null) || (shortDesc.length() == 0))
return false;
if (target instanceof DrawingObjectBaseElement) {
ODFElement shortDescElem = null;
if (odfVersion != -1.0) {
shortDescElem = ((DrawingObjectBaseElement) target)
.getShortDescElement(odfVersion);
} else {
shortDescElem = ((DrawingObjectBaseElement) target)
.getShortDescElement();
}
if (shortDescElem == null) {
Document doc = target.getOwnerDocument();
if (doc instanceof ODFDocument) {
Element newElem = null;
ODFDocument odfDoc = ((ODFDocument) doc);
String svgPrefix = target
.lookupPrefix(SVGConstants.SVG_NAMESPACE_URI);
if (svgPrefix == null)
return false;
if ((odfVersion == 1.0)
|| ((odfVersion == -1.0) && (odfDoc.getODFVersion() == 1.0))) {
newElem = doc.createElement(svgPrefix + COLON
+ SVGConstants.ELEMENT_DESC);
newElem.setTextContent(shortDesc);
} else if ((odfVersion > 1.0)
|| ((odfVersion == -1.0) && (odfDoc.getODFVersion() > 1.0))) {
newElem = doc.createElement(svgPrefix + COLON
+ SVGConstants.ELEMENT_TITLE);
newElem.setTextContent(shortDesc);
}
if (newElem != null) {
if (target instanceof EmbedDrawingObjectElement) {
Element parent = (Element) target.getParentNode();
parent.appendChild(newElem);
return true;
} else if (target instanceof DrawingObjectElement) {
target.appendChild(newElem);
return true;
}
}
}
} else {
shortDescElem.setTextContent(shortDesc);
return true;
}
}
return false;
}
public boolean fixLongDesc(ODFElement target, String longDesc) {
if ((longDesc == null) || (longDesc.length() == 0))
return false;
if (target instanceof DrawingObjectBaseElement) {
ODFElement longDescElem = null;
if (odfVersion != -1.0) {
longDescElem = ((DrawingObjectBaseElement) target)
.getLongDescElement(odfVersion);
} else {
longDescElem = ((DrawingObjectBaseElement) target)
.getLongDescElement();
}
if (longDescElem == null) {
Document doc = target.getOwnerDocument();
if (doc instanceof ODFDocument) {
Element newElem = null;
ODFDocument odfDoc = ((ODFDocument) doc);
Element parent = (Element) target.getParentNode();
if ((odfVersion > 1.0)
|| ((odfVersion == -1.0) && (odfDoc.getODFVersion() > 1.0))) {
String svgPrefix = target
.lookupPrefix(SVGConstants.SVG_NAMESPACE_URI);
if (svgPrefix == null)
return false;
newElem = doc.createElement(svgPrefix + COLON
+ SVGConstants.ELEMENT_DESC);
newElem.setTextContent(longDesc);
}
if (newElem != null) {
if (target instanceof EmbedDrawingObjectElement) {
parent.appendChild(newElem);
return true;
} else if (target instanceof DrawingObjectElement) {
target.appendChild(newElem);
return true;
}
}
}
} else {
longDescElem.setTextContent(longDesc);
return true;
}
}
return false;
}
private void expandRepeatedTableRow(TableRowElement row) {
int repeat = row.getAttrTableNumberRowsRepeated();
if (repeat != -1) {
Node rowParent = row.getParentNode();
row.removeAttributeNS(TableConstants.TABLE_NAMESPACE_URI,
TableConstants.ATTR_NUMBER_ROWS_REPEATED);
for (int i = 0; i < repeat - 1; i++) {
TableRowElement cloneRow = (TableRowElement) row
.cloneNode(false);
rowParent.insertBefore(cloneRow, row);
}
}
}
public boolean fixTableRowHeader(ODFElement target, int headerNum) {
if (target instanceof TableElement) {
NodeList testnl = ((TableElement) target).getTableHeaderRows();
if ((testnl != null) && (testnl.getLength() > 0))
return false;
Document doc = target.getOwnerDocument();
if (doc instanceof ODFDocument) {
String tablePrefix = target
.lookupPrefix(TableConstants.TABLE_NAMESPACE_URI);
if (tablePrefix == null)
return false;
Element headerRow = doc.createElement(tablePrefix + COLON
+ TableConstants.ELEMENT_TABLE_HEADER_ROWS);
List<TableRowElement> rowList = ((TableElement) target)
.getTableRowChildren();
for (int i = 0; i < rowList.size(); i++) {
expandRepeatedTableRow(rowList.get(i));
}
rowList = ((TableElement) target).getTableRowChildren();
if ((rowList.size() == 0) || (headerNum > rowList.size()))
return false;
Node newHeaderRow = target.insertBefore(headerRow, rowList
.get(0));
for (int i = 0; i < headerNum; i++) {
TableRowElement row = rowList.get(i);
newHeaderRow.appendChild(row);
}
return true;
}
}
return false;
}
private void expandRepeatedTableColumn(TableColumnElement col) {
int repeat = col.getAttrTableNumberColumnsRepeated();
if (repeat != -1) {
Node colParent = col.getParentNode();
col.removeAttributeNS(TableConstants.TABLE_NAMESPACE_URI,
TableConstants.ATTR_NUMBER_COLUMNS_REPEATED);
for (int i = 0; i < repeat - 1; i++) {
TableColumnElement cloneCol = (TableColumnElement) col
.cloneNode(false);
colParent.insertBefore(cloneCol, col);
}
}
}
public boolean fixTableColumnHeader(ODFElement target, int headerNum) {
if (target instanceof TableElement) {
NodeList testnl = ((TableElement) target).getTableHeaderColumns();
if ((testnl != null) && (testnl.getLength() > 0))
return false;
Document doc = target.getOwnerDocument();
if (doc instanceof ODFDocument) {
String tablePrefix = target
.lookupPrefix(TableConstants.TABLE_NAMESPACE_URI);
if (tablePrefix == null)
return false;
Element headerColumn = doc.createElement(tablePrefix + COLON
+ TableConstants.ELEMENT_TABLE_HEADER_COLUMNS);
List<TableColumnElement> colList = ((TableElement) target)
.getTableColumnChildren();
for (int i = 0; i < colList.size(); i++) {
expandRepeatedTableColumn(colList.get(i));
}
colList = ((TableElement) target).getTableColumnChildren();
if ((colList.size() == 0) || (headerNum > colList.size()))
return false;
Node newHeaderColumn = target.insertBefore(headerColumn,
colList.get(0));
for (int i = 0; i < headerNum; i++) {
TableColumnElement col = colList.get(i);
newHeaderColumn.appendChild(col);
}
return true;
}
}
return false;
}
@SuppressWarnings("nls")
public boolean fixTableCaption(ODFElement target, String caption) {
if ((caption == null) || (caption.length() == 0))
return false;
if (target instanceof TableElement) {
SequenceElement test = ((TableElement) target)
.getTextSequenceElement();
if (test != null)
return false;
Document doc = target.getOwnerDocument();
if (doc instanceof ODFDocument) {
// add text:p element next to table:table element
Element newPElem = null;
String textPrefix = target
.lookupPrefix(TextConstants.TEXT_NAMESPACE_URI);
if (textPrefix == null)
return false;
String stylePrefix = target
.lookupPrefix(StyleConstants.STYLE_NAMESPACE_URI);
if (stylePrefix == null)
return false;
Element pElem = doc.createElement(textPrefix + COLON
+ TextConstants.ELEMENT_P);
pElem.setAttribute(textPrefix + COLON
+ TextConstants.ATTR_STYLE_NAME, "Table");
Node parent = target.getParentNode();
Node nextNode = target.getNextSibling();
if (nextNode == null) {
newPElem = (Element) parent.appendChild(pElem);
} else {
newPElem = (Element) parent.insertBefore(pElem, nextNode);
}
if (newPElem != null) {
newPElem.appendChild(doc.createTextNode("Table "));
// set content of text:p element
Element seqElem = doc.createElement(textPrefix + COLON
+ TextConstants.ELEMENT_SEQUENCE);
seqElem.setAttribute(textPrefix + COLON
+ TextConstants.ATTR_NAME, "Table");
seqElem.setAttribute(textPrefix + COLON
+ TextConstants.ATTR_FORMULA, "ooow:Table+1");
seqElem.setAttribute(stylePrefix + COLON
+ StyleConstants.ATTR_NUM_FORMAT, "1");
newPElem.appendChild(seqElem);
Text captionText = doc.createTextNode(" : " + caption);
newPElem.appendChild(captionText);
return true;
}
}
}
return false;
}
@SuppressWarnings("nls")
public boolean isFormLabelFixCapable(ODFElement target) {
final String CONTROL_IMPL_CHECKBOX = "com.sun.star.form.component.CheckBox";
final String CONTROL_IMPL_OPTIONBUTTON = "com.sun.star.form.component.OptionButton";
final String CONTROL_IMPL_PUSHBUTTON = "com.sun.star.form.component.PushButton";
final String CONTROL_IMPL_RADIOBUTTON = "com.sun.star.form.component.RadioButton";
final String CONTROL_IMPL_GROUPBOX = "com.sun.star.form.component.GroupBox";
if (target instanceof ControlElement) {
FormControlElement formControl = ((ControlElement) target)
.getFormControlElement();
String controlImpl = formControl.getAttrFormControlImplementation();
if ((controlImpl.endsWith(CONTROL_IMPL_CHECKBOX))
|| (controlImpl.endsWith(CONTROL_IMPL_OPTIONBUTTON))
|| (controlImpl.endsWith(CONTROL_IMPL_PUSHBUTTON))
|| (controlImpl.endsWith(CONTROL_IMPL_RADIOBUTTON))
|| (controlImpl.endsWith(CONTROL_IMPL_GROUPBOX)))
return true;
}
return false;
}
public boolean fixFormLabel(ODFElement target, String label) {
if ((label == null) || (label.length() == 0))
return false;
if (target instanceof ControlElement) {
FormControlElement formControl = ((ControlElement) target)
.getFormControlElement();
if (formControl.hasAttributeNS(FormConstants.FORM_NAMESPACE_URI,
FormConstants.ATTR_LABEL)) {
formControl.removeAttributeNS(FormConstants.FORM_NAMESPACE_URI,
FormConstants.ATTR_LABEL);
}
String formPrefix = formControl.getPrefix();
formControl.setAttribute(formPrefix + COLON
+ FormConstants.ATTR_LABEL, label);
return true;
}
return false;
}
public boolean fixFormTabStop(ODFElement target, boolean tabStop) {
if (target instanceof ControlElement) {
FormControlElement formControl = ((ControlElement) target)
.getFormControlElement();
if (formControl.hasAttributeNS(FormConstants.FORM_NAMESPACE_URI,
FormConstants.ATTR_TAB_STOP)) {
formControl.removeAttributeNS(FormConstants.FORM_NAMESPACE_URI,
FormConstants.ATTR_TAB_STOP);
}
String formPrefix = formControl.getPrefix();
formControl.setAttribute(formPrefix + COLON
+ FormConstants.ATTR_TAB_STOP, new Boolean(tabStop)
.toString());
return true;
}
return false;
}
public boolean isInvisibleElement(ODFElement elem) {
NodeList nl = xpathService.evalForNodeList(EXP1, elem);
if ((nl != null) && (nl.getLength() > 0))
return true;
return false;
}
public String getInvisibleSectionName(ODFElement elem) {
NodeList nl = xpathService.evalForNodeList(EXP1, elem);
if ((nl != null) && (nl.getLength() > 0)) {
if (nl.item(0) instanceof Element) {
Element section = (Element) nl.item(0);
if (section.hasAttributeNS(TextConstants.TEXT_NAMESPACE_URI,
TextConstants.ATTR_NAME)) {
return section.getAttributeNS(
TextConstants.TEXT_NAMESPACE_URI,
TextConstants.ATTR_NAME);
}
}
}
return null;
}
public boolean isProtectedElement(ODFElement target) {
ContentType type = ContentType.NONE;
Element content = target.getOwnerDocument().getDocumentElement();
if (content instanceof DocumentContentElement) {
type = ((DocumentContentElement) content).getBodyElement()
.getContent().getContentType();
}
if (type != ContentType.SPREADSHEET)
return false;
if (target instanceof SpreadSheetElement) {
SpreadSheetElement spreadsheet = (SpreadSheetElement) target;
return spreadsheet.getAttrTableStructureProtected();
} else if (target instanceof TableElement) {
TableElement table = (TableElement) target;
return table.getAttrTableProtected();
} else {
SpreadSheetElement spreadsheet = null;
TableElement table = null;
IStylable cell = null;
if ((target instanceof TableCellElement)
|| (target instanceof CoveredTableCellElement)) {
cell = (IStylable) target;
} else {
NodeList cellList = xpathService.evalForNodeList(EXP2, target);
if ((cellList != null) && (cellList.getLength() == 1)) {
Node node = cellList.item(0);
if ((node instanceof TableCellElement)
|| (node instanceof CoveredTableCellElement)) {
cell = (IStylable) node;
}
}
}
if (cell == null)
return false;
NodeList tableList = xpathService.evalForNodeList(EXP3, target);
if ((tableList != null) && (tableList.getLength() == 1)) {
Node node = tableList.item(0);
if (node instanceof TableElement) {
table = (TableElement) node;
}
}
if (table == null)
return false;
Node tableParent = table.getParentNode();
if (tableParent instanceof SpreadSheetElement) {
spreadsheet = (SpreadSheetElement) tableParent;
}
if (spreadsheet == null)
return false;
if (spreadsheet.getAttrTableStructureProtected()
|| table.getAttrTableProtected()) {
int cellProtect = StyleConstants.CELL_PROTECT_VALUE_NOT_DEFINED;
StyleElement styleElem = cell.getStyle();
if (styleElem != null) {
for (int i = 0; i < styleElem.getPropertySize(); i++) {
StylePropertiesBase prop = styleElem
.getPropertyElement(i);
if (prop instanceof TableCellPropertiesElement) {
TableCellPropertiesElement cellProp = (TableCellPropertiesElement) prop;
cellProtect = cellProp.getAttrStyleCellProtect();
}
}
}
if ((cellProtect == StyleConstants.CELL_PROTECT_VALUE_PROTECTED)
|| (cellProtect == StyleConstants.CELL_PROTECT_VALUE_HIDDEN_AND_PROTECTED)) {
return true;
} else if (cellProtect == StyleConstants.CELL_PROTECT_VALUE_NOT_DEFINED) {
if (table.hasAttributeNS(
TableConstants.TABLE_NAMESPACE_URI,
TableConstants.ATTR_PROTECTED))
return table.getAttrTableProtected();
if (spreadsheet.hasAttributeNS(
TableConstants.TABLE_NAMESPACE_URI,
TableConstants.ATTR_STRUCTURE_PROTECTED))
return spreadsheet.getAttrTableStructureProtected();
}
}
}
return false;
}
public void setSpeakerNotesContent(NotesElement notes, String content) {
String[] contentList = content.split("\n"); //$NON-NLS-1$
NodeList frameList = notes.getElementsByTagNameNS(
DrawConstants.DRAW_NAMESPACE_URI, DrawConstants.ELEMENT_FRAME);
if ((frameList == null) || (frameList.getLength() <= 0))
return;
FrameElement notesFrame = null;
for (int i = 0; i < frameList.getLength(); i++) {
Node node = frameList.item(i);
if (node instanceof FrameElement) {
FrameElement frame = (FrameElement) node;
String presentationClass = frame.getAttributeNS(
PresentationConstants.PRESENTATION_NAMESPACE_URI,
PresentationConstants.ATTR_CLASS);
if ((presentationClass != null)
&& (presentationClass
.equals(PresentationConstants.ATTR_CLASS_VALUE_NOTES))) {
notesFrame = frame;
}
}
}
if (notesFrame == null)
return;
NodeList textBoxList = notesFrame.getElementsByTagNameNS(
DrawConstants.DRAW_NAMESPACE_URI,
DrawConstants.ELEMENT_TEXT_BOX);
if ((textBoxList == null) || (textBoxList.getLength() != 1))
return;
Document doc = notes.getOwnerDocument();
TextBoxElement textBox = (TextBoxElement) textBoxList.item(0);
NodeList pList = textBox.getElementsByTagNameNS(
TextConstants.TEXT_NAMESPACE_URI, TextConstants.ELEMENT_P);
for (int i = 0; i < contentList.length; i++) {
PElement pElem = null;
if ((i == 0) && (pList != null) && (pList.getLength() == 1)) {
pElem = (PElement) pList.item(0);
} else {
pElem = (PElement) doc.createElementNS(
TextConstants.TEXT_NAMESPACE_URI,
TextConstants.ELEMENT_P);
}
textBox.appendChild(pElem);
Text text = doc.createTextNode(contentList[i]);
pElem.appendChild(text);
}
}
}