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: ReportProgressDialog.java,v 1.3 2007/04/01 18:49:30 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.common;
033
034 import java.awt.Dialog;
035 import java.awt.Frame;
036 import java.awt.GridBagConstraints;
037 import java.awt.GridBagLayout;
038 import java.awt.Insets;
039 import java.awt.event.WindowAdapter;
040 import java.awt.event.WindowEvent;
041 import java.text.MessageFormat;
042 import java.util.ResourceBundle;
043 import javax.swing.JDialog;
044 import javax.swing.JLabel;
045 import javax.swing.JPanel;
046 import javax.swing.JProgressBar;
047 import javax.swing.SwingUtilities;
048 import javax.swing.border.EmptyBorder;
049
050 import org.jfree.report.event.ReportProgressEvent;
051 import org.jfree.report.event.ReportProgressListener;
052 import org.jfree.report.modules.gui.common.GuiCommonModule;
053
054
055 /**
056 * A progress monitor dialog component that visualizes the report processing progress. It
057 * will receive update events from the report processors and updates the UI according to
058 * the latest event data.
059 * <p/>
060 * The progress will be computed according to the currently processed table row. This
061 * approach provides relativly accurate data, but assumes that processing all bands
062 * consumes roughly the same time.
063 *
064 * @author Thomas Morgner
065 */
066 public class ReportProgressDialog extends JDialog
067 {
068 private class ScreenUpdateRunnable implements Runnable
069 {
070 private int page;
071 private int activity;
072 private int currentRow;
073
074 public ScreenUpdateRunnable (final int activity,
075 final int currentRow,
076 final int page)
077 {
078 this.activity = activity;
079 this.currentRow = currentRow;
080 this.page = page;
081 }
082
083 public void run ()
084 {
085 // todo
086 }
087 }
088
089 private class ReportProgressHandler implements ReportProgressListener
090 {
091 public ReportProgressHandler()
092 {
093 }
094
095 public void reportProcessingStarted(ReportProgressEvent event)
096 {
097 postUpdate(event);
098 }
099
100 public void reportProcessingUpdate(ReportProgressEvent event)
101 {
102 postUpdate(event);
103 }
104
105 public void reportProcessingFinished(ReportProgressEvent event)
106 {
107 postUpdate(event);
108 }
109
110 private void postUpdate (ReportProgressEvent event)
111 {
112 final ScreenUpdateRunnable runnable = new ScreenUpdateRunnable
113 (event.getActivity(), event.getRow(), event.getPage());
114 if (SwingUtilities.isEventDispatchThread())
115 {
116 runnable.run();
117 }
118 else
119 {
120 SwingUtilities.invokeLater(runnable);
121 }
122 }
123 }
124
125 private static class ToFrontHandler extends WindowAdapter
126 {
127 public ToFrontHandler()
128 {
129 }
130
131 /**
132 * Invoked when a window has been opened.
133 */
134 public void windowOpened (final WindowEvent e)
135 {
136 e.getWindow().toFront();
137 }
138 }
139
140 /**
141 * A label that carries the global message that describes the current task.
142 */
143 private JLabel messageCarrier;
144 /**
145 * A label containing the report processing pass count.
146 */
147 private JLabel passCountMessage;
148 /**
149 * A label containing the current page.
150 */
151 private JLabel pageCountMessage;
152 /**
153 * A label containing the currently processed row.
154 */
155 private JLabel rowCountMessage;
156 /**
157 * The progress bar that is used to visualize the progress.
158 */
159 private JProgressBar progressBar;
160 /**
161 * The reuseable message format for the page label.
162 */
163 private MessageFormat pageMessageFormatter;
164 /**
165 * The reuseable message format for the rows label.
166 */
167 private MessageFormat rowsMessageFormatter;
168 /**
169 * The reuseable message format for the pass label.
170 */
171 private MessageFormat passMessageFormatter;
172
173 /**
174 * The last page received.
175 */
176 private int lastPage;
177 /**
178 * The last pass values received.
179 */
180 private int lastPass;
181 /**
182 * The last max-row received.
183 */
184 private int lastMaxRow;
185 /**
186 * the cached value for the max-row value as integer.
187 */
188 private Integer lastMaxRowInteger; // this values doesnt change much, so reduce GC work
189 /**
190 * a text which describes the layouting process.
191 */
192 private String layoutText;
193 /**
194 * a text that describes the export phase of the report processing.
195 */
196 private String outputText;
197
198
199 /**
200 * Localised resources.
201 */
202 private ResourceBundle resources;
203
204 /**
205 * Creates a non-modal dialog without a title and with the specified Dialog owner.
206 *
207 * @param dialog the owner of the dialog
208 */
209 public ReportProgressDialog (final Dialog dialog)
210 {
211 super(dialog);
212 setLocale(dialog.getLocale());
213 initConstructor();
214 }
215
216 /**
217 * Creates a non-modal dialog without a title and with the specified Frame owner.
218 *
219 * @param frame the owner of the dialog
220 */
221 public ReportProgressDialog (final Frame frame)
222 {
223 super(frame);
224 setLocale(frame.getLocale());
225 initConstructor();
226 }
227
228 /**
229 * Creates a non-modal dialog without a title and without a specified Frame owner. A
230 * shared, hidden frame will be set as the owner of the Dialog.
231 */
232 public ReportProgressDialog ()
233 {
234 initConstructor();
235 }
236
237 /**
238 * Initializes the dialog (Non-GUI stuff).
239 */
240 private void initConstructor ()
241 {
242 resources = ResourceBundle.getBundle
243 (GuiCommonModule.RESOURCE_BASE_NAME, getLocale());
244 initialize();
245 addWindowListener(new ToFrontHandler());
246
247 setOutputText(resources.getString("progress-dialog.perform-output"));
248 setLayoutText(resources.getString("progress-dialog.prepare-layout"));
249
250 lastPass = -1;
251 lastMaxRow = -1;
252 lastPage = -1;
253 }
254
255 /**
256 * Initializes the GUI components of this dialog.
257 */
258 private void initialize ()
259 {
260 final JPanel contentPane = new JPanel();
261 contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
262 contentPane.setLayout(new GridBagLayout());
263
264 pageMessageFormatter = new MessageFormat(resources.getString("progress-dialog.page-label"));
265 rowsMessageFormatter = new MessageFormat(resources.getString("progress-dialog.rows-label"));
266 passMessageFormatter = new MessageFormat(resources.getString("progress-dialog.pass-label"));
267
268 messageCarrier = new JLabel(" ");
269 passCountMessage = new JLabel(" ");
270 rowCountMessage = new JLabel(" ");
271 pageCountMessage = new JLabel(" ");
272 progressBar = new JProgressBar();
273
274 GridBagConstraints gbc = new GridBagConstraints();
275 gbc.gridx = 0;
276 gbc.gridy = 0;
277 gbc.gridwidth = 2;
278 gbc.fill = GridBagConstraints.HORIZONTAL;
279 gbc.weightx = 1;
280 gbc.anchor = GridBagConstraints.WEST;
281 gbc.insets = new Insets(3, 1, 5, 1);
282 gbc.ipadx = 200;
283 contentPane.add(messageCarrier, gbc);
284
285 gbc = new GridBagConstraints();
286 gbc.gridx = 0;
287 gbc.gridy = 1;
288 gbc.gridwidth = 2;
289 gbc.anchor = GridBagConstraints.SOUTHWEST;
290 gbc.insets = new Insets(3, 1, 1, 1);
291 contentPane.add(passCountMessage, gbc);
292
293 gbc = new GridBagConstraints();
294 gbc.gridx = 0;
295 gbc.gridy = 2;
296 gbc.gridwidth = 2;
297 gbc.anchor = GridBagConstraints.WEST;
298 gbc.fill = GridBagConstraints.HORIZONTAL;
299 gbc.weightx = 1;
300 gbc.insets = new Insets(3, 1, 1, 1);
301 contentPane.add(progressBar, gbc);
302
303 gbc = new GridBagConstraints();
304 gbc.gridx = 0;
305 gbc.gridy = 3;
306 gbc.gridwidth = 1;
307 gbc.weighty = 1;
308 gbc.anchor = GridBagConstraints.NORTHWEST;
309 gbc.insets = new Insets(3, 1, 1, 1);
310 contentPane.add(pageCountMessage, gbc);
311
312 gbc = new GridBagConstraints();
313 gbc.gridx = 1;
314 gbc.gridy = 3;
315 gbc.gridwidth = 1;
316 gbc.anchor = GridBagConstraints.NORTHWEST;
317 gbc.insets = new Insets(3, 10, 1, 1);
318 gbc.weightx = 1;
319 gbc.fill = GridBagConstraints.HORIZONTAL;
320 contentPane.add(rowCountMessage, gbc);
321
322 setContentPane(contentPane);
323 }
324
325 /**
326 * Returns the current message.
327 *
328 * @return the current global message.
329 */
330 public String getMessage ()
331 {
332 return messageCarrier.getText();
333 }
334
335 /**
336 * Defines the current message.
337 *
338 * @param message the current global message.
339 */
340 public void setMessage (final String message)
341 {
342 messageCarrier.setText(message);
343 }
344
345 /**
346 * Updates the page message label if the current page has changed.
347 *
348 * @param page the new page parameter.
349 */
350 protected void updatePageMessage (final int page)
351 {
352 if (lastPage != page)
353 {
354 final Object[] parameters = new Object[]{new Integer(page)};
355 pageCountMessage.setText(pageMessageFormatter.format(parameters));
356 lastPage = page;
357 }
358 }
359
360 /**
361 * Updates the rows message label if either the rows or maxrows changed.
362 *
363 * @param rows the currently processed rows.
364 * @param maxRows the maximum number of rows in the report.
365 */
366 protected void updateRowsMessage (final int rows, final int maxRows)
367 {
368 if (maxRows != lastMaxRow)
369 {
370 lastMaxRowInteger = new Integer(maxRows);
371 lastMaxRow = maxRows;
372 }
373 final Object[] parameters = new Object[]{
374 new Integer(rows),
375 lastMaxRowInteger
376 };
377 rowCountMessage.setText(rowsMessageFormatter.format(parameters));
378 }
379
380 /**
381 * Updates the pass message label if either the pass or prepare state changed. The pass
382 * reflects the current processing level, one level for every function dependency
383 * level.
384 *
385 * @param pass the current reporting pass.
386 * @param prepare true, if the current run is a prepare run, false otherwise.
387 */
388 protected void updatePassMessage (final int pass, final boolean prepare)
389 {
390 if (lastPass != pass)
391 {
392 lastPass = pass;
393 if (pass >= 0)
394 {
395 final Object[] parameters = new Object[]{new Integer(pass)};
396 passCountMessage.setText(passMessageFormatter.format(parameters));
397 }
398 else
399 {
400 final String message;
401 if (prepare)
402 {
403 message = getLayoutText();
404 }
405 else
406 {
407 message = getOutputText();
408 }
409 passCountMessage.setText(message);
410 }
411 }
412 }
413
414 /**
415 * Returns the current pass message component.
416 *
417 * @return the pass message component.
418 */
419 protected final JLabel getPassCountMessage ()
420 {
421 return passCountMessage;
422 }
423
424 /**
425 * Returns the current pagecount message component.
426 *
427 * @return the page message component.
428 */
429 protected final JLabel getPageCountMessage ()
430 {
431 return pageCountMessage;
432 }
433
434 /**
435 * Returns the current row message component.
436 *
437 * @return the row message component.
438 */
439 protected final JLabel getRowCountMessage ()
440 {
441 return rowCountMessage;
442 }
443
444 /**
445 * Returns the current pass message component.
446 *
447 * @return the pass message component.
448 */
449 protected final MessageFormat getPageMessageFormatter ()
450 {
451 return pageMessageFormatter;
452 }
453
454 /**
455 * Returns the current pass message component.
456 *
457 * @return the pass message component.
458 */
459 protected final MessageFormat getRowsMessageFormatter ()
460 {
461 return rowsMessageFormatter;
462 }
463
464 /**
465 * Returns the current pass message component.
466 *
467 * @return the pass message component.
468 */
469 protected final MessageFormat getPassMessageFormatter ()
470 {
471 return passMessageFormatter;
472 }
473
474 /**
475 * Returns the output text message. This text describes the export phases of the report
476 * processing.
477 *
478 * @return the output phase description.
479 */
480 public String getOutputText ()
481 {
482 return outputText;
483 }
484
485 /**
486 * Defines the output text message. This text describes the export phases of the report
487 * processing.
488 *
489 * @param outputText the output message.
490 */
491 public void setOutputText (final String outputText)
492 {
493 if (outputText == null)
494 {
495 throw new NullPointerException("OutputText must not be null.");
496 }
497 this.outputText = outputText;
498 }
499
500 /**
501 * Returns the layout text. This text describes the prepare phases of the report
502 * processing.
503 *
504 * @return the layout text.
505 */
506 public String getLayoutText ()
507 {
508 return layoutText;
509 }
510
511 /**
512 * Defines the layout text message. This text describes the prepare phases of the report
513 * processing.
514 *
515 * @param layoutText the layout message.
516 */
517 public void setLayoutText (final String layoutText)
518 {
519 if (layoutText == null)
520 {
521 throw new NullPointerException("LayoutText must not be null.");
522 }
523 this.layoutText = layoutText;
524 }
525
526 protected boolean isSameMaxRow (int row)
527 {
528 return lastMaxRow == row;
529 }
530
531 }