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 3525 2007-10-16 11:43:48Z tmorgner $ 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 static class ScreenUpdateRunnable implements Runnable 069 { 070 private int page; 071 private int activity; 072 private int currentRow; 073 074 private 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 private ReportProgressHandler() 092 { 093 } 094 095 public void reportProcessingStarted(final ReportProgressEvent event) 096 { 097 postUpdate(event); 098 } 099 100 public void reportProcessingUpdate(final ReportProgressEvent event) 101 { 102 postUpdate(event); 103 } 104 105 public void reportProcessingFinished(final ReportProgressEvent event) 106 { 107 postUpdate(event); 108 } 109 110 private void postUpdate (final 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 private 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 (final int row) 527 { 528 return lastMaxRow == row; 529 } 530 531 }