blob: 4feae7d622e7827b30b5c4a4dd80df0b2560d921 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 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:
* Hisashi MIYASHITA - initial API and implementation
*******************************************************************************/
package org.eclipse.actf.model.dom.dombycom.impl.html;
import java.util.HashSet;
import org.eclipse.actf.model.dom.dombycom.AnalyzedResult;
import org.eclipse.actf.model.dom.dombycom.DomByCom;
import org.eclipse.actf.model.dom.dombycom.IDocumentEx;
import org.eclipse.actf.model.dom.dombycom.IElementEx;
import org.eclipse.actf.model.dom.dombycom.INodeEx;
import org.eclipse.actf.model.dom.dombycom.IStyle;
import org.eclipse.actf.model.dom.dombycom.impl.AttrImpl;
import org.eclipse.actf.model.dom.dombycom.impl.DocumentImpl;
import org.eclipse.actf.model.dom.dombycom.impl.Helper;
import org.eclipse.actf.model.dom.dombycom.impl.NamedNodeMapImpl;
import org.eclipse.actf.model.dom.dombycom.impl.NodeImpl;
import org.eclipse.actf.model.dom.dombycom.impl.NodeListImpl;
import org.eclipse.actf.model.dom.dombycom.impl.StyleImpl;
import org.eclipse.actf.util.vocab.AbstractTerms;
import org.eclipse.actf.util.vocab.Vocabulary;
import org.eclipse.actf.util.win32.comclutch.DispatchException;
import org.eclipse.actf.util.win32.comclutch.IDispatch;
import org.eclipse.swt.graphics.Rectangle;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.TypeInfo;
@SuppressWarnings("nls")
public class ElementImpl extends NodeImpl implements IElementEx {
protected ElementImpl(NodeImpl baseNode, IDispatch inode) {
super(baseNode, inode, Node.ELEMENT_NODE);
}
protected ElementImpl(DocumentImpl baseDoc, IDispatch inode) {
super(baseDoc, inode, Node.ELEMENT_NODE);
}
public String getTagName() {
return (String) Helper.get(inode, "tagName");
}
private static final Integer getSetAttributeFlag = Integer.valueOf(2);
public String getAttribute(String name) {
IDispatch r = (IDispatch) inode.invoke1("getAttributeNode", name);
if (r == null)
return null;
Boolean b = (Boolean) Helper.get(r, "specified");
if (!b.booleanValue())
return null;
return (String) Helper.get(r, "value");
}
public void setAttribute(String name, String value) throws DOMException {
inode.invoke("setAttribute", new Object[] { name, value,
getSetAttributeFlag });
}
public void removeAttribute(String name) throws DOMException {
inode.invoke1("removeAttribute", name);
}
public String getCurrentAttribute(String name) {
String r = (String) inode.invoke("getAttribute", new Object[] { name,
getSetAttributeFlag });
return r;
}
// public String getSpecifiedAttribute(String name) {
// IDispatch r = (IDispatch) inode.invoke1("getAttributeNode", name);
// if (r == null)
// return null;
// Boolean b = (Boolean) Helper.get(r, "specified");
// if (!b.booleanValue())
// return null;
// return (String) Helper.get(r, "value");
// }
public Attr getAttributeNode(String name) {
IDispatch r = (IDispatch) inode.invoke1("getAttributeNode", name);
if (r == null)
return null;
return (Attr) newNode(r, Node.ATTRIBUTE_NODE);
}
public Attr setAttributeNode(Attr newAttr) throws DOMException {
if (!(newAttr instanceof AttrImpl)) {
Helper.notSupported();
}
AttrImpl a = (AttrImpl) newAttr;
IDispatch r = (IDispatch) inode.invoke1("setAttributeNode", a
.getINode());
if (r == null)
return null;
return (Attr) newNode(r, Node.ATTRIBUTE_NODE);
}
public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
if (!(oldAttr instanceof AttrImpl)) {
Helper.notSupported();
}
AttrImpl a = (AttrImpl) oldAttr;
IDispatch r = (IDispatch) inode.invoke1("removeAttributeNode", a
.getINode());
if (r == null)
return null;
return (Attr) newNode(r, Node.ATTRIBUTE_NODE);
}
public NodeList getElementsByTagName(String name) {
IDispatch r = (IDispatch) inode.invoke1("getElementsByTagName", name);
if (r == null)
return null;
return new NodeListImpl(this, r);
}
private NamedNodeMapImpl cachedAttributes;
private void initCache() {
if (cachedAttributes != null)
return;
cachedAttributes = (NamedNodeMapImpl) getAttributes();
}
public String getAttributeNS(String namespaceURI, String localName) {
initCache();
Attr a = (Attr) cachedAttributes
.getNamedItemNS(namespaceURI, localName);
if (a == null)
return null;
return a.getValue();
}
public void setAttributeNS(String namespaceURI, String qualifiedName,
String value) throws DOMException {
throw new UnsupportedOperationException();
}
public void removeAttributeNS(String namespaceURI, String localName)
throws DOMException {
initCache();
Attr a = (Attr) cachedAttributes
.getNamedItemNS(namespaceURI, localName);
if (a == null)
return;
removeAttributeNode(a);
}
public Attr getAttributeNodeNS(String namespaceURI, String localName) {
initCache();
Attr a = (Attr) cachedAttributes
.getNamedItemNS(namespaceURI, localName);
if (a == null)
return null;
return a;
}
public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
throw new UnsupportedOperationException();
}
public NodeList getElementsByTagNameNS(String namespaceURI, String localName) {
throw new UnsupportedOperationException();
}
public boolean hasAttribute(String name) {
String val = getAttribute(name);
if (val == null)
return false;
return true;
}
public boolean hasAttributeNS(String namespaceURI, String localName) {
String val = getAttributeNS(namespaceURI, localName);
if (val == null)
return false;
return true;
}
public TypeInfo getSchemaTypeInfo() {
throw new UnsupportedOperationException();
}
public void setIdAttribute(String name, boolean isId) throws DOMException {
throw new UnsupportedOperationException();
}
public void setIdAttributeNS(String namespaceURI, String localName,
boolean isId) throws DOMException {
throw new UnsupportedOperationException();
}
public void setIdAttributeNode(Attr idAttr, boolean isId)
throws DOMException {
throw new UnsupportedOperationException();
}
// --------------------------------------------------------------------------------
// INodeEx interface
// --------------------------------------------------------------------------------
public boolean doClick() {
try {
if ("OPTION".equals(getLocalName())) {
Helper.put(inode, "selected", Boolean.valueOf(true));
return true;
} else if ("SELECT".equals(getLocalName())) {
return false;
}
inode.invoke0("click");
return true;
} catch (DispatchException e) {
e.printStackTrace();
return false;
}
}
private String originalBorder;
public boolean highlight() {
if (DomByCom.BORDER_MODE == DomByCom.STYLE_BORDER) {
String className = (String) Helper.get(inode, "className");
if (className == null)
return false;
className += " CSStoHighlight";
Helper.put(inode, "className", className);
} else if (DomByCom.BORDER_MODE == DomByCom.DIV_BORDER) {
Element div = getOwnerDocument().getElementById(DomByCom.ID_DIV);
IStyle style = ((IElementEx) div).getStyle();
Rectangle r = Helper.getLocation(inode);
String compatMode = ((IDocumentEx) getOwnerDocument())
.getCompatMode();
int w = 0;
if (compatMode.equals(IDocumentEx.CSS1_COMPAT)) {
w = 0;
} else if (compatMode.equals(IDocumentEx.BACK_COMPAT)) {
w = DomByCom.DIV_BORDER_WIDTH * 2;
}
style.put("left", (r.x - DomByCom.DIV_BORDER_WIDTH) + "px");
style.put("top", (r.y - DomByCom.DIV_BORDER_WIDTH) + "px");
style.put("width", (r.width + w) + "px");
style.put("height", (r.height + w) + "px");
} else if (DomByCom.BORDER_MODE == DomByCom.STYLE_BORDER2) {
IDispatch style = (IDispatch) Helper.get(inode, "style");
if (style == null)
return false;
originalBorder = (String) Helper.get(style, "cssText");
String border = originalBorder + DomByCom.BORDER_STYLE_STRING;
Helper.put(style, "cssText", border);
}
try {
inode.invoke0("scrollIntoView");
inode.invoke0("onmouseover");
return true;
} catch (DispatchException e) {
}
return false;
}
public boolean unhighlight() {
if (DomByCom.BORDER_MODE == DomByCom.STYLE_BORDER) {
String className = (String) Helper.get(inode, "className");
if (className == null)
return false;
String newClassName = className.replaceAll(" CSStoHighlight", "");
Helper.put(inode, "className", newClassName);
} else if (DomByCom.BORDER_MODE == DomByCom.DIV_BORDER) {
Element div = getOwnerDocument().getElementById(DomByCom.ID_DIV);
IStyle style = ((IElementEx) div).getStyle();
style.put("left", "-1000px");
style.put("top", "-1000px");
style.put("width", "100px");
style.put("height", "100px");
} else if (DomByCom.BORDER_MODE == DomByCom.STYLE_BORDER2) {
IDispatch style = (IDispatch) Helper.get(inode, "style");
if (style == null)
return false;
Helper.put(style, "cssText", originalBorder);
}
try {
inode.invoke0("onmouseout");
} catch (DispatchException e) {
}
return false;
}
static class InputType {
public enum InputClass {
EDIT, BUTTON, RADIO, CHECKBOX, COMBOBOX, HIDDEN, PASSWORD, FILE
}
private final InputClass inputClass;
private final String uiString;
String getUIString() {
return uiString;
}
boolean isEdit() {
return (inputClass == InputClass.EDIT);
}
boolean isFileEdit() {
return (inputClass == InputClass.FILE);
}
boolean isButton() {
return (inputClass == InputClass.BUTTON);
}
boolean isRadio() {
return (inputClass == InputClass.RADIO);
}
boolean isCheckBox() {
return (inputClass == InputClass.CHECKBOX);
}
boolean isComboBox() {
return (inputClass == InputClass.COMBOBOX);
}
boolean isHidden() {
return (inputClass == InputClass.HIDDEN);
}
boolean isPassword() {
return (inputClass == InputClass.PASSWORD);
}
boolean isClickable() {
return (isButton() || isRadio() || isCheckBox() || isComboBox());
}
final String htmlType;
InputType(String uiString, String htmlType, InputClass inputClass) {
this.uiString = uiString;
this.htmlType = htmlType;
this.inputClass = inputClass;
}
}
private static final InputType[] HTMLINPUTCLASSES = new InputType[] {
new InputType("edit", "text", InputType.InputClass.EDIT),
new InputType("password edit", "password",
InputType.InputClass.PASSWORD),
new InputType("radio button", "radio", InputType.InputClass.RADIO),
new InputType("checkbox", "checkbox", InputType.InputClass.CHECKBOX),
new InputType("file upload edit", "file", InputType.InputClass.FILE),
new InputType("", "hidden", InputType.InputClass.HIDDEN),
new InputType("button", "submit", InputType.InputClass.BUTTON),
new InputType("reset button", "reset", InputType.InputClass.BUTTON),
new InputType("button", "button", InputType.InputClass.BUTTON),
new InputType("button", "image", InputType.InputClass.BUTTON) };
InputType getInputType() {
Object o = Helper.get(inode, "type");
if (!(o instanceof String))
return null;
String type = (String) o;
for (int i = 0; i < HTMLINPUTCLASSES.length; i++) {
if (type.equals(HTMLINPUTCLASSES[i].htmlType)) {
return HTMLINPUTCLASSES[i];
}
}
return null;
}
private String getInputValue() {
return (String) Helper.get(inode, "value");
}
private String modifySrcStr(String src) {
int st = src.lastIndexOf('/');
int end = src.lastIndexOf('?');
if (end == -1)
end = src.length();
if (st < 0) {
if (end < 0)
return src;
st = 0;
} else {
st++;
}
if (end <= st) {
return src.substring(st);
} else {
return src.substring(st, end);
}
}
public String extractString() {
String name = getLocalName();
if ("IMG".equals(name)) {
String alt = getAttribute("alt");
if (alt != null) {
alt = Helper.trimHTMLStr(alt);
}
String title = getAttribute("title");
if (title != null) {
title = Helper.trimHTMLStr(title);
if (alt == null || alt.length() == 0)
alt = title;
}
String src = getAttribute("src");
if (src != null) {
src = modifySrcStr(src);
}
boolean noAlt = (alt == null);
boolean nullAlt = ((alt != null) && (alt.length() == 0));
boolean isLink = Vocabulary.isLink().eval(this);
if (isLink) {
if (noAlt) {
if (Vocabulary.isReadNoAltImageLink()) {
return src;
} else {
return "";
}
} else if (nullAlt && Vocabulary.isReadNullAltImageLink()) {
if (false) {
if (anyTextInParentLink())
return alt;
}
return src;
}
return alt;
} else {
if (noAlt) {
if (Vocabulary.isReadNoAltImage()) {
return src;
} else {
return "";
}
} else if (nullAlt && Vocabulary.isReadNullAltImage()) {
return src;
}
return alt;
}
} else if (Vocabulary.isEmbeddedObject().eval(this)) {
return "(Embedded Object)";
} else if ("INPUT".equals(name)) {
InputType type = getInputType();
if (type != null) {
if (type.isHidden())// || type.isCheckBox() || type.isRadio())
return "";
String alt = getAttribute("alt");
if (alt != null) {
alt = Helper.trimHTMLStr(alt);
if (alt.length() > 0)
return alt;
}
String value = getInputValue();
if (type.isPassword())
value = value.replaceAll(".", "*");
if (value != null && value.length() > 0) {
return value;
}
String title = getAttribute("title");
if (title != null)
return title;
}
} else if ("SELECT".equals(name)) {
return "Select";
} else if ("AREA".equals(name)) {
String alt = getAttribute("alt");
if (alt != null) {
alt = Helper.trimHTMLStr(alt);
if (alt.length() > 0)
return alt;
}
}
if (false) {
// title attribute can be added to any element accoding to XHTML2.
String title = getAttribute("title");
if (title != null) {
title = Helper.trimHTMLStr(title);
return title;
}
}
return "";
}
private boolean anyTextInParentLink() {
Node current = this.getParentNode();
if (current == null)
return false;
while (current != null) {
if ("A".equals(current.getNodeName())) {
break;
}
current = current.getParentNode();
}
if (current == null)
return false;
return anyTextInSiblings(current.getFirstChild());
}
private boolean anyTextInSiblings(Node element) {
StringBuffer buff = new StringBuffer();
Node next = element;
while (next != null) {
if (next instanceof ImageElementImpl) {
next = next.getNextSibling();
continue;
}
if (next instanceof Element) {
if (anyTextInSiblings(next.getFirstChild())) {
return true;
}
}
if (next instanceof INodeEx) {
INodeEx nex = (INodeEx) next;
buff.append(nex.extractString());
}
next = next.getNextSibling();
}
return Helper.trimHTMLStr(buff.toString()).length() > 0;
}
@Override
public short getHeadingLevel() {
String name = getLocalName();
if (name.length() != 2)
return super.getHeadingLevel();
if (name.charAt(0) != 'H')
return super.getHeadingLevel();
switch (name.charAt(1)) {
case '1':
return 1;
case '2':
return (short) 2;
case '3':
return (short) 3;
case '4':
return (short) 4;
case '5':
return (short) 5;
case '6':
return (short) 6;
}
return super.getHeadingLevel();
}
public boolean setFocus() {
try {
inode.invoke0("focus");
return true;
} catch (DispatchException e) {
e.printStackTrace();
}
return false;
}
@Override
public void setTextContent(String text) {
try {
Helper.put(inode, "innerText", text);
} catch (DispatchException e) {
e.printStackTrace();
}
}
public IStyle getStyle() {
IDispatch style = (IDispatch) Helper.get(inode, "currentStyle");
return new StyleImpl(style);
}
public AbstractTerms getTerms() {
return HTMLTerms.getInstance();
}
public Rectangle getLocation() {
try {
return Helper.getLocation(inode);
} catch (Exception e) {
// System.out.println("getLocation error "+this.extractString());
}
return null;
}
public Position getRadioPosition() {
if (getInputType() == null)
return null;
if (!getInputType().isRadio())
return null;
Element form = getParentElement(new String[] { "FORM" });
if (form == null)
return null;
String radioName = (String) Helper.get(inode, "name");
Position p = new Position();
searchRadioPosition(form, radioName, p, false);
return p;
}
private void searchRadioPosition(Element parent, String radioName,
Position p, boolean found) {
NodeList list = parent.getChildNodes();
int len = list.getLength();
for (int i = 0; i < len; i++) {
Node n = list.item(i);
if (n instanceof ElementImpl) {
ElementImpl e = (ElementImpl) n;
if (e.hasChildNodes()) {
searchRadioPosition(e, radioName, p, found);
}
if (e.getInputType() == null)
continue;
if (!e.getInputType().isRadio())
continue;
String name = (String) Helper.get(e.getINode(), "name");
if (radioName.equals(name)) {
if (!found)
p.index++;
p.total++;
}
if (e.isSameNode(this)) {
found = true;
}
}
}
}
public Position getListPosition() {
Element list = getParentElement(new String[] { "UL", "OL", "DL" });
Element item = getParentElement(new String[] { "LI", "DT" });
if (list == null)
return null;
Position p = new Position();
searchListPosition(list, item, p, false);
return p;
}
private void searchListPosition(Element parent, Element item, Position p,
boolean found) {
NodeList list = parent.getChildNodes();
int len = list.getLength();
for (int i = 0; i < len; i++) {
Node n = list.item(i);
if (n instanceof ElementImpl) {
ElementImpl e = (ElementImpl) n;
String name = e.getNodeName();
if (e.hasChildNodes()
&& !("UL".equals(name) || "OL".equals(name) || "DL"
.equals(name))) {
searchListPosition(e, item, p, found);
}
if (!"LI".equals(e.getNodeName())
&& !"DT".equals(e.getNodeName()))
continue;
if (!found)
p.index++;
p.total++;
if (e.isSameNode(item)) {
found = true;
}
}
}
}
private Element getParentElement(String[] tagNames) {
Element parent = this;
HashSet<String> set = new HashSet<String>();
for (int i = 0; i < tagNames.length; i++) {
set.add(tagNames[i].intern());
}
String name = parent.getNodeName();
while (!set.contains(name.intern())) {
Node temp = parent.getParentNode();
if (temp == null || !(temp instanceof Element))
return null;
parent = (Element) temp;
name = parent.getNodeName();
}
return parent;
}
public Element getFormLabel() {
NodeList nl = getOwnerDocument().getElementsByTagName("LABEL");
Object myId = Helper.get(inode, "id");
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof ElementImpl) {
ElementImpl label = (ElementImpl) node;
String id = (String) Helper.get(label.inode, "htmlFor");
if (id == null)
continue;
if (id.equals(myId))
return label;
}
}
return null;
}
public char getAccessKey() {
String key = null;
String name = getNodeName();
if ("LABEL".equals(name))
return 0;
Element label = getFormLabel();
if (label != null && label instanceof ElementImpl) {
key = (String) Helper.get(((ElementImpl) label).inode, "accessKey");
} else {
key = (String) Helper.get(inode, "accessKey");
}
if (key != null && key.length() == 1)
return key.toUpperCase().charAt(0);
return 0;
}
@Override
public AnalyzedResult analyze(AnalyzedResult ar) {
char key = getAccessKey();
if (key != 0)
ar.addAccessKey(this);
return super.analyze(ar);
}
}