/**
* Copyright (C) 2008-2010, Squale Project - http://www.squale.org
*
* This file is part of Squale.
*
* Squale 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 any later version.
*
* Squale 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 General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Squale. If not, see <http://www.gnu.org/licenses/>.
*/
package org.squale.squaleweb.applicationlayer.action.export.ppt;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.swing.ImageIcon;
import javax.swing.JEditorPane;
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.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.model.Line;
import org.apache.poi.hslf.model.MasterSheet;
import org.apache.poi.hslf.model.Picture;
import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.model.Table;
import org.apache.poi.hslf.model.TableCell;
import org.apache.poi.hslf.model.TextBox;
import org.apache.poi.hslf.usermodel.RichTextRun;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.squale.squalecommon.util.xml.ParsingHandler;
import org.squale.squalecommon.util.xml.XmlResolver;
import org.squale.squaleweb.resources.WebMessages;
/**
* General data to create ppt documents
*/
public class PPTData
{
/** DTD location */
public static final String DTD_LOCATION = "/org/squale/squaleweb/resources/ppt/dtd/ppt_mapping-1.0.dtd";
/** Public id of mapping file */
public static final String PUBLIC_ID = "-//Squale//DTD PPT Mapping 1.0//EN";
/** Default font name for text box in ppt */
protected static final String DEFAULT_FONT_NAME = "Arial";
/** Default font size for text box in ppt */
protected static final int DEFAULT_FONT_SIZE = 10;
/** Default font color for text box in ppt */
protected static final Color DEFAULT_FONT_COLOR = Color.BLACK;
/** Default backgroud color for cell in ppt */
protected static final Color DEFAULT_BACKGROUND_COLOR = Color.WHITE;
/** Log */
private static Log LOGGER = LogFactory.getLog( PPTData.class );
/** Mapping indicating settings */
protected Document mapping;
/** Presentation to modify */
protected SlideShow presentation;
/** Slides of model to use */
protected Slide[] modelSlides;
/** request */
protected HttpServletRequest request;
/** Errors while parsing mapping file */
protected StringBuffer errors = new StringBuffer();
/**
* Getter for presentation attribute
*
* @return presentation
*/
public SlideShow getPresentation()
{
return presentation;
}
/**
* Create a document with mapping file
*
* @param mappingStream stream of mapping file
* @throws PPTGeneratorException if error while parsing mapping file
*/
public void setMapping( InputStream mappingStream )
throws PPTGeneratorException
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating( true );
try
{
DocumentBuilder db = dbf.newDocumentBuilder();
db.setEntityResolver( new XmlResolver( PUBLIC_ID, DTD_LOCATION ) );
db.setErrorHandler( new ParsingHandler( LOGGER, errors ) );
mapping = db.parse( mappingStream );
if ( errors.length() > 0 )
{
handleException( "export.audit_report.mapping.error", new String[] { errors.toString() } );
}
}
catch ( ParserConfigurationException e )
{
handleException( "export.audit_report.mapping.error", new String[] { e.getMessage() } );
}
catch ( SAXException e )
{
handleException( "export.audit_report.mapping.error", new String[] { e.getMessage() } );
}
catch ( IOException e )
{
handleException( "export.audit_report.mapping.error", new String[] { e.getMessage() } );
}
}
/**
* Set the presentation attribute
*
* @param pPresentationStream new presentation
* @throws PPTGeneratorException if error creating ppt
*/
public void setPresentation( InputStream pPresentationStream )
throws PPTGeneratorException
{
try
{
this.presentation = new SlideShow( pPresentationStream );
}
catch ( IOException ioe )
{
handleException( "export.audit_report.presentation.error.format" );
}
}
/**
* Getter for modelSlides attribute
*
* @return slides of model
*/
public Slide[] getModelSlides()
{
return modelSlides;
}
/**
* Set modelSlides attribute
*
* @param pModelStream the model
* @throws PPTGeneratorException if error occured while getting slides
*/
public void setModel( InputStream pModelStream )
throws PPTGeneratorException
{
try
{
SlideShow model = new SlideShow( new HSLFSlideShow( pModelStream ) );
modelSlides = model.getSlides();
}
catch ( IOException ioe )
{
handleException( "export.audit_report.model.error.format" );
}
}
/**
* Launched an PPTGeneratorException
*
* @param pKey key for exception message
* @throws PPTGeneratorException error launched
*/
private void handleException( String pKey )
throws PPTGeneratorException
{
throw new PPTGeneratorException( WebMessages.getString( request, pKey ) );
}
/**
* Launched an PPTGeneratorException
*
* @param pKey key for exception message
* @param pArgs message parameters
* @throws PPTGeneratorException error launched
*/
private void handleException( String pKey, String[] pArgs )
throws PPTGeneratorException
{
throw new PPTGeneratorException( (String) WebMessages.getString( request.getLocale(), pKey, pArgs ) );
}
/**
* Modify the presentation in function of mapping description
*
* @throws PPTGeneratorException if error occured while generating ppt
*/
public void modifyPresentation()
throws PPTGeneratorException
{
// Parse mapping
// Get class name with root tag
Element root = mapping.getDocumentElement();
// Get class name
String classname = root.getAttribute( "class" );
Class dataClass = null;
try
{
dataClass = Class.forName( classname );
}
catch ( ClassNotFoundException e )
{
throw new PPTGeneratorException( "class not found :" + classname );
}
// initalization
Class[] argsForSet = new Class[] { Slide.class, Rectangle.class };
Class[] argsForAdd = new Class[] { MasterSheet.class };
NodeList nl = root.getElementsByTagName( "*" );
for ( int i = 0; i < nl.getLength(); i++ )
{
Node curChild = nl.item( i );
String methodName = ( (Element) curChild ).getAttribute( "methodName" );
if ( curChild.getNodeName().equals( "add" ) )
{
int modelPage = Integer.parseInt( ( (Element) curChild ).getAttribute( "model" ) );
addSlide( getMethod( dataClass, methodName, argsForAdd ), modelPage );
}
else if ( curChild.getNodeName().equals( "set" ) )
{
int slide = Integer.parseInt( ( (Element) curChild ).getAttribute( "slide" ) );
String where = ( (Element) curChild ).getAttribute( "where" );
setSlide( getMethod( dataClass, methodName, argsForSet ), where, slide );
}
}
}
/**
* Get a method
*
* @param dataClass utility class
* @param methodName method to find
* @param args method's arguments
* @return corresponding method
* @throws PPTGeneratorException if error
*/
private Method getMethod( Class dataClass, String methodName, Class[] args )
throws PPTGeneratorException
{
Method methodToCall = null;
try
{
methodToCall = dataClass.getMethod( methodName, args );
}
catch ( SecurityException e )
{
handleException( "export.audit_report.mapping.error.method.access", new String[] { methodName } );
}
catch ( NoSuchMethodException e )
{
handleException( "export.audit_report.mapping.error.method.not_found", new String[] { methodName } );
}
return methodToCall;
}
/**
* Add slide at the end of the presentation
*
* @param methodToCall method to invoke to create slide
* @param modelPage model to use
* @throws PPTGeneratorException if error
*/
private void addSlide( Method methodToCall, int modelPage )
throws PPTGeneratorException
{
if ( modelPage > modelSlides.length || modelPage < 1 )
{
handleException( "export.audit_report.mapping.error.model_slide", new String[] { "" + modelPage } );
}
try
{
methodToCall.invoke( this, new Object[] { modelSlides[modelPage - 1].getMasterSheet() } );
}
catch ( IllegalArgumentException e )
{
handleException( "export.audit_report.mapping.error.method_args", new String[] { methodToCall.getName() } );
}
catch ( IllegalAccessException e )
{
handleException( "export.audit_report.mapping.error.method.access", new String[] { methodToCall.getName() } );
}
catch ( InvocationTargetException e )
{
handleException( "export.audit_report.mapping.error.method_exception", new String[] {
methodToCall.getName(), e.getMessage() } );
}
}
/**
* Set a slide
*
* @param methodToCall method to invoke to create slide
* @param where reference for setting
* @param slide page number of slide to change
* @throws PPTGeneratorException if error
*/
private void setSlide( Method methodToCall, String where, int slide )
throws PPTGeneratorException
{
if ( slide > presentation.getSlides().length || slide < 1 )
{
handleException( "export.audit_report.mapping.error.presentation_slide", new String[] { "" + slide } );
}
try
{
Slide slideToSet = getPresentation().getSlides()[slide - 1];
Rectangle whereRec = new Rectangle();
for ( int i = 0; i < slideToSet.getShapes().length; i++ )
{
if ( slideToSet.getShapes()[i] instanceof TextBox
&& ( (TextBox) slideToSet.getShapes()[i] ).getText() != null
&& where.equalsIgnoreCase( ( (TextBox) slideToSet.getShapes()[i] ).getText().trim() ) )
{
whereRec = slideToSet.getShapes()[i].getAnchor();
}
}
methodToCall.invoke( this, new Object[] { slideToSet, whereRec } );
}
catch ( IllegalArgumentException e )
{
handleException( "export.audit_report.mapping.error.method_args", new String[] { methodToCall.getName() } );
}
catch ( IllegalAccessException e )
{
handleException( "export.audit_report.mapping.error.method.access", new String[] { methodToCall.getName() } );
}
catch ( InvocationTargetException e )
{
handleException( "export.audit_report.mapping.error.method_exception", new String[] {
methodToCall.getName(), e.getMessage() } );
}
}
/**
* Getter for errors propertie
*
* @return errors occured while parsing mapping file
*/
public StringBuffer getErrors()
{
return errors;
}
/**
* Set properties of cell
*
* @param cell cell to set
* @param text text of cell
*/
protected void setTabCell( TableCell cell, String text )
{
setTabCell( cell, text, DEFAULT_FONT_NAME, DEFAULT_FONT_SIZE, DEFAULT_BACKGROUND_COLOR );
}
/**
* Set properties of a cell
*
* @param cell cell to set
* @param text text of cell
* @param fontName font name for text
* @param fontSize font name for text
* @param backgroundColor background color for cell
*/
protected void setTabCell( TableCell cell, String text, String fontName, int fontSize, Color backgroundColor )
{
setTabCell( cell, text, fontName, fontSize );
cell.setFillColor( backgroundColor );
}
/**
* Set properties of a cell
*
* @param cell cell to set
* @param text text of cell
* @param fontName font name for text
* @param fontSize font name for text
* @param bold if text in bold
* @param fontColor color of text
* @param backgroundColor background color for cell
*/
protected void setTabCell( TableCell cell, String text, String fontName, int fontSize, Color backgroundColor,
boolean bold, Color fontColor )
{
setTabCell( cell, text, fontName, fontSize, bold, fontColor );
cell.setFillColor( backgroundColor );
}
/**
* Set properties of a cell
*
* @param cell cell to set
* @param text text of cell
* @param fontName font name for text
* @param fontSize font name for text
*/
protected void setTabCell( TableCell cell, String text, String fontName, int fontSize )
{
cell.setText( text );
RichTextRun rt = cell.getTextRun().getRichTextRuns()[0];
rt.setFontName( fontName );
rt.setFontSize( fontSize );
cell.setVerticalAlignment( TextBox.AnchorMiddle );
cell.setMarginBottom( 0 );
cell.setMarginTop( 0 );
}
/**
* Set properties of a cell
*
* @param cell cell to set
* @param text text of cell
* @param fontName font name for text
* @param fontSize font name for text
* @param bold if text in bold
* @param fontColor color of text
*/
protected void setTabCell( TableCell cell, String text, String fontName, int fontSize, boolean bold, Color fontColor )
{
cell.setText( text );
RichTextRun rt = cell.getTextRun().getRichTextRuns()[0];
rt.setFontName( fontName );
rt.setFontSize( fontSize );
rt.setBold( bold );
rt.setFontColor( fontColor );
cell.setVerticalAlignment( TextBox.AnchorMiddle );
}
/**
* Create a table with black border
*
* @param nbRows number of rows
* @param nbCol number of columns
* @return the table
*/
protected Table createTableWithBorder( int nbRows, int nbCol )
{
final int columnHeight = 10;
Table table = new Table( nbRows, nbCol );
// set table borders
Line border = table.createBorder();
border.setLineColor( Color.black );
border.setLineWidth( 1.0 );
table.setAllBorders( border );
// minimize height for all row
for(int i=0; i< nbRows; i++) {
table.setRowHeight( i, columnHeight );
}
return table;
}
/**
* Add a text box in the slide
*
* @param slide slide to set
* @param text text to add
* @param fontSize font size of the text
* @param anchor place of text box
* @param isBullet if text is a list
*/
protected void addTextBox( Slide slide, String text, int fontSize, Rectangle anchor, boolean isBullet )
{
TextBox txt = new TextBox();
txt.setText( text );
txt.setAnchor( anchor );
RichTextRun rt = txt.getTextRun().getRichTextRuns()[0];
rt.setFontSize( fontSize );
rt.setBullet( isBullet );
slide.addShape( txt );
}
/**
* Add title in slide
*
* @param slide slide to set
* @param title text of title
*/
protected void addTitle( Slide slide, String title )
{
TextBox titleBox = slide.addTitle();
titleBox.setText( title );
}
/**
* Add title in slide
*
* @param slide slide to set
* @param title text of title
* @param fontSize size for font
*/
protected void addTitle( Slide slide, String title, int fontSize )
{
TextBox titleBox = slide.addTitle();
titleBox.setText( title );
RichTextRun rt = titleBox.getTextRun().getRichTextRuns()[0];
rt.setFontSize( fontSize );
}
/**
* Add graph in slide
*
* @param slideToSet slide to set
* @param graph graph to add
* @param anchor place to add graph
* @throws IOException if error
*/
protected void addJFreeChart( Slide slideToSet, JFreeChart graph, Rectangle anchor )
throws IOException
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
int width = anchor.width;
int height = anchor.height;
if ( width <= 0 )
{
width = getPresentation().getPageSize().width;
}
if ( height <= 0 )
{
height = getPresentation().getPageSize().height;
}
ChartUtilities.writeChartAsPNG( out, graph, width, height );
addPicture( slideToSet, out.toByteArray(), anchor );
}
/**
* Add a picture in a slide
*
* @param slideToSet slide to set
* @param data image data
* @param anchor place to add image
* @throws IOException if error
*/
protected void addPicture( Slide slideToSet, byte[] data, Rectangle anchor )
throws IOException
{
int idx = getPresentation().addPicture( data, Picture.PNG );
Picture pict = new Picture( idx );
pict.setAnchor( anchor );
slideToSet.addShape( pict );
}
/**
* Convert a html code to an image
*
* @param html html to convert
* @return html converted to png
* @throws IOException if error
* @throws PPTGeneratorException
*/
protected byte[] htmlToImage( String html )
throws IOException, PPTGeneratorException
{
try {
JEditorPane editor = new JEditorPane();
editor.setContentType( "text/html" );
editor.setText( html );
editor.setSize(editor.getPreferredSize());
editor.addNotify();
LOGGER.debug("Panel is built");
BufferedImage bufferSave =
new BufferedImage( editor.getPreferredSize().width, editor.getPreferredSize().height,
BufferedImage.TYPE_3BYTE_BGR );
Graphics g = bufferSave.getGraphics();
g.setColor( Color.WHITE );
g.fillRect( 0, 0, editor.getPreferredSize().width, editor.getPreferredSize().height );
editor.paint( g );
LOGGER.debug("graphics is drawn");
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write( bufferSave, "png", out );
return out.toByteArray();
} catch ( HeadlessException e ) {
LOGGER.error("X Server no initialized or -Djava.awt.headless=true not set !");
throw new PPTGeneratorException("X Server no initialized or -Djava.awt.headless=true not set !");
}
}
/**
* Add an image with a html code without change its dimension
*
* @param slideToSet slide to set
* @param html html code
* @param x horizontal position
* @param y vertical position
* @throws IOException if error
* @throws PPTGeneratorException
*/
protected void addHtmlPicture( Slide slideToSet, String html, int x, int y ) throws IOException, PPTGeneratorException
{
try {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
if ( ! ge.isHeadlessInstance() ) {
LOGGER.warn("Runtime is not configured for supporting graphiv manipulation !");
}
JEditorPane editor = new JEditorPane();
editor.setContentType( "text/html" );
editor.setText( html );
LOGGER.debug("Editor pane is built");
editor.setSize(editor.getPreferredSize());
editor.addNotify(); // Serveur X requis
LOGGER.debug("Panel rendering is done");
BufferedImage bufferSave =
new BufferedImage( editor.getPreferredSize().width, editor.getPreferredSize().height,
BufferedImage.TYPE_3BYTE_BGR );
Graphics g = bufferSave.getGraphics();
g.setColor( Color.WHITE );
g.fillRect( 0, 0, editor.getPreferredSize().width, editor.getPreferredSize().height );
editor.paint( g );
LOGGER.debug("graphics is drawn");
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write( bufferSave, "png", out );
LOGGER.debug("image is written");
addPicture( slideToSet, out.toByteArray(), new Rectangle(x, y, editor.getPreferredSize().width, editor.getPreferredSize().height) );
LOGGER.debug("image is added");
} catch ( HeadlessException e ) {
LOGGER.error("X Server no initialized or -Djava.awt.headless=true not set !");
throw new PPTGeneratorException("X Server no initialized or -Djava.awt.headless=true not set !");
}
}
private BufferedImage convertImgToBufferedImg(Image limage, String l)
{
if(limage instanceof BufferedImage)
{
return((BufferedImage)limage);
}
else
{
Image lImage = new ImageIcon(limage).getImage();
BufferedImage bufferedimage = new BufferedImage(lImage.getWidth(null),
lImage.getHeight(null),
BufferedImage.TYPE_INT_RGB);
Graphics gr = bufferedimage.createGraphics();
gr.drawImage(lImage,0,0,null);
gr.dispose();
return(bufferedimage);
}
}
}