All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.xfa.TextNode Maven / Gradle / Ivy

There is a newer version: 2024.11.18598.20241113T125352Z-241000
Show 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;

import com.adobe.xfa.ut.ExFull;

/**
 * A class to represent the textual content of an XFA element in the DOM.
 */
public class TextNode extends Chars {

	private boolean mbIsFragment;

	/**
	 * Instantiates a text node with the given text.
	 * @param parent the node's parent, if any.
	 * @param prevSibling the node's previous sibling, if any.
	 * @param text the node's text.
	 */
	public TextNode(Element parent, Node prevSibling, String text) {
		super(parent, prevSibling, text);
		setClass(STRS.TEXTNAME, XFA.TEXTNODETAG);
	}

	/**
	 * Instantiates a text node.
	 * @param parent the node's parent, if any.
	 * @param prevSibling the node's previous sibling, if any.
	 * @param text the char array that contains our text.
	 * @param start offset into the char array to start at.
	 * @param length the number of characters to take.
	 *
	 * @exclude from published api.
	 */
	public TextNode(Element parent, Node prevSibling, char[] text, int start, int length) {
		super(parent, prevSibling, text, start, length);
		setClass(STRS.TEXTNAME, XFA.TEXTNODETAG);
	}
	
	/**
	 * @exclude from published api.
	 */
	public Node clone(Element parent) {
		return new TextNode(parent, null, getValue());
	}
		
	/**
	 * Creates a proto'ed TextNode.  Modeled on Protoable.createProto().
 	 * @exclude from published api.
	 */
	public TextNode createProto(Element oParent, String text, boolean bFull /* = false */) {
		//
		// Ensure the parent isn't null.
		//
		assert (oParent != null);
		boolean bMute = false;
		TextNode oRetNode = null;
		try {
			// Ensure createProto by default doesn't notify.
			// If it does it will notify layout and cause it to be damaged.
			// We only do this if bFull = false because bFull copies nodes without 
			// keeping the proto linkage
			if (oParent != null && ! bFull) {
				bMute = oParent.isMute();
				oParent.mute();
			}
			
			Model oModel = oParent.getModel();
			oRetNode = oModel.createTextNode(oParent, oParent.getLastXMLChild(), text);
			
			if (oRetNode != null) {
				
				if (isTransient() || oParent.isTransient() )
					oRetNode.isTransient(true, true);
				
				if (! bFull)
					oRetNode.makeDefault();
				else
					oRetNode.makeNonDefault(false);
			}
			
			if (! bMute && oParent != null)
				oParent.unMute();
		} 
		catch(ExFull oEx) {
			if (! bMute && oParent != null)
				oParent.unMute();
			throw oEx;
		}
		return oRetNode;
	}

	/**
	 * This is logically the equivalent of {@link Element#getDeltas(Element, XFAList)}, but
	 * it does not override it because TextNode does not derive from Element in XFA4J.
	 * @see Element#getDeltas(Element, XFAList)
	 * @exclude from public api.
	 */
	public void getDeltas(TextNode delta, XFAList list) {
//		 Adobe patent application tracking # B252, entitled METHOD AND SYSTEM TO PERSIST STATE, inventors: Roberto Perelman, Chris Solc, Anatole Matveief, Jeff Young, John Brinkman
//		 Adobe patent application tracking # B322, entitled METHOD AND SYSTEM TO MAINTAIN THE INTEGRITY OF A CERTIFIED DOCUMENT WHILE PERSISTING STATE IN A DYNAMIC FORM, inventors: Roberto Perelman, Chris Solc, Anatole Matveief, Jeff Young, John Brinkman
		if (isSameClass(delta) && list != null) {
			Element parent = getXFAParent();
			Element deltaParent = delta.getXFAParent();
			Delta newDelta = null;//CL#699561
			if (delta.getModel().getAppModel() != null &&
				!delta.getModel().getAppModel().getLegacySetting(AppModel.XFA_LEGACY_V32_SCRIPTING)) //bug 2603682
				newDelta = new Delta(parent, deltaParent, this, delta, "value");
			else
				newDelta = new Delta(parent, deltaParent, this, delta, "");
			list.append(newDelta);
		}
	}

	/**
	 * @exclude from published api.
	 */
	public ScriptTable getScriptTable() {
		return TextNodeScript.getScriptTable();
	}

	/**
	 * Gets this node's text value.
	 * @return the text value.
	 */
	public String getValue() {
		return getText();
	}

	/**
	 * Gets this node's text value.
	 * @param value the text value.
	 */
	public void setValue(String value, boolean bNotify /* = true */, boolean bDefault /* = false */) {
		setText(value);
		// After a "set" operation we won't be a default property anymore, and
		// we'll no longer delegate to any protos.
		if (!bDefault)
			makeNonDefault(false);
		// Watson 1298960: if directly set, need to notify peers of
		// change such that layout is aware of it.
		if (bNotify)
			notifyPeers(VALUE_CHANGED,"",null);
		//setDirty(); // Chars.setText will have dirtied
	}

	/**
	 * Is this TextNode here as a result of a fragment relationship?
	 * @return fragment state
	 *
	 * @exclude from published api.
	 */
	public boolean isFragment() {
		return mbIsFragment;
	}

	/**
	 * Set the fragment state of this node
	 * @param bFragment the fragment state
	 *
	 * @exclude from published api.
	 */
	public void isFragment(boolean bFragment) {
		mbIsFragment = bFragment;
		
		// if setting to false, set parent node to false
		if (!bFragment) {
			Element parent = getXMLParent();
			if ((parent != null) && (parent.isFragment() == true)) 
				parent.isFragment(false, false);
		}
	}

	/**
	 * @see Node#makeNonDefault(boolean)
	 * @exclude from published api.
	 */
	public void makeNonDefault(boolean bRecursive /* = false */) {
		
		super.makeNonDefault(bRecursive);
		
		if (isFragment()) {
			// If we're setting a property which is currently a result of an external
			// proto (a.k.a. fragment) load, then we're effectively setting a local property
			// override in the referencing doc and therefore need to clear the fragment flag 
			// from ancestors to allow saving of the override property.			
			isFragment(false);
			
			// Since fragments can cause dom nodes to have both fragment and transient flags 
			// (loading with externalProtosAreTransient), clearing a 'fragment' flag (e.g. in order to 
			// override a fragment property while editing in Designer) then the transient flag also 
			// needs to clear or else the override property will be lost on save.
			isTransient(false, false);
		}
	}
	

	/**
	 * Restore a delta for this TextNode
	 * @param delta the delta to restore.
	 * @exclude
	 */
	void restoreDelta(TextNode delta) {
// Adobe patent application tracking # B252, entitled METHOD AND SYSTEM TO PERSIST STATE, inventors: Roberto Perelman, Chris Solc, Anatole Matveief, Jeff Young, John Brinkman
// Adobe patent application tracking # B322, entitled METHOD AND SYSTEM TO MAINTAIN THE INTEGRITY OF A CERTIFIED DOCUMENT WHILE PERSISTING STATE IN A DYNAMIC FORM, inventors: Roberto Perelman, Chris Solc, Anatole Matveief, Jeff Young, John Brinkman
		Element parent = getXFAParent();
		if (parent != null) {
			// remove the delta from the parent
			delta.remove();
			
			// remove this node from the parent
			remove();

			// append the delta
			parent.appendChild(delta, false);

			delta.makeNonDefault(false);	
		}
	}
	
	/**
	 * Helper function for compareVersions.
	 * 
	 * @exclude from published api.
	 */
	String trimTrailingZeros(String sSource) {
		// Trim trailing 0's (and radix):
		int nKeep = sSource.length();
		boolean bRadixFound = false;
		
		for (int i = 0; i < sSource.length(); i++) {
			if (sSource.charAt(i) == '.') {
				bRadixFound = true;
				nKeep = i;
			}
			else if (bRadixFound && Character.isDigit(sSource.charAt(i)) && sSource.charAt(i) != '0') {
				nKeep = i + 1;
			}
		}
	
		return sSource.substring(0, nKeep);
	}
	
	/**
	 * Override of the corresponding Node.compareVersions.
	 * 
	 * @exclude from published api.
	 */
	protected boolean compareVersions(Node oRollbackTextNode, Node oContainer, Node.ChangeLogger oChangeLogger, Object oUserData) {
		boolean bMatches = compareVersionsBasic(oRollbackTextNode, oContainer, oChangeLogger, oUserData);
		if (! bMatches)
			return false;
		//
		// We're a leaf node.  Compare PCDATA.
		//
		String sValue = ((TextNode) oRollbackTextNode).getValue();
		//Bug#3047226: XTG does case insensitive comparison here. Need to do it explicitly in XFA4J.		
		if (! getValue().equalsIgnoreCase(sValue)) {
			bMatches = false;
	   		// Our number formatting is a bit buggy, and tends to end up with different canonical
			// formats depending on whether the source was a merge or user input.   If we did find
			// a difference, we sanitize the strings to a single canonical format (no trailing zeros
			// or radix) and try again.  Watson 2301544.
	   		Node oParent = getXFAParent();
	   		if (oParent != null && (oParent.isSameClass(XFA.FLOATTAG) || oParent.isSameClass(XFA.DECIMALTAG))) {
	   		    String sSanitizedValue = trimTrailingZeros(getValue());
	   		    String sSanitizedRollback = trimTrailingZeros(sValue);
				//Bug#3047226: XTG does case insensitive comparison here. Need to do it explicitly in XFA4J.				
	   		    if (sSanitizedValue.equalsIgnoreCase(sSanitizedRollback))
	   		        bMatches = true;
	   		}
			if (bMatches == false && oChangeLogger != null)
				logValueChangeHelper(oContainer, getValue(), oChangeLogger, oUserData);
		}
		return bMatches;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy