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    }