package org.docx4j.convert.out.common.writer; import java.util.List; import javax.xml.transform.TransformerException; import org.docx4j.convert.out.ConversionHyperlinkHandler; import org.docx4j.convert.out.common.AbstractWmlConversionContext; import org.docx4j.model.fields.FldSimpleModel; import org.docx4j.model.fields.FormattingSwitchHelper; import org.docx4j.openpackaging.parts.relationships.Namespaces; import org.docx4j.openpackaging.parts.relationships.RelationshipsPart; import org.docx4j.relationships.Relationship; import org.docx4j.wml.P; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Node; /** Model for the hyperlink tag.<br> */ public class AbstractHyperlinkWriterModel implements ConversionHyperlinkHandler.Model { private static Logger log = LoggerFactory.getLogger(AbstractHyperlinkWriterModel.class); protected Node content = null; /** field-argument of the Hyperlink field or the targetUri of the relationship. * corresponds to switch \l field-argument, the \l switch might be omitted. */ protected String target = null; /** Only avaiable if the information is read from a relationship. * Otherwise always false. */ protected boolean external = false; /** * Specifies the name of a bookmark in the current document which shall be the target of * this hyperlink.<br> * If this attribute is omitted, then the default behavior shall be to navigate to the start of * the document. If a hyperlink target is also specified using the r:id attribute, then this * attribute shall be ignored.<br> */ protected String anchor = null; /** * Specifies a location in the target of the hyperlink that has no bookmarks. The method by * which the contents of this attribute are linked to document text is outside the scope of * ECMA-376. */ protected String docLocation = null; //history - ignored /** * Specifies the ID of the relationship whose target shall be used as the target for this * hyperlink. */ protected String rId = null; /** * Specifies a frame within the parent HTML frameset for the target of the parent hyperlink * when one exists. * corresponds to switch \t field-argument * corresponds to switch \n with tgtFrame = "_blank" */ protected String tgtFrame = null; /** * Specifies a string which can be surfaced in a user interface as associated with the parent * hyperlink. * corresponds to switch \o field-argument */ protected String tooltip = null; // imageMapCoordinates switch \m ignored - requires a ismap attribute in an embedded img // P.Hyperlink pHyperlink; // /** // * Where this model was built with a P.Hyperlink, // * here it is. Useful for debugging. // * @return // */ // public P.Hyperlink getPHyperlink() { // return pHyperlink; // } /** Default build method, get's called with a P.Hyperlink. */ public void build(AbstractWmlConversionContext conversionContext, Object node, Node content) throws TransformerException { Relationship relationship = null; RelationshipsPart rPart = null; P.Hyperlink pHyperlink = (P.Hyperlink)node; // log.debug(XmlUtils.marshaltoString(hyperlink, true, true)); this.content = content; setAnchor(pHyperlink.getAnchor()); setDocLocation(pHyperlink.getDocLocation()); setRId(pHyperlink.getId()); setTgtFrame(pHyperlink.getTgtFrame()); setTooltip(pHyperlink.getTooltip()); if (conversionContext.getCurrentPart() == null) { log.warn("set currentPart (via conversionContext)"); } else if ((getRId() != null) && (getRId().length() > 0) ) { rPart = conversionContext.getCurrentPart().getRelationshipsPart(); if (rPart == null) { log.error("RelationshipsPart is missing!"); } else { log.debug("looking for rel" + getRId()); relationship = rPart.getRelationshipByID(getRId()); if ((relationship != null) && (Namespaces.HYPERLINK.equals(relationship.getType()))) { setTarget(relationship.getTarget()); setExternal("External".equals(relationship.getTargetMode())); } } } } /** Custom build method, get's used with a FldSimpleModel in those cases * where the hyperlink is defined within a Field */ public void build(AbstractWmlConversionContext conversionContext, FldSimpleModel fldSimpleModel, Node content) throws TransformerException { int idx = 0; List<String> parameters = fldSimpleModel.getFldParameters(); String parameter = null; boolean isSwitch = false; char switchChar = '\0'; String switchParameter = null; this.content = content; while (idx < parameters.size()) { parameter = parameters.get(idx); if ((parameter != null) && (parameter.length() > 0)) {//should allways be true isSwitch = ((parameter.charAt(0) == '\\') && (parameter.length() == 2)); if (isSwitch) { switchChar = Character.toLowerCase(parameter.charAt(1)); switch (switchChar) { case 'l': //target switchParameter = FormattingSwitchHelper.getSwitchValue(idx + 1, parameters); if (switchParameter != null) { setTarget(switchParameter); idx++; } break; case 't': //target frame name switchParameter = FormattingSwitchHelper.getSwitchValue(idx + 1, parameters); if (switchParameter != null) { setTgtFrame(switchParameter); idx++; } break; case 'n': //target frame = "_blank" setTgtFrame("_blank"); break; case 'o': //tooltip switchParameter = FormattingSwitchHelper.getSwitchValue(idx + 1, parameters); if (switchParameter != null) { setTooltip(switchParameter); idx++; } break; case 'm': //image map coordinates break; } } else { //should only happen once with the first value, all others should be preceeded by a switch if (idx == 0) { setTarget(FormattingSwitchHelper.getSwitchValue(idx, parameters)); } } } idx++; } if ((getTarget() != null) && (getTarget().length() > 0) && ((getTarget().indexOf('/') > -1) || (getTarget().indexOf('\\') > -1) || (getTarget().indexOf('.') > -1) || (getTarget().indexOf(':') > -1))) { /* Don't know if this is correct: assume an external target if it contains * one of the following characters: \/:. */ setExternal(true); } } public String getExternalTarget() { return (isExternal() ? getTarget() : null); } public String getInternalTarget() { String ret = (isExternal() ? null : getTarget()); if (ret == null) { ret = getAnchor(); // this is a target, see http://webapp.docx4java.org/OnlineDemo/ecma376/WordML/hyperlink_2.html } if (ret == null) { ret = getDocLocation(); } return ret; } @Override public String getTarget() { return target; } @Override public void setTarget(String target) { this.target = target; } @Override public boolean isExternal() { return external; } @Override public void setExternal(boolean external) { this.external = external; } @Override public String getAnchor() { return anchor; } @Override public void setAnchor(String anchor) { this.anchor = anchor; } @Override public String getDocLocation() { return docLocation; } @Override public void setDocLocation(String docLocation) { this.docLocation = docLocation; } @Override public String getRId() { return rId; } @Override public void setRId(String rId) { this.rId = rId; } @Override public String getTgtFrame() { return tgtFrame; } @Override public void setTgtFrame(String tgtFrame) { this.tgtFrame = tgtFrame; } @Override public String getTooltip() { return tooltip; } @Override public void setTooltip(String tooltip) { this.tooltip = tooltip; } @Override public Node getContent() { return content; } @Override public String toString() { return "HyperlinkModel [target=" + target + ", external=" + external + ", anchor=" + anchor + ", docLocation=" + docLocation + ", rId=" + rId + ", tgtFrame=" + tgtFrame + "]"; } }