com.adobe.xfa.content.ExDataValue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
The newest version!
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2005 Adobe Systems Incorporated All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of
* Adobe Systems Incorporated and its suppliers, if any. The intellectual and
* technical concepts contained herein are proprietary to Adobe Systems
* Incorporated and its suppliers and may be covered by U.S. and Foreign
* Patents, patents in process, and are protected by trade secret or copyright
* law. Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained from
* Adobe Systems Incorporated.
*/
package com.adobe.xfa.content;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import com.adobe.xfa.Attribute;
import com.adobe.xfa.Document;
import com.adobe.xfa.Element;
import com.adobe.xfa.Int;
import com.adobe.xfa.LogMessage;
import com.adobe.xfa.Model;
import com.adobe.xfa.Node;
import com.adobe.xfa.RichTextNode;
import com.adobe.xfa.STRS;
import com.adobe.xfa.ScriptTable;
import com.adobe.xfa.StringAttr;
import com.adobe.xfa.TextNode;
import com.adobe.xfa.XFA;
import com.adobe.xfa.XMLMultiSelectNode;
import com.adobe.xfa.ut.ExFull;
import com.adobe.xfa.ut.MsgFormatPos;
import com.adobe.xfa.ut.ResId;
import com.adobe.xfa.ut.StringUtils;
/**
* An element that describes a unit of foreign data content.
*
* @exclude from published api.
*/
public final class ExDataValue extends Content {
public ExDataValue(Element parent, Node prevSibling) {
super(parent, prevSibling, null, XFA.EXDATA, XFA.EXDATA, null,
XFA.EXDATATAG, XFA.EXDATA);
}
/**
* Indicates that the children of this node should not be indexed by ID.
*
* In C++, the children of exData are only kept in the XML DOM, so they
* are never indexed as part of the XFA DOM.
*
* @exclude from published API.
*/
protected boolean childrenAreIndexable() {
return false;
}
public boolean equals(Object object) {
if (this == object)
return true;
return super.equals(object) &&
getValue(true, true, true).equals(((ExDataValue)object).getValue(true, true, true));
}
public int hashCode() {
return super.hashCode() ^ getValue(true, true, true).hashCode();
}
public ScriptTable getScriptTable() {
return ExDataScript.getScriptTable();
}
public String getStrValue() {
return getValue(false, false, true);
}
public void updateIDValues(String sPrefix, List oldReferenceList) {
// Redirect this call to the rich text node, if that's what our one-of child is.
Node oNode = getOneOfChild(true, false);
if (oNode instanceof RichTextNode)
((RichTextNode) oNode).updateIDValuesImpl(sPrefix, oldReferenceList);
}
/**
* Get the text stored in this element
*
* @return the text string
*/
public String getValue(
boolean bAsFragment /* = false */,
boolean bSuppressPreamble /* = false */,
boolean bLegacyWhitespaceProcessing /* = false */) {
String sValue = "";
if (!getIsNull()) {
// If there's a child on the XFA side, we need to
// see if it's a richTextNode, textNode, or a link child
Node node = getOneOfChild();
if (node instanceof RichTextNode) {
RichTextNode richTextValue = (RichTextNode) node;
sValue = richTextValue.getValue(bAsFragment, bSuppressPreamble, bLegacyWhitespaceProcessing);
} else if (node instanceof TextNode) {
TextNode textValue = (TextNode) node;
sValue = textValue.getValue();
} else if (node instanceof XMLMultiSelectNode) {
// multi-select choice list values
XMLMultiSelectNode multiSelectValue = (XMLMultiSelectNode) node;
sValue = multiSelectValue.getValue(bAsFragment,bSuppressPreamble);
}
// JavaPort: Dead code removed for element.
// The link element was only used in XFA 1.0, so it is not supported by XFA4J.
}
Element grandParent = null;
if (getXFAParent() != null)
grandParent = getXFAParent().getXFAParent();
if (grandParent != null && grandParent.isSameClass(XFA.FIELDTAG) && !bAsFragment) {
Int maxLength = (Int) getAttribute(XFA.MAXLENGTHTAG);
int nMaxLength = maxLength.getValue();
// If necessary, truncate the string to maxChars.
if (0 < nMaxLength && nMaxLength < sValue.length()) {
sValue = sValue.substring(0, maxLength.getValue());
}
}
return sValue;
}
/**
* For XML node children, get the value within this element
*
* @param values
* a list of values
*/
public void getValues(List values) {
// watson bug 1570212, when getValues is called handle the case when
// we have null or if the values isn't a multi select node. We run into
// this if only one value is selected on a multi select list.
if (!getIsNull()) {
// watson bug 1570212
// If there's a child on the XFA side, we need to
// see if it's a multiselect node
Node child = getOneOfChild(true, false);
if (child instanceof XMLMultiSelectNode) {
((XMLMultiSelectNode)child).getValues(values);
}
else {
String sValue = getValue(false, false, true);
values.add(sValue);
}
}
}
/**
* Text children of exData cannot be processed at parse time.
* This processing is deferred to postLoad processing.
*
* @exclude from published api.
*/
public boolean processTextChildrenDuringParse() {
return false;
}
/**
* @see Element#loadXML(InputStream, boolean, ReplaceContent)
*/
public void loadXML(InputStream sInFile, boolean bIgnoreAggregatingTag, ReplaceContent eReplaceContent) {
// Load the xml fragment into the XMLDOM
// exData can only have one child - so clear any existing content before new load
removeXmlChildren();
// JavaPort: We can't call super.loadXML since this exData could be in a FormModel,
// which explicitly doesn't allow loadXML.
Document doc = getOwnerDocument();
Element imported = doc.loadIntoDocument(sInFile);
Element startNode = imported.getFirstXMLChildElement();
if (startNode == null)
return;
if (!bIgnoreAggregatingTag) {
setContent(startNode, false);
}
else {
startNode = startNode.getFirstXMLChildElement();
if (startNode != null)
setContent(startNode, false);
}
}
public void setContent(Node domNode, boolean bDefault /* = false */) {
mbIsNullDetermined = false;
// Removing the Nil Attribute prior to populating the DOM structure,
// so that getIsNull() does not mask the visibility of data presence in the DOM.
// Fix for Watson bug#1242681 referring to Global binding changes in RTF.
removeXsiNilAttribute();
// Get the ExDataValueModelImpl
Model model = getModel();
Element element = null;
if (domNode instanceof Element)
element = (Element)domNode;
// Check to see if this is an html fragment
if (element != null &&
(element.getNS() == STRS.XHTMLNS ||
element.getLocalName() == STRS.BODY ||
element.getLocalName() == STRS.XHTML)) {
StringAttr prop = new StringAttr(XFA.CONTENTTYPE, STRS.TEXTHTML);
setAttribute(prop, XFA.CONTENTTYPETAG);
// Convert domNode into a RichTextNode
RichTextNode richTextNode = new RichTextNode(null, null);
copyDomElementOntoXfa(element, richTextNode);
removeXmlChildren();
setOneOfChild(richTextNode);
if (!bDefault)
makeNonDefault(false);
// Do we need to bump the template version?
// Only need to validate to bump version if bumpVersionOnRichTextLoad has been
// set - it is false by default and will be set true by Designer.
if (getAppModel() != null && getAppModel().bumpVersionOnRichTextLoad()) {
if (!validateUsage(richTextNode.getVersionRequired(), 0, true)) {
// child first then parent
// TODO need better error here
MsgFormatPos reason = new MsgFormatPos(ResId.InvalidChildVersionException);
reason.format("");
reason.format(element.getClassAtom());
model.addErrorList(new ExFull(reason), LogMessage.MSG_WARNING, this);
}
}
notifyPeers(VALUE_CHANGED, "", null);
}
else if (getAttribute(XFA.CONTENTTYPETAG).toString().equals(STRS.TEXTXML)) {
// multi-select choice list values
Node newContent = null;
if (element != null) {
// Convert domNode into an XMLMultiSelectNode
XMLMultiSelectNode xmlMultiSelectNode = new XMLMultiSelectNode(null, null);
copyDomElementOntoXfa(element, xmlMultiSelectNode);
newContent = xmlMultiSelectNode;
}
else if (domNode instanceof TextNode) {
newContent = domNode;
}
removeXmlChildren();
setOneOfChild(newContent);
if (!bDefault)
makeNonDefault(false);
notifyPeers(VALUE_CHANGED, "", null);
} else {
// If the contentType is text/html, then clear it. So the content
// won't be treated as richtext
if (getAttribute(XFA.CONTENTTYPETAG).toString().equals(STRS.TEXTHTML)) {
StringAttr prop = new StringAttr(XFA.CONTENTTYPE, "");
setAttribute(prop, XFA.CONTENTTYPETAG);
}
// text nodes
if (domNode instanceof TextNode) {
removeXmlChildren();
setOneOfChild(domNode);
if (!bDefault)
makeNonDefault(false);
notifyPeers(VALUE_CHANGED, "", null);
}
else {
// JavaPort: In the C++, loadXML will have appended domNode to the
// peer, even if we log an error here.
appendChild(domNode, false);
// Note that the unknown content is left in place as generic nodes
// (of class XFA.INVALID_ELEMENT). This replicates the C++ behaviour
// where there would be no child element of exData in the XFA DOM, but there
// would be a child in the XML DOM.
// Give an error, unknown content
// Log a warning, invalid content type.
// %1 is unable to support the specified content. Hint(%2)
MsgFormatPos format = new MsgFormatPos(ResId.UnsupportedContentWarning);
format.format(getClassAtom());
format.format(domNode.getName());
ExFull err = new ExFull(format);
// TODO JavaPort: start using log severities
model.addErrorList(err, LogMessage.MSG_WARNING /* 0 */, this);
}
}
}
private void removeXmlChildren() {
Node child = getFirstXMLChild();
while (child != null) {
removeChild(child);
child = getFirstXMLChild();
}
}
/**
* Copies an XML DOM element onto an existing XFA element.
* This is used in the case where in C++ a RichTextNode or XMLMultiSelectNode would
* be peered to an XML DOM node. In XFA4J, the the XFA node represents both the
* XFA and XML DOM node. The children of domNode need to be moved to the XFA node
* since there is no XML DOM. This assumes that domNode has already been imported
* so it doesn't need to be copied again.
*
* @param domNode the XML DOM node that is being peered to xfaNode.
* @param xfaNode the RichTextNode or XMLMultiSelectNode that is being peered.
*/
private void copyDomElementOntoXfa(Element domNode, Element xfaNode) {
// JavaPort: in C++, the RichTextNode would be peered to domNode, but
// here it replaces it.
xfaNode.setModel(getModel());
xfaNode.setDocument(getOwnerDocument());
xfaNode.setDOMProperties(domNode.getNS(), domNode.getLocalName(), domNode.getXMLName(), null);
// Copy attributes
for (int i = 0; i < domNode.getNumAttrs(); i++) {
Attribute a = domNode.getAttr(i);
xfaNode.setAttribute(a.getNS(), a.getQName(), a.getLocalName(), a.getAttrValue(), false);
}
// Node children
// The child nodes have already been imported, and can simply be copied.
Node nextSibling;
for (Node child = domNode.getFirstXMLChild(); child != null; child = nextSibling) {
nextSibling = child.getNextXMLSibling();
xfaNode.appendChild(child);
}
}
/**
* For XML node children, set the value within this element
*
* @param values
* a list of values to set. (Strings)
*/
public void setValue(List values) {
if (getAttribute(XFA.CONTENTTYPETAG).toString().equals(STRS.TEXTXML)) {
if (getFirstXFAChild() != null) {
// multi-select choice list values
Node child = getFirstXFAChild();
if (child instanceof XMLMultiSelectNode) {
((XMLMultiSelectNode)child).setValues(values);
return; // we are done;
}
// invalid content, remove all the children
while (getFirstXMLChild() != null) {
getFirstXMLChild().remove();
}
}
// create the XMLMULTISELECTNODETAG
Model model = getModel();
XMLMultiSelectNode newNode = (XMLMultiSelectNode)model.getSchema().getInstance(
XFA.XMLMULTISELECTNODETAG, model, this, null, false);
// watson 1776125 we must create our own dom node since #xml is not valid xml.
// To find the name go up and get the fields/draw name if that doesn't exist default to "items".
Element parent = getXFAParent();
while (parent != null && !parent.isContainer())
parent = parent.getXFAParent();
String aName = XFA.ITEMS;
if (parent != null)
aName = parent.getName();
// create the dom node with the same name as the field/draw.
newNode.setLocalName(aName);
// save the values
newNode.setValues(values);
}
else {
String sValue = (String) values.get(0);
setValue(sValue);
}
}
/**
* Set the text value within this element
*
* @param sText
* a string to set/replace the text stored in this element
*/
public void setValue(String sText) {
String sContent = getAttribute(XFA.CONTENTTYPETAG).toString();
if (sContent.equals(STRS.TEXTXML)) {
// watson bug 1856188 we may not have a multi select node,
// so call setValue() with a string list since this function
// can create a new multi select node.
// parse input string, each line is a new item value
List selectionList = new ArrayList();
if (!StringUtils.isEmpty(sText)) {
StringTokenizer tokenizer = new StringTokenizer(sText, "\n");
while (tokenizer.hasMoreTokens()) {
selectionList.add(tokenizer.nextToken());
}
}
setValue(selectionList);
} else {
// if we're assigning plain text to a rich text field, then change
// the content type.
if (StringUtils.isEmpty(sContent) || sContent.equals(STRS.TEXTHTML))
setAttribute(new StringAttr(XFA.CONTENTTYPE, STRS.TEXTPLAIN), XFA.CONTENTTYPETAG);
setStrValue(sText, true, false);
}
}
/**
* Cast this element to a String. This allows this object to be used in
* contexts where a string is expected without needing to explicitly call
* getValue().
*
* @return the text value.
*/
public String toString() {
return getValue(false, false, true);
}
}