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

net.sf.jasperreports.engine.util.JRStyledTextParser Maven / Gradle / Ivy

There is a newer version: 6.21.3
Show newest version
/*
 * JasperReports - Free Java Reporting Library.
 * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com
 *
 * Unless you have purchased a commercial license agreement from Jaspersoft,
 * the following license terms apply:
 *
 * This program is part of JasperReports.
 *
 * JasperReports is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JasperReports is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with JasperReports. If not, see .
 */
package net.sf.jasperreports.engine.util;

import java.awt.Color;
import java.awt.GraphicsEnvironment;
import java.awt.font.TextAttribute;
import java.io.IOException;
import java.io.StringReader;
import java.lang.ref.SoftReference;
import java.text.AttributedCharacterIterator;
import java.text.AttributedCharacterIterator.Attribute;
import java.text.AttributedString;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import net.sf.jasperreports.engine.JRPrintHyperlink;
import net.sf.jasperreports.engine.JRPrintHyperlinkParameter;
import net.sf.jasperreports.engine.JRPrintHyperlinkParameters;
import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.base.JRBasePrintHyperlink;
import net.sf.jasperreports.engine.fonts.FontFamily;
import net.sf.jasperreports.engine.type.HyperlinkTypeEnum;
import net.sf.jasperreports.engine.util.JRStyledText.Run;
import net.sf.jasperreports.extensions.ExtensionsEnvironment;


/**
 * @author Teodor Danciu ([email protected])
 */
public class JRStyledTextParser implements ErrorHandler
{
	private static final Log log = LogFactory.getLog(JRStyledTextParser.class);

	private static final Set AVAILABLE_FONT_FACE_NAMES = new HashSet();
	static
	{
		//FIXME doing this in a static block obscures exceptions, move it to some other place
		try
		{
			//FIXMEFONT do some cache
			//FIXME these should be taken from the current JasperReportsContext
			List families = ExtensionsEnvironment.getExtensionsRegistry().getExtensions(FontFamily.class);
			for (Iterator itf = families.iterator(); itf.hasNext();)
			{
				FontFamily family =itf.next();
				AVAILABLE_FONT_FACE_NAMES.add(family.getName());
			}
			
			//FIXME use JRGraphEnvInitializer
			AVAILABLE_FONT_FACE_NAMES.addAll(
				Arrays.asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames())
				);
		}
		catch (Exception e)
		{
			log.error("Error while loading available fonts", e);
			throw e;
		}
	}

	/**
	 *
	 */
	private static final String ROOT_START = "";
	private static final String ROOT_END = "";
	private static final String NODE_style = "style";
	private static final String NODE_bold = "b";
	private static final String NODE_italic = "i";
	private static final String NODE_underline = "u";
	private static final String NODE_sup = "sup";
	private static final String NODE_sub = "sub";
	private static final String NODE_font = "font";
	private static final String NODE_br = "br";
	private static final String NODE_li = "li";
	private static final String NODE_a = "a";
	private static final String NODE_param = "param";
	private static final String ATTRIBUTE_fontName = "fontName";
	private static final String ATTRIBUTE_fontFace = "face";
	private static final String ATTRIBUTE_color = "color";
	private static final String ATTRIBUTE_size = "size";
	private static final String ATTRIBUTE_isBold = "isBold";
	private static final String ATTRIBUTE_isItalic = "isItalic";
	private static final String ATTRIBUTE_isUnderline = "isUnderline";
	private static final String ATTRIBUTE_isStrikeThrough = "isStrikeThrough";
	private static final String ATTRIBUTE_forecolor = "forecolor";
	private static final String ATTRIBUTE_backcolor = "backcolor";
	private static final String ATTRIBUTE_pdfFontName = "pdfFontName";
	private static final String ATTRIBUTE_pdfEncoding = "pdfEncoding";
	private static final String ATTRIBUTE_isPdfEmbedded = "isPdfEmbedded";
	private static final String ATTRIBUTE_type = "type";
	private static final String ATTRIBUTE_href = "href";
	private static final String ATTRIBUTE_target = "target";
	private static final String ATTRIBUTE_name = "name";
	private static final String ATTRIBUTE_valueClass = "valueClass";

	private static final String SPACE = " ";
	private static final String EQUAL_QUOTE = "=\"";
	private static final String QUOTE = "\"";
	private static final String LESS = "<";
	private static final String LESS_SLASH = "";
	
	/**
	 * Thread local soft cache of instances.
	 */
	private static final ThreadLocal> threadInstances = new ThreadLocal>();
	
	/**
	 * 
	 */
	private static final ThreadLocal threadLocale = new ThreadLocal();
	
	/**
	 * Return a cached instance.
	 * 
	 * @return a cached instance
	 */
	public static JRStyledTextParser getInstance()
	{
		JRStyledTextParser instance = null;
		SoftReference instanceRef = threadInstances.get();
		if (instanceRef != null)
		{
			instance =  instanceRef.get();
		}
		if (instance == null)
		{
			instance = new JRStyledTextParser();
			threadInstances.set(new SoftReference(instance));
		}
		return instance;
	}
	

	/**
	 * 
	 */
	public static void setLocale(Locale locale)
	{
		threadLocale.set(locale);
	}
	
	/**
	 * 
	 */
	public static Locale getLocale()
	{
		return threadLocale.get();
	}
	
	/**
	 *
	 */
	private DocumentBuilder documentBuilder;
	
	/**
	 *
	 */
	private JRBasePrintHyperlink hyperlink;


	/**
	 *
	 */
	private JRStyledTextParser()
	{
		try
		{
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			factory.setFeature(JRXmlUtils.FEATURE_DISALLOW_DOCTYPE, true);
			
			documentBuilder = factory.newDocumentBuilder();
			documentBuilder.setErrorHandler(this);
		}
		catch (ParserConfigurationException e)
		{
			throw new JRRuntimeException(e);
		}
	}


	/**
	 *
	 */
	public JRStyledText parse(Map attributes, String text, Locale locale) throws SAXException
	{
		JRStyledText styledText = new JRStyledText(locale);
		
		Document document = null;

		try
		{
			document = documentBuilder.parse(new InputSource(new StringReader(ROOT_START + text + ROOT_END)));
		}
		catch (IOException e)
		{
			throw new JRRuntimeException(e);
		}
		
		hyperlink = null;
		
		parseStyle(styledText, document.getDocumentElement());
		
		styledText.setGlobalAttributes(attributes);
		
		return styledText;
	}

	/**
	 * Creates a styled text object by either parsing a styled text String or
	 * by wrapping an unstyled String.
	 * 
	 * @param parentAttributes the element-level styled text attributes
	 * @param text the (either styled or unstyled) text
	 * @param isStyledText flag indicating that the text is styled
	 * @param locale the locale for the text
	 * @return a styled text object
	 */
	public JRStyledText getStyledText(Map parentAttributes, String text, boolean isStyledText, Locale locale)
	{
		JRStyledText styledText = null;
		if (isStyledText)
		{
			try
			{
				styledText = parse(parentAttributes, text, locale);
			}
			catch (SAXException e)
			{
				//ignore if invalid styled text and treat like normal text
			}
		}
	
		if (styledText == null)
		{
			// using the original String object instead without creating a buffer and a String copy
			styledText = new JRStyledText(locale, text, parentAttributes);
		}
		
		return styledText;
	}
	
	/**
	 * Outputs a styled text String given a styled text instance.
	 * 
	 * @param styledText the styled text object
	 * @return the String styled text representation
	 */
	public String write(JRStyledText styledText)
	{
		return write(styledText.getGlobalAttributes(), 
				styledText.getAttributedString().getIterator(), 
				styledText.getText());
	}
	
	/**
	 * Outputs a styled text String given a set of element-level styled text
	 * attributes and a styled text in the form of a String text and an iterator
	 * of style attributes.
	 * 
	 * @param parentAttrs the element-level styled text attributes
	 * @param iterator iterator of styled text attributes
	 * @param text the text
	 * @return the String styled text representation
	 */
	public String write(Map parentAttrs, AttributedCharacterIterator iterator, String text)
	{
		StringBuilder sb = new StringBuilder();
		
		int runLimit = 0;

		while(runLimit < iterator.getEndIndex() && (runLimit = iterator.getRunLimit()) <= iterator.getEndIndex())
		{
			String chunk = text.substring(iterator.getIndex(), runLimit);
			Map attrs = iterator.getAttributes();
			
			StringBuilder styleBuilder = writeStyleAttributes(parentAttrs, attrs);
			if (styleBuilder.length() > 0)
			{
				sb.append(LESS);
				sb.append(NODE_style);
				sb.append(styleBuilder.toString());
				sb.append(GREATER);
				writeChunk(sb, parentAttrs, attrs, chunk);
				sb.append(LESS_SLASH);
				sb.append(NODE_style);
				sb.append(GREATER);
			}
			else
			{
				writeChunk(sb, parentAttrs, attrs, chunk);
			}

			iterator.setIndex(runLimit);
		}
		
		return sb.toString();
	}

	/**
	 * Outputs the String representation of a styled text chunk.
	 * 
	 * @param styledText the styled text
	 * @param startIndex the start index
	 * @param endIndex the end index
	 * @return the String styled text representation of the chunk delimited by
	 * the start index and the end index
	 * @see #write(Map, AttributedCharacterIterator, String)
	 */
	public String write(JRStyledText styledText, 
			int startIndex, int endIndex)
	{
		AttributedCharacterIterator subIterator = new AttributedString(
				styledText.getAttributedString().getIterator(), 
				startIndex, endIndex).getIterator();
		String subText = styledText.getText().substring(startIndex, endIndex);
		return write(styledText.getGlobalAttributes(), subIterator, subText);
	}

	/**
	 *
	 */
	public void writeChunk(StringBuilder sb, Map parentAttrs, Map attrs, String chunk)
	{
		Object value = attrs.get(TextAttribute.SUPERSCRIPT);
		Object oldValue = parentAttrs.get(TextAttribute.SUPERSCRIPT);

		boolean isSuper = false;
		boolean isSub = false;
		
		if (value != null && !value.equals(oldValue))
		{
			isSuper=TextAttribute.SUPERSCRIPT_SUPER.equals(value);
			isSub=TextAttribute.SUPERSCRIPT_SUB.equals(value);
		}

		String scriptNode = isSuper?NODE_sup:NODE_sub;

		if (isSuper || isSub)
		{
			sb.append(LESS);
			sb.append(scriptNode);
			sb.append(GREATER);
		}

		JRPrintHyperlink hlink = (JRPrintHyperlink)attrs.get(JRTextAttribute.HYPERLINK);
		if (hlink != null)
		{
			sb.append(LESS);
			sb.append(NODE_a);

			String href = hlink.getHyperlinkReference();
			if (href != null && href.trim().length() > 0)
			{
				sb.append(SPACE);
				sb.append(ATTRIBUTE_href);
				sb.append(EQUAL_QUOTE);
				sb.append(JRStringUtil.htmlEncode(href));
				sb.append(QUOTE);
			}
			
			String type = hlink.getLinkType();
			if (type != null && type.trim().length() > 0)
			{
				sb.append(SPACE);
				sb.append(ATTRIBUTE_type);
				sb.append(EQUAL_QUOTE);
				sb.append(type);
				sb.append(QUOTE);
			}
			
			String target = hlink.getLinkTarget();
			if (target != null && target.trim().length() > 0)
			{
				sb.append(SPACE);
				sb.append(ATTRIBUTE_target);
				sb.append(EQUAL_QUOTE);
				sb.append(target);
				sb.append(QUOTE);
			}
			
			sb.append(GREATER);
			
			JRPrintHyperlinkParameters parameters = hlink.getHyperlinkParameters();
			if (parameters != null && parameters.getParameters() != null)
			{
				for (JRPrintHyperlinkParameter parameter : parameters.getParameters())
				{
					sb.append(LESS);
					sb.append(NODE_param);
					sb.append(SPACE);
					sb.append(ATTRIBUTE_name);
					sb.append(EQUAL_QUOTE);
					sb.append(parameter.getName());
					sb.append(QUOTE);
					sb.append(GREATER);
					
					if (parameter.getValue() != null)
					{
						String strValue = JRValueStringUtils.serialize(parameter.getValueClass(), parameter.getValue());
						sb.append(JRStringUtil.xmlEncode(strValue));
					}

					sb.append(LESS_SLASH);
					sb.append(NODE_param);
					sb.append(GREATER);
				}
			}
		}

		sb.append(JRStringUtil.xmlEncode(chunk));

		if (hlink != null)
		{
			sb.append(LESS_SLASH);
			sb.append(NODE_a);
			sb.append(GREATER);
		}

		if (isSuper || isSub)
		{
			sb.append(LESS_SLASH);
			sb.append(scriptNode);
			sb.append(GREATER);
		}
	}

	/**
	 *
	 */
	private void parseStyle(JRStyledText styledText, Node parentNode) throws SAXException
	{
		NodeList nodeList = parentNode.getChildNodes();
		for(int i = 0; i < nodeList.getLength(); i++)
		{
			Node node = nodeList.item(i);
			if (node.getNodeType() == Node.TEXT_NODE)
			{
				styledText.append(node.getNodeValue());
			}
			else if (
				node.getNodeType() == Node.ELEMENT_NODE
				&& NODE_style.equals(node.getNodeName())
				)
			{
				NamedNodeMap nodeAttrs = node.getAttributes();

				Map styleAttrs = new HashMap();

				if (nodeAttrs.getNamedItem(ATTRIBUTE_fontName) != null)
				{
					styleAttrs.put(
						TextAttribute.FAMILY,
						nodeAttrs.getNamedItem(ATTRIBUTE_fontName).getNodeValue()
						);
				}

				if (nodeAttrs.getNamedItem(ATTRIBUTE_isBold) != null)
				{
					styleAttrs.put(
						TextAttribute.WEIGHT,
						Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isBold).getNodeValue())
						? TextAttribute.WEIGHT_BOLD : TextAttribute.WEIGHT_REGULAR
						);
				}

				if (nodeAttrs.getNamedItem(ATTRIBUTE_isItalic) != null)
				{
					styleAttrs.put(
						TextAttribute.POSTURE,
						Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isItalic).getNodeValue())
						? TextAttribute.POSTURE_OBLIQUE : TextAttribute.POSTURE_REGULAR
						);
				}

				if (nodeAttrs.getNamedItem(ATTRIBUTE_isUnderline) != null)
				{
					styleAttrs.put(
						TextAttribute.UNDERLINE,
						Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isUnderline).getNodeValue())
						? TextAttribute.UNDERLINE_ON : null
						);
				}

				if (nodeAttrs.getNamedItem(ATTRIBUTE_isStrikeThrough) != null)
				{
					styleAttrs.put(
						TextAttribute.STRIKETHROUGH,
						Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isStrikeThrough).getNodeValue())
						? TextAttribute.STRIKETHROUGH_ON : null
						);
				}

				if (nodeAttrs.getNamedItem(ATTRIBUTE_size) != null)
				{
					styleAttrs.put(
						TextAttribute.SIZE,
						Float.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_size).getNodeValue())
						);
				}

				if (nodeAttrs.getNamedItem(ATTRIBUTE_pdfFontName) != null)
				{
					styleAttrs.put(
						JRTextAttribute.PDF_FONT_NAME,
						nodeAttrs.getNamedItem(ATTRIBUTE_pdfFontName).getNodeValue()
						);
				}

				if (nodeAttrs.getNamedItem(ATTRIBUTE_pdfEncoding) != null)
				{
					styleAttrs.put(
						JRTextAttribute.PDF_ENCODING,
						nodeAttrs.getNamedItem(ATTRIBUTE_pdfEncoding).getNodeValue()
						);
				}

				if (nodeAttrs.getNamedItem(ATTRIBUTE_isPdfEmbedded) != null)
				{
					styleAttrs.put(
						JRTextAttribute.IS_PDF_EMBEDDED,
						Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isPdfEmbedded).getNodeValue())
						);
				}

				if (nodeAttrs.getNamedItem(ATTRIBUTE_forecolor) != null)
				{
					Color color = 
						JRColorUtil.getColor(
							nodeAttrs.getNamedItem(ATTRIBUTE_forecolor).getNodeValue(),
							Color.black
							);
					styleAttrs.put(
						TextAttribute.FOREGROUND,
						color
						);
				}

				if (nodeAttrs.getNamedItem(ATTRIBUTE_backcolor) != null)
				{
					Color color = 
						JRColorUtil.getColor(
							nodeAttrs.getNamedItem(ATTRIBUTE_backcolor).getNodeValue(),
							Color.black
							);
					styleAttrs.put(
						TextAttribute.BACKGROUND,
						color
						);
				}

				int startIndex = styledText.length();

				parseStyle(styledText, node);

				styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length()));
			}
			else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_bold.equalsIgnoreCase(node.getNodeName()))
			{
				Map styleAttrs = new HashMap();
				styleAttrs.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);

				int startIndex = styledText.length();

				parseStyle(styledText, node);

				styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length()));
			}
			else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_italic.equalsIgnoreCase(node.getNodeName()))
			{
				Map styleAttrs = new HashMap();
				styleAttrs.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);

				int startIndex = styledText.length();

				parseStyle(styledText, node);

				styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length()));
			}
			else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_underline.equalsIgnoreCase(node.getNodeName()))
			{
				Map styleAttrs = new HashMap();
				styleAttrs.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);

				int startIndex = styledText.length();

				parseStyle(styledText, node);

				styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length()));
			}
			else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_sup.equalsIgnoreCase(node.getNodeName()))
			{
				Map styleAttrs = new HashMap();
				styleAttrs.put(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER);

				int startIndex = styledText.length();

				parseStyle(styledText, node);

				styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length()));
			}
			else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_sub.equalsIgnoreCase(node.getNodeName()))
			{
				Map styleAttrs = new HashMap();
				styleAttrs.put(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB);

				int startIndex = styledText.length();

				parseStyle(styledText, node);

				styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length()));
			}
			else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_font.equalsIgnoreCase(node.getNodeName()))
			{
				NamedNodeMap nodeAttrs = node.getAttributes();

				Map styleAttrs = new HashMap();

				if (nodeAttrs.getNamedItem(ATTRIBUTE_size) != null)
				{
					styleAttrs.put(
						TextAttribute.SIZE,
						Float.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_size).getNodeValue())
						);
				}

				if (nodeAttrs.getNamedItem(ATTRIBUTE_color) != null)
				{
					Color color = 
						JRColorUtil.getColor(
							nodeAttrs.getNamedItem(ATTRIBUTE_color).getNodeValue(),
							Color.black
							);
					styleAttrs.put(
						TextAttribute.FOREGROUND,
						color
						);
				}

				if (nodeAttrs.getNamedItem(ATTRIBUTE_fontFace) != null) 
				{
					String fontFaces = nodeAttrs.getNamedItem(ATTRIBUTE_fontFace).getNodeValue();

					StringTokenizer t = new StringTokenizer(fontFaces, ",");
					while (t.hasMoreTokens()) 
					{
						String face = t.nextToken().trim();
						if (AVAILABLE_FONT_FACE_NAMES.contains(face)) 
						{
							styleAttrs.put(TextAttribute.FAMILY, face);
							break;
						}
					}
				}
				
				int startIndex = styledText.length();

				parseStyle(styledText, node);

				styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length()));

			}
			else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_br.equalsIgnoreCase(node.getNodeName()))
			{
				styledText.append("\n");

				int startIndex = styledText.length();
				resizeRuns(styledText.getRuns(), startIndex, 1);

				parseStyle(styledText, node);
				styledText.addRun(new JRStyledText.Run(new HashMap(), startIndex, styledText.length()));

				if (startIndex < styledText.length()) {
					styledText.append("\n");
					resizeRuns(styledText.getRuns(), startIndex, 1);
				}
			}
			else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_li.equalsIgnoreCase(node.getNodeName()))
			{
				String tmpText = styledText.getText();
				if(tmpText.length() > 0 && !tmpText.endsWith("\n"))
				{
					styledText.append("\n");
				}
				styledText.append(" \u2022 ");

				int startIndex = styledText.length();
				resizeRuns(styledText.getRuns(), startIndex, 1);
				parseStyle(styledText, node);
				styledText.addRun(new JRStyledText.Run(new HashMap(), startIndex, styledText.length()));
				
				// if the text in the next node does not start with a '\n', or 
				// if the next node is not a 
  • one, we have to append a new line Node nextNode = node.getNextSibling(); String textContent = getFirstTextOccurence(nextNode); if(nextNode != null && !((nextNode.getNodeType() == Node.ELEMENT_NODE && NODE_li.equalsIgnoreCase(nextNode.getNodeName()) || (textContent != null && textContent.startsWith("\n"))) )) { styledText.append("\n"); resizeRuns(styledText.getRuns(), startIndex, 1); } } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_a.equalsIgnoreCase(node.getNodeName())) { if (hyperlink == null) { NamedNodeMap nodeAttrs = node.getAttributes(); Map styleAttrs = new HashMap(); hyperlink = new JRBasePrintHyperlink(); hyperlink.setHyperlinkType(HyperlinkTypeEnum.REFERENCE); styleAttrs.put(JRTextAttribute.HYPERLINK, hyperlink); if (nodeAttrs.getNamedItem(ATTRIBUTE_href) != null) { hyperlink.setHyperlinkReference( nodeAttrs.getNamedItem(ATTRIBUTE_href).getNodeValue()); } if (nodeAttrs.getNamedItem(ATTRIBUTE_type) != null) { hyperlink.setLinkType(nodeAttrs.getNamedItem(ATTRIBUTE_type).getNodeValue()); } if (nodeAttrs.getNamedItem(ATTRIBUTE_target) != null) { hyperlink.setLinkTarget(nodeAttrs.getNamedItem(ATTRIBUTE_target).getNodeValue()); } int startIndex = styledText.length(); parseStyle(styledText, node); styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); hyperlink = null; } else { throw new SAXException("Hyperlink tags cannot be nested."); } } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_param.equalsIgnoreCase(node.getNodeName())) { if (hyperlink == null) { throw new SAXException("Hyperlink tags must appear inside an tag only."); } else { NamedNodeMap nodeAttrs = node.getAttributes(); JRPrintHyperlinkParameter parameter = new JRPrintHyperlinkParameter(); if (nodeAttrs.getNamedItem(ATTRIBUTE_name) != null) { parameter.setName(nodeAttrs.getNamedItem(ATTRIBUTE_name).getNodeValue()); } if (nodeAttrs.getNamedItem(ATTRIBUTE_valueClass) != null) { parameter.setValueClass(nodeAttrs.getNamedItem(ATTRIBUTE_valueClass).getNodeValue()); } String strValue = node.getTextContent(); if (strValue != null) { Object value = JRValueStringUtils.deserialize(parameter.getValueClass(), strValue); parameter.setValue(value); } hyperlink.addHyperlinkParameter(parameter); } } else if (node.getNodeType() == Node.ELEMENT_NODE) { String nodeName = "<" + node.getNodeName() + ">"; throw new SAXException("Tag " + nodeName + " is not a valid styled text tag."); } } } /** * */ private void resizeRuns(List runs, int startIndex, int count) { for (int j = 0; j < runs.size(); j++) { JRStyledText.Run run = runs.get(j); if (run.startIndex <= startIndex && run.endIndex > startIndex - count) { run.endIndex += count; } } } /** * */ private StringBuilder writeStyleAttributes(Map parentAttrs, Map attrs) { StringBuilder sb = new StringBuilder(); Object value = attrs.get(TextAttribute.FAMILY); Object oldValue = parentAttrs.get(TextAttribute.FAMILY); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_fontName); sb.append(EQUAL_QUOTE); sb.append(value); sb.append(QUOTE); } value = attrs.get(TextAttribute.WEIGHT); oldValue = parentAttrs.get(TextAttribute.WEIGHT); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_isBold); sb.append(EQUAL_QUOTE); sb.append(value.equals(TextAttribute.WEIGHT_BOLD)); sb.append(QUOTE); } value = attrs.get(TextAttribute.POSTURE); oldValue = parentAttrs.get(TextAttribute.POSTURE); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_isItalic); sb.append(EQUAL_QUOTE); sb.append(value.equals(TextAttribute.POSTURE_OBLIQUE)); sb.append(QUOTE); } value = attrs.get(TextAttribute.UNDERLINE); oldValue = parentAttrs.get(TextAttribute.UNDERLINE); if ( (value == null && oldValue != null) || (value != null && !value.equals(oldValue)) ) { sb.append(SPACE); sb.append(ATTRIBUTE_isUnderline); sb.append(EQUAL_QUOTE); sb.append(value != null); sb.append(QUOTE); } value = attrs.get(TextAttribute.STRIKETHROUGH); oldValue = parentAttrs.get(TextAttribute.STRIKETHROUGH); if ( (value == null && oldValue != null) || (value != null && !value.equals(oldValue)) ) { sb.append(SPACE); sb.append(ATTRIBUTE_isStrikeThrough); sb.append(EQUAL_QUOTE); sb.append(value != null); sb.append(QUOTE); } value = attrs.get(TextAttribute.SIZE); oldValue = parentAttrs.get(TextAttribute.SIZE); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_size); sb.append(EQUAL_QUOTE); sb.append(value); sb.append(QUOTE); } value = attrs.get(JRTextAttribute.PDF_FONT_NAME); oldValue = parentAttrs.get(JRTextAttribute.PDF_FONT_NAME); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_pdfFontName); sb.append(EQUAL_QUOTE); sb.append(value); sb.append(QUOTE); } value = attrs.get(JRTextAttribute.PDF_ENCODING); oldValue = parentAttrs.get(JRTextAttribute.PDF_ENCODING); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_pdfEncoding); sb.append(EQUAL_QUOTE); sb.append(value); sb.append(QUOTE); } value = attrs.get(JRTextAttribute.IS_PDF_EMBEDDED); oldValue = parentAttrs.get(JRTextAttribute.IS_PDF_EMBEDDED); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_isPdfEmbedded); sb.append(EQUAL_QUOTE); sb.append(value); sb.append(QUOTE); } value = attrs.get(TextAttribute.FOREGROUND); oldValue = parentAttrs.get(TextAttribute.FOREGROUND); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_forecolor); sb.append(EQUAL_QUOTE); sb.append(JRColorUtil.getCssColor((Color)value)); sb.append(QUOTE); } value = attrs.get(TextAttribute.BACKGROUND); oldValue = parentAttrs.get(TextAttribute.BACKGROUND); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_backcolor); sb.append(EQUAL_QUOTE); sb.append(JRColorUtil.getCssColor((Color)value)); sb.append(QUOTE); } return sb; } /** * The method returns the first text occurrence in a given node element * @param node * @return String */ private String getFirstTextOccurence(Node node){ if(node != null) { if(node.getNodeValue() != null) { return node.getNodeValue(); } NodeList nodeList = node.getChildNodes(); for (int i=0; i< nodeList.getLength(); i++) { String firstOccurence = getFirstTextOccurence(nodeList.item(i)); if(firstOccurence != null) { return firstOccurence; } } } return null; } @Override public void error(SAXParseException e) { if(log.isErrorEnabled()) { log.error("Error parsing styled text.", e); } } @Override public void fatalError(SAXParseException e) { if(log.isFatalEnabled()) { log.fatal("Error parsing styled text.", e); } } @Override public void warning(SAXParseException e) { if(log.isWarnEnabled()) { log.warn("Error parsing styled text.", e); } } }




  • © 2015 - 2024 Weber Informatics LLC | Privacy Policy