/* ******************************************************************************
*
* Copyright 2008-2010 Hans Dijkema
*
* JRichTextEditor 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.
*
* JRichTextEditor 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 JRichTextEditor. If not, see <http://www.gnu.org/licenses/>.
*
* ******************************************************************************/
package nl.dykema.jxmlnote.report;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;
import java.io.IOException;
import java.util.Vector;
import javax.swing.Icon;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.StyleConstants;
import nl.dykema.jxmlnote.document.XMLNoteDocument;
import nl.dykema.jxmlnote.document.XMLNoteImageIcon;
import nl.dykema.jxmlnote.document.XMLNoteMark;
import nl.dykema.jxmlnote.exceptions.BadStyleException;
import nl.dykema.jxmlnote.exceptions.DefaultXMLNoteErrorHandler;
import nl.dykema.jxmlnote.interfaces.MarkMarkupProvider;
import nl.dykema.jxmlnote.interfaces.MarkMarkupProviderMaker;
import nl.dykema.jxmlnote.interfaces.MarkMarkupProvider.MarkupType;
import nl.dykema.jxmlnote.report.elements.Chunk;
import nl.dykema.jxmlnote.report.elements.Paragraph;
import nl.dykema.jxmlnote.report.elements.Tab;
import nl.dykema.jxmlnote.styles.XMLNoteParStyle;
import nl.dykema.jxmlnote.styles.XMLNoteStyleConstants;
import nl.dykema.jxmlnote.styles.XMLNoteStyles;
/**
* XMLNoteToPdf uses iText to render a XMLNoteDocument to PDF. It can be instantiated stand alone,
* in which case it sets up all that is needed to create a PDF document from an XMLNoteDocument.
* <p>
* It can also be instantiated as part of a larger iText session. In that case, it needs to be
* instantiated with an existing PDFWriter.
* <p>
* This class is not thread safe.
* <p>
* @author Hans Dijkema
*
*/
public class XMLNoteToReport {
private MarkMarkupProviderMaker _maker;
private XMLNoteMark _currentMark;
private MarkMarkupProvider _currentProvider;
private MarkTextProvider _markTextProvider;
private boolean _cancelled;
private Report _report;
/**
* This interface can be used during printing to provide extra text
* before- and after this XMLNoteMark.
*/
public interface MarkTextProvider {
/**
* Must provide text <code>XMLNoteToReport.Moment.BEFORE</code>, or <code>XMLNoteToReport.Moment.AFTER</code>
* this mark is marked in the text.
*
* @param mark The mark that is reported
* @param moment The moment of the getting of text
* @return the text
*/
public String provideText(XMLNoteMark mark,Moment moment);
}
/**
* Used in the context of MarkTextProvider
*/
public enum Moment {
BEFORE, AFTER
}
/**
* Render an other XMLNoteDocument to the pdf writer of the XMLNoteToPdf object.
*
* @param doc The XMLNoteDocument to render
*/
public void addXMLNote(XMLNoteDocument doc,MarkMarkupProviderMaker maker,MarkTextProvider prov) {
_maker=maker;
_markTextProvider=prov;
_cancelled=false;
Element root=doc.getDefaultRootElement();
int i,n;
for(i=0,n=getLastNonWhitespacePar(doc,root);i<n && !_cancelled;i++) {
addParagraph(doc,root.getElement(i));
}
}
protected int getLastNonWhitespacePar(XMLNoteDocument doc,Element root) {
int i;
for(i=root.getElementCount()-1;i>=0 && doc.isWhiteSpaceParagraph(i);i--);
return i+1;
}
protected void addParagraph(XMLNoteDocument doc,Element par) {
XMLNoteStyles styles=doc.getStyles();
String styleId=XMLNoteStyleConstants.getId(par.getAttributes());
XMLNoteParStyle style=null;
if (styleId!=null) {
style=styles.parStyle(styleId);
}
if (styleId==null) {
try {
style=styles.getDefaultStyle();
} catch (BadStyleException e) {
DefaultXMLNoteErrorHandler.exception(e);
return;
}
}
try {
Paragraph itpar=_report.createParagraph(style);
itpar.addAttributes(par.getAttributes());
addParContent(doc,itpar,par);
_report.add(itpar);
/*if (_report.willFit(itpar)) {
_report.add(itpar);
} else {
_report.hardPageBreak();
_report.add(itpar);
}*/
} catch (ReportException e) {
DefaultXMLNoteErrorHandler.exception(e);
} catch (BadLocationException e) {
DefaultXMLNoteErrorHandler.exception(e);
}
}
protected void addParContent(XMLNoteDocument doc,Paragraph itpar,Element par) throws BadLocationException, ReportException {
int i,n;
for(i=0,n=par.getElementCount();i<n;i++) {
Element chunk=par.getElement(i);
AttributeSet chunkAttrs=chunk.getAttributes();
Icon icn=StyleConstants.getIcon(chunkAttrs);
if (icn!=null) {
if (icn instanceof XMLNoteImageIcon) {
XMLNoteImageIcon ico=(XMLNoteImageIcon) icn;
try {
//Image pdfImage=getImage(ico);
Image img=getImage(ico);
Dimension sizeInPt=ico.getSizeInPt();
Chunk itchunk=_report.createChunkForWidth(img,(float) sizeInPt.getWidth());
itpar.add(itchunk);
} catch (Exception e) {
DefaultXMLNoteErrorHandler.exception(e);
}
}
} else {
boolean bold=StyleConstants.isBold(chunkAttrs);
boolean italic=StyleConstants.isItalic(chunkAttrs);
boolean underline=StyleConstants.isUnderline(chunkAttrs);
int start=chunk.getStartOffset();
int end=chunk.getEndOffset();
String txt=doc.getText(start,end-start);
int k,j,m;
for(k=0,j=0,m=txt.length();j<m;j++) {
Vector<XMLNoteMark> marks=doc.getMarksForOffset(start+j);
if (!marks.isEmpty()) {
if (_currentMark==null) {
if (k!=j) {
String c=txt.substring(k,j);
Chunk itchunk=_report.createChunk(c,bold,italic,underline);
itpar.add(itchunk);
k=j;
}
_currentMark=marks.get(0);
_currentProvider=_maker.create(_currentMark.id(), _currentMark.markClass());
if (_markTextProvider!=null) {
String t=_markTextProvider.provideText(_currentMark,Moment.BEFORE);
if (t!=null) {
outputMarkedText(itpar,t,bold,italic,underline);
}
}
} else if (_currentMark!=marks.get(0)) {
if (k!=j) {
String c=txt.substring(k,j);
if (_currentMark!=null) {
if (_markTextProvider!=null) {
String t=_markTextProvider.provideText(_currentMark,Moment.AFTER);
if (t!=null) { c+=t; }
}
}
outputMarkedText(itpar,c,bold,italic,underline);
k=j;
}
_currentMark=marks.get(0);
_currentProvider=_maker.create(_currentMark.id(), _currentMark.markClass());
if (_markTextProvider!=null) {
String t=_markTextProvider.provideText(_currentMark,Moment.BEFORE);
if (t!=null) { outputMarkedText(itpar,t,bold,italic,underline); }
}
}
} else {
if (_currentMark!=null) {
String c;
if (k!=j) {
c=txt.substring(k,j);
} else {
c="";
if (_markTextProvider!=null) {
String t=_markTextProvider.provideText(_currentMark,Moment.AFTER);
if (t!=null) { c+=t; }
}
outputMarkedText(itpar,c,bold,italic,underline);
k=j;
}
}
_currentMark=null;
_currentProvider=null;
}
switch (txt.charAt(j)) {
case '\t': String c=txt.substring(k,j);
Chunk itchunk=_report.createChunk(c,bold,italic,underline);
setChunkMarkup(itchunk);
itpar.add(itchunk);
Tab tabchunk=_report.createTab(itpar);
itpar.add(tabchunk);
k=j+1;
break;
}
}
if (k<j) {
Chunk itchunk=_report.createChunk(txt.substring(k,j),bold,italic,underline);
setChunkMarkup(itchunk);
itpar.add(itchunk);
}
}
}
}
protected void outputMarkedText(Paragraph itpar,String t,boolean bold,boolean italic,boolean underline) throws ReportException {
Chunk itchunk=_report.createChunk(t,bold,italic,underline);
Color col=_currentProvider.markColor(_currentMark);
MarkMarkupProvider.MarkupType tp=_currentProvider.type(_currentMark);
if (tp==MarkupType.MARKER) {
itchunk.setBackground(col,1.0f,1.0f,1.0f,1.0f);
} else {
itchunk.setUnderline(col, 2.0f, -3.0f );
}
Color textCol=_currentProvider.textColor(_currentMark);
if (textCol!=null) {
itchunk.setTextColor(textCol);
}
itpar.add(itchunk);
}
void setChunkMarkup(Chunk itchunk) {
if (_currentMark!=null) {
Color col=_currentProvider.markColor(_currentMark);
MarkMarkupProvider.MarkupType tp=_currentProvider.type(_currentMark);
if (tp==MarkupType.MARKER) {
itchunk.setBackground(col,1.0f,1.0f,1.0f,1.0f);
} else {
itchunk.setUnderline(col, 2.0f, -3.0f);
}
Color textCol=_currentProvider.textColor(_currentMark);
if (textCol!=null) {
itchunk.setTextColor(textCol);
}
}
}
protected Image getImage(XMLNoteImageIcon icn) throws IOException {
Dimension sizeInPt=icn.getSizeInPt();
Image pdfImage;
if (icn.getOriginal()==null) {
pdfImage=icn.getImage();
} else {
pdfImage=icn.getOriginal().getImage();
}
//return BufferedImageBuilder.getScaledInstance(pdfImage, (int) sizeInPt.getWidth(), (int) sizeInPt.getHeight());
return pdfImage;
//pdfImage.getScaledInstance((int) sizeInPt.getWidth(),(int) sizeInPt.getHeight(), Image.SCALE_SMOOTH);
}
/**
* Cancels addXMLNote() in the middle of a session
*/
public void cancel() {
_cancelled=true;
}
/**
* Writer/Document constructor
*
* @param wrt The PdfWriter to use
* @param doc The iText Document to complement
*
*/
public XMLNoteToReport(Report rep) {
_report=rep;
_maker=null;
_cancelled=false;
}
}