/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program 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.
*
* Copyright (c) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.modules.output.table.xls.helper;
import java.awt.Color;
import java.util.ArrayList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.RichTextString;
import org.pentaho.reporting.engine.classic.core.layout.model.InlineRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderableComplexText;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorMetaData;
import org.pentaho.reporting.engine.classic.core.layout.process.text.RichTextSpec;
import org.pentaho.reporting.engine.classic.core.modules.output.table.base.DefaultTextExtractor;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.StyleSheet;
import org.pentaho.reporting.engine.classic.core.style.TextStyleKeys;
import org.pentaho.reporting.libraries.base.util.FastStack;
public class ExcelTextExtractor extends DefaultTextExtractor {
private static final Log logger = LogFactory.getLog( ExcelTextExtractor.class );
private ArrayList<RichTextFormat> formatBuffer;
private FastStack<RichTextFormat> formatBufferStack;
private ExcelColorProducer colorProducer;
private CreationHelper creationHelper;
private ExcelFontFactory fontFactory;
public ExcelTextExtractor( final OutputProcessorMetaData metaData, final ExcelColorProducer colorProducer,
final CreationHelper creationHelper, final ExcelFontFactory fontFactory ) {
super( metaData );
this.creationHelper = creationHelper;
this.fontFactory = fontFactory;
if ( colorProducer == null ) {
throw new NullPointerException();
}
this.colorProducer = colorProducer;
this.formatBuffer = new ArrayList<RichTextFormat>();
this.formatBufferStack = new FastStack<RichTextFormat>();
}
public Object compute( final RenderBox paraBox ) {
formatBuffer.clear();
super.compute( paraBox );
if ( formatBuffer.size() <= 1 ) {
// A simple result. So there's no need to create a rich-text string.
final Object rawResult = getRawResult();
if ( rawResult != null && rawResult instanceof String == false ) {
return rawResult;
}
final String text = getText();
if ( text.length() > 32767 ) {
ExcelTextExtractor.logger
.warn( "Excel-Cells cannot contain text larger than 32.737 characters. Text will be clipped." );
return text.substring( 0, 32767 );
} else if ( text.length() > 0 ) {
return text;
}
return null;
}
final String text = getText();
return computeRichText( fontFactory, creationHelper, text, formatBuffer );
}
public static RichTextString computeRichText( final ExcelFontFactory fontFactory,
final CreationHelper creationHelper, final String text, final ArrayList<RichTextFormat> buffer ) {
if ( text.length() > 0 ) {
if ( text.length() < 32768 ) {
// There's rich text.
final RichTextString rtStr = creationHelper.createRichTextString( text );
for ( int i = 0; i < buffer.size(); i++ ) {
final RichTextFormat o = buffer.get( i );
final int position = o.getPosition();
final HSSFFontWrapper font = o.getFont();
if ( i == ( buffer.size() - 1 ) ) {
// Last element ..
rtStr.applyFont( position, text.length(), fontFactory.getExcelFont( font ) );
} else {
final RichTextFormat next = buffer.get( i + 1 );
rtStr.applyFont( position, next.getPosition(), fontFactory.getExcelFont( font ) );
}
}
return rtStr;
} else {
ExcelTextExtractor.logger
.warn( "Excel-Cells cannot contain text larger than 32.737 characters. Text will be clipped." );
final String realText = text.substring( 0, 32767 );
final RichTextString rtStr = creationHelper.createRichTextString( realText );
for ( int i = 0; i < buffer.size(); i++ ) {
final RichTextFormat o = buffer.get( i );
final int position = o.getPosition();
if ( position >= 32767 ) {
break;
}
final HSSFFontWrapper font = o.getFont();
if ( i == ( buffer.size() - 1 ) ) {
// Last element ..
final int endPosition = Math.min( 32767, text.length() );
rtStr.applyFont( position, endPosition, fontFactory.getExcelFont( font ) );
} else {
final RichTextFormat next = buffer.get( i + 1 );
final int endPosition = Math.min( 32767, next.getPosition() );
rtStr.applyFont( position, endPosition, fontFactory.getExcelFont( font ) );
}
}
return rtStr;
}
}
return null;
}
protected boolean startInlineBox( final InlineRenderBox box ) {
if ( box.getStaticBoxLayoutProperties().isVisible() == false ) {
return false;
}
final StyleSheet styleSheet = box.getStyleSheet();
final Color textColor = (Color) styleSheet.getStyleProperty( ElementStyleKeys.PAINT );
final HSSFFontWrapper wrapper = new HSSFFontWrapper( styleSheet, colorProducer.getNearestColor( textColor ) );
final RichTextFormat rtf = new RichTextFormat( getTextLength(), wrapper );
// Check the style.
if ( formatBuffer.isEmpty() ) {
formatBuffer.add( rtf );
} else {
int lastIndex = formatBuffer.size() - 1;
final RichTextFormat lastRtf = formatBuffer.get( lastIndex );
if ( lastRtf.getPosition() == rtf.getPosition() ) {
formatBuffer.set( lastIndex, rtf );
} else if ( lastRtf.getFont().equals( rtf.getFont() ) == false ) {
formatBuffer.add( rtf );
}
}
formatBufferStack.push( rtf );
return true;
}
protected void finishInlineBox( final InlineRenderBox box ) {
formatBufferStack.pop();
if ( formatBufferStack.isEmpty() ) {
return;
}
RichTextFormat rtf = formatBufferStack.peek();
final RichTextFormat lastRtf = formatBuffer.get( formatBuffer.size() - 1 );
if ( lastRtf.getFont().equals( rtf.getFont() ) == false ) {
formatBuffer.add( new RichTextFormat( getTextLength(), rtf.getFont() ) );
}
}
protected void drawComplexText( final RenderableComplexText renderableComplexText ) {
if ( renderableComplexText.getRawText().length() == 0 ) {
// This text is empty.
return;
}
if ( renderableComplexText.isNodeVisible( getParagraphBounds(), isOverflowX(), isOverflowY() ) == false ) {
return;
}
// check if we have to process inline text elements
if ( renderableComplexText.getRichText().getStyleChunks().size() > 1 ) {
int relativeLength = 0;
// iterate through all inline elements
for ( RichTextSpec.StyledChunk styledChunk : renderableComplexText.getRichText().getStyleChunks() ) {
// Add style for current styled chunk
final StyleSheet styleSheet = styledChunk.getStyleSheet();
final Color textColor = (Color) styleSheet.getStyleProperty( ElementStyleKeys.PAINT );
final String fontName = (String) styleSheet.getStyleProperty( TextStyleKeys.FONT );
final short fontSize = (short) styleSheet.getIntStyleProperty( TextStyleKeys.FONTSIZE, 0 );
final boolean bold = styleSheet.getBooleanStyleProperty( TextStyleKeys.BOLD );
final boolean italic = styleSheet.getBooleanStyleProperty( TextStyleKeys.ITALIC );
final boolean underline = styleSheet.getBooleanStyleProperty( TextStyleKeys.UNDERLINED );
final boolean strikethrough = styleSheet.getBooleanStyleProperty( TextStyleKeys.STRIKETHROUGH );
final HSSFFontWrapper wrapper =
new HSSFFontWrapper( fontName, fontSize, bold, italic, underline, strikethrough, colorProducer
.getNearestColor( textColor ) );
if ( styledChunk.getOriginatingTextNode() instanceof RenderableComplexText ) {
final RichTextFormat rtf = new RichTextFormat( relativeLength, wrapper );
relativeLength += styledChunk.getText().length();
formatBuffer.add( rtf );
}
}
}
super.drawComplexText( renderableComplexText );
}
}