001 /**
002 * ========================================
003 * JFreeReport : a free Java report library
004 * ========================================
005 *
006 * Project Info: http://reporting.pentaho.org/
007 *
008 * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009 *
010 * This library is free software; you can redistribute it and/or modify it under the terms
011 * of the GNU Lesser General Public License as published by the Free Software Foundation;
012 * either version 2.1 of the License, or (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016 * See the GNU Lesser General Public License for more details.
017 *
018 * You should have received a copy of the GNU Lesser General Public License along with this
019 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020 * Boston, MA 02111-1307, USA.
021 *
022 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023 * in the United States and other countries.]
024 *
025 * ------------
026 * $Id: PrintReportProcessor.java,v 1.9 2007/04/01 18:49:31 taqua Exp $
027 * ------------
028 * (C) Copyright 2000-2005, by Object Refinery Limited.
029 * (C) Copyright 2005-2007, by Pentaho Corporation.
030 */
031
032 package org.jfree.report.modules.gui.swing.printing;
033
034 import java.awt.print.PageFormat;
035 import java.awt.print.Pageable;
036 import java.awt.print.Printable;
037
038 import org.jfree.layouting.StateException;
039 import org.jfree.layouting.modules.output.graphics.GraphicsOutputProcessor;
040 import org.jfree.layouting.modules.output.graphics.PageDrawable;
041 import org.jfree.layouting.modules.output.graphics.QueryPhysicalPageInterceptor;
042 import org.jfree.report.DataSourceException;
043 import org.jfree.report.ReportDataFactory;
044 import org.jfree.report.ReportDataFactoryException;
045 import org.jfree.report.ReportProcessingException;
046 import org.jfree.report.flow.LibLayoutReportTarget;
047 import org.jfree.report.flow.ReportJob;
048 import org.jfree.report.flow.ReportTargetState;
049 import org.jfree.report.flow.layoutprocessor.LayoutController;
050 import org.jfree.report.flow.paginating.PageState;
051 import org.jfree.report.flow.paginating.PaginatingReportProcessor;
052 import org.jfree.util.Log;
053
054 /**
055 * A paginating report processor that outputs to Pageables.
056 *
057 * @author Thomas Morgner
058 */
059 public class PrintReportProcessor extends PaginatingReportProcessor
060 implements Pageable
061 {
062 private ReportJob job;
063 private Throwable error;
064
065 public PrintReportProcessor(final ReportJob job)
066 {
067 super(new GraphicsOutputProcessor(job.getConfiguration()));
068 this.job = job;
069
070 synchronized(job)
071 {
072 final ReportDataFactory dataFactory = job.getDataFactory();
073 if (dataFactory != null)
074 {
075 dataFactory.open();
076 }
077 }
078 }
079
080 protected GraphicsOutputProcessor getGraphicsProcessor()
081 {
082 return (GraphicsOutputProcessor) getOutputProcessor();
083 }
084
085 public boolean isError()
086 {
087 return error != null;
088 }
089
090 protected ReportJob getJob()
091 {
092 return job;
093 }
094
095 public void close()
096 {
097 getJob().close();
098 }
099
100 protected PageDrawable processPage(int page)
101 throws ReportDataFactoryException,
102 DataSourceException, ReportProcessingException, StateException
103 {
104 final ReportJob job = getJob();
105 synchronized (job)
106 {
107 // set up the scene
108 final PageState state = getPhysicalPageState(page);
109
110 final ReportTargetState targetState = state.getTargetState();
111 final GraphicsOutputProcessor outputProcessor = getGraphicsProcessor();
112 outputProcessor.setPageCursor(state.getPageCursor());
113 final QueryPhysicalPageInterceptor interceptor =
114 new QueryPhysicalPageInterceptor(outputProcessor.getPhysicalPage(page));
115 outputProcessor.setInterceptor(interceptor);
116
117 final LibLayoutReportTarget target =
118 (LibLayoutReportTarget) targetState.restore(outputProcessor);
119
120 LayoutController position = state.getLayoutController();
121
122 // we have the data and we have our position inside the report.
123 // lets generate something ...
124 while (position.isAdvanceable())
125 {
126 position = position.advance(target);
127 target.commit();
128
129 while (position.isAdvanceable() == false &&
130 position.getParent() != null)
131 {
132 final LayoutController parent = position.getParent();
133 position = parent.join(position.getFlowController());
134 }
135
136 if (interceptor.isMoreContentNeeded() == false)
137 {
138 outputProcessor.setInterceptor(null);
139 return interceptor.getDrawable();
140 }
141
142 }
143
144 outputProcessor.setInterceptor(null);
145 return interceptor.getDrawable();
146 }
147 }
148
149 /**
150 * Returns the number of pages in the set. To enable advanced printing
151 * features, it is recommended that <code>Pageable</code> implementations
152 * return the true number of pages rather than the UNKNOWN_NUMBER_OF_PAGES
153 * constant.
154 *
155 * @return the number of pages in this <code>Pageable</code>.
156 */
157 public synchronized int getNumberOfPages()
158 {
159 if (isError())
160 {
161 return 0;
162 }
163
164 if (isPaginated() == false)
165 {
166 try
167 {
168 prepareReportProcessing(getJob());
169 }
170 catch (Exception e)
171 {
172 Log.debug("PrintReportProcessor: ", e);
173 error = e;
174 return 0;
175 }
176 }
177 Log.debug ("After pagination, we have " +
178 getGraphicsProcessor().getPhysicalPageCount() + " physical pages.");
179 return getGraphicsProcessor().getPhysicalPageCount();
180 }
181
182 public boolean paginate()
183 {
184 if (isError())
185 {
186 return false;
187 }
188
189 if (isPaginated() == false)
190 {
191 try
192 {
193 prepareReportProcessing(getJob());
194 return true;
195 }
196 catch (Exception e)
197 {
198 error = e;
199 return false;
200 }
201 }
202 return true;
203 }
204
205 /**
206 * Returns the <code>PageFormat</code> of the page specified by
207 * <code>pageIndex</code>.
208 *
209 * @param pageIndex the zero based index of the page whose <code>PageFormat</code>
210 * is being requested
211 * @return the <code>PageFormat</code> describing the size and orientation.
212 * @throws IndexOutOfBoundsException if the <code>Pageable</code> does not
213 * contain the requested page.
214 */
215 public synchronized PageFormat getPageFormat(final int pageIndex)
216 throws IndexOutOfBoundsException
217 {
218 if (isError())
219 {
220 return null;
221 }
222
223 if (isPaginated() == false)
224 {
225 try
226 {
227 prepareReportProcessing(getJob());
228 }
229 catch (Exception e)
230 {
231 error = e;
232 return null;
233 }
234 }
235
236 try
237 {
238 final PageDrawable pageDrawable = processPage(pageIndex);
239 return pageDrawable.getPageFormat();
240 }
241 catch (Exception e)
242 {
243 throw new IllegalStateException("Unable to return a valid pageformat.");
244 }
245 }
246
247 /**
248 * Returns the <code>Printable</code> instance responsible for rendering the
249 * page specified by <code>pageIndex</code>.
250 *
251 * @param pageIndex the zero based index of the page whose <code>Printable</code>
252 * is being requested
253 * @return the <code>Printable</code> that renders the page.
254 * @throws IndexOutOfBoundsException if the <code>Pageable</code> does not
255 * contain the requested page.
256 */
257 public synchronized Printable getPrintable(final int pageIndex)
258 throws IndexOutOfBoundsException
259 {
260 if (isError())
261 {
262 return null;
263 }
264
265 if (isPaginated() == false)
266 {
267 try
268 {
269 prepareReportProcessing(getJob());
270 }
271 catch (Exception e)
272 {
273 error = e;
274 return null;
275 }
276 }
277
278 try
279 {
280 final PageDrawable pageDrawable = processPage(pageIndex);
281 return new DrawablePrintable(pageDrawable);
282 }
283 catch (Exception e)
284 {
285 throw new IllegalStateException("Unable to return a valid pageformat.");
286 }
287 }
288
289 public PageDrawable getPageDrawable(final int pageIndex)
290 {
291 if (isError())
292 {
293 return null;
294 }
295
296 if (isPaginated() == false)
297 {
298 try
299 {
300 prepareReportProcessing(getJob());
301 }
302 catch (Exception e)
303 {
304 error = e;
305 return null;
306 }
307 }
308
309 try
310 {
311 return processPage(pageIndex);
312 }
313 catch (Exception e)
314 {
315 error = e;
316 Log.debug("Failed to process the page", e);
317 throw new IllegalStateException("Unable to return a valid pageformat.");
318 }
319 }
320
321 /**
322 * Throws an unsupported operation exception. Printing is controlled by a
323 * framework which calls this pageable class for each page. Therefore,
324 * printing has to be invoked from outside.
325 *
326 * @param job
327 * @throws UnsupportedOperationException
328 */
329 public final void processReport(final ReportJob job)
330 {
331 throw new UnsupportedOperationException("Printing is a passive process.");
332 }
333 }