classpath-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[cp-patches] [RFC] ProgressMonitor implemented


From: Robert Schuster
Subject: [cp-patches] [RFC] ProgressMonitor implemented
Date: Thu, 15 Sep 2005 20:09:44 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.11) Gecko/20050830

Hi,
this patch implements the ProgressMonitor. I'll send a demo application to the
associated bug report[0].

2005-09-15  Robert Schuster  <address@hidden>

    * javax/swing/ProgressMonitor: Implemented the former stubbed
    class and added documentation.
    (close): Implemented and added documentation.
    (setProgress): Dito.
    (isCanceled): Dito.
    (setMinimum): Added documentation.
    (getMinimum): Dito.
    (setMaximum): Dito.
    (getMaximum): Dito.
    (setNote): Dito.
    (getMillisToDecideToPopup): Dito.
    (setMillisToDecideToPopup): Dito.
    (getMillisToPopup): Dito.
    (setMillisToPopup): Dito.
    (getNote): Dito.

[0] - http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23850

cu
Robert
Index: javax/swing/ProgressMonitor.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/ProgressMonitor.java,v
retrieving revision 1.4
diff -u -r1.4 ProgressMonitor.java
--- javax/swing/ProgressMonitor.java    13 Sep 2005 09:17:21 -0000      1.4
+++ javax/swing/ProgressMonitor.java    15 Sep 2005 17:59:38 -0000
@@ -1,5 +1,5 @@
 /* ProgressMonitor.java --
-   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -38,56 +38,74 @@
 package javax.swing;
 
 import java.awt.Component;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
 
 /**
- * ProgressMonitor
- * @author     Andrew Selkirk
- * @version    1.0
+ * <p>Using this class you can easily monitor tasks where you cannot
+ * estimate the duration exactly.</p> 
+ *
+ * <p>A ProgressMonitor instance waits until the first time setProgress
+ * is called. When <code>millisToDecideToPopup</code> time elapsed the
+ * instance estimates the duration until the whole operation is completed.
+ * If this duration exceeds <code>millisToPopup</code> a non-modal dialog
+ * with a message and a progress bar is shown.</p>
+ *
+ * <p>The value of <code>millisToDecideToPopup</code> defaults to
+ * <code>500</code> and <code>millisToPopup</code> to
+ * <code>2000</code>.</p>
+ *
+ * @author Andrew Selkirk
+ * @author Robert Schuster (address@hidden)
+ * @since 1.2
+ * @status updated to 1.2
  */
 public class ProgressMonitor
 {
   /**
    * parentComponent
    */
-  private Component component;
+  Component component;
 
   /**
    * note
    */
-  private String note;
+  String note;
 
   /**
    * message
    */
-  private Object message;
+  Object message;
 
   /**
    * millisToDecideToPopup
    */
-  private int millisToDecideToPopup;
+  int millisToDecideToPopup = 500;
 
   /**
    * millisToPopup
    */
-  private int millisToPopup;
+  int millisToPopup = 2000;
 
-  /**
-   * min
-   */
-  private int minimum;
+  int min, max, progress;
 
-  /**
-   * max
-   */
-  private int maximum;
+  JProgressBar progressBar;
+
+  JLabel noteLabel;
+
+  JDialog progressDialog;
+
+  Timer timer;
+
+  boolean canceled;
 
   /**
    * Constructor ProgressMonitor
-   * @param component TODO
-   * @param message TODO
-   * @param note TODO
-   * @param minimum TODO
-   * @param maximum TODO
+   * @param component The parent component of the progress dialog or 
<code>null</code>.
+   * @param message A constant message object which works in the way it does 
in <code>JOptionPane</code>.
+   * @param note A string message which can be changed while the operation 
goes on.
+   * @param minimum The minimum value for the operation (start value).
+   * @param maximum The maximum value for the operation (end value).
    */
   public ProgressMonitor(Component component, Object message,
                          String note, int minimum, int maximum)
@@ -97,93 +115,154 @@
     this.component = component;
     this.message = message;
     this.note = note;
-    this.minimum = minimum;
-    this.maximum = maximum;
 
-    // TODO
+    min = minimum;
+    max = maximum;
   }
 
   /**
-   * close
+   * <p>Hides the dialog and stops any measurements.</p>
+   *
+   * <p>Has no effect when <code>setProgress</code> is not at least
+   * called once.</p>
    */
   public void close()
   {
-    // TODO
+    if ( progressDialog != null )
+    {
+      progressDialog.setVisible(false);
+    }
+
+    if ( timer != null )
+    {
+      timer.stop();
+      timer = null;
+    }
   }
 
   /**
-   * setProgress
-   * @param progress TODO
+   * <p>Updates the progress value.</p>
+   *
+   * <p>When called for the first time this initializes a timer
+   * which decides after <code>millisToDecideToPopup</code> time
+   * whether to show a progress dialog or not.</p>
+   *
+   * <p>If the progress value equals or exceeds the maximum
+   * value the progress dialog is closed automatically.</p>
+   *
+   * @param progress New progress value.
    */
   public void setProgress(int progress)
   {
-    // TODO
+    this.progress = progress;
+
+    // Initializes and starts a timer with a task
+    // which measures the duration and displays
+    // a progress dialog if neccessary.
+    if ( timer == null && progressDialog == null )
+    {
+      timer = new Timer(25, null);
+      timer.addActionListener(new TimerListener());
+      timer.start();
+    }
+
+    // Cancels timer and hides progress dialog if the
+    // maximum value is reached.
+    if ( progressBar != null && this.progress >= progressBar.getMaximum() )
+    {
+      // The reason for using progressBar.getMaximum() instead of max is that
+      // we want to prevent that changes to the value have any effect after the
+      // progress dialog is visible (This is how the JDK behaves.).
+      close();
+    }
+
   }
 
-  /**
-   * getMinimum
-   * @returns int
+  /** Returns the minimum or start value of the operation.
+   *
+   * @returns Minimum or start value of the operation.
    */
   public int getMinimum()
   {
-    return minimum; // TODO
+    return min;
   }
 
   /**
-   * setMinimum
-   * @param minimum TODO
+   * <p>Use this method to set the minimum or start value of
+   * your operation.</p>
+   *
+   * <p>For typical application like copy operation this will be
+   * zero.</p>
+   *
+   * <p>Keep in mind that changing this value after the progress
+   * dialog is made visible has no effect upon the progress bar.</p>
+   *
+   * @param minimum The new minimum value.
    */
   public void setMinimum(int minimum)
   {
-    this.minimum = minimum;
-    // TODO
+    min = minimum;
   }
 
   /**
-   * getMaximum
-   * @returns int
+   * Return the maximum or end value of your operation.
+   *
+   * @returns Maximum or end value.
    */
   public int getMaximum()
   {
-    return maximum; // TODO
+    return max;
   }
 
   /**
-   * setMaximum
-   * @param maximum TODO
+   * <p>Sets the maximum or end value of the operation to the
+   * given integer.</p>
+   *
+   * @param maximum
    */
   public void setMaximum(int maximum)
   {
-    this.maximum = maximum;
-    // TODO
+    max = maximum;
   }
 
   /**
-   * isCanceled
-   * @returns boolean
+   * Returns whether the user canceled the operation.
+   *
+   * @returns Whether the operation was canceled.
    */
   public boolean isCanceled()
   {
-    return false; // TODO
+    // The value is predefined to false
+    // and changes only when the user clicks
+    // the cancel button in the progress dialog.
+    return canceled;
   }
 
   /**
-   * getMillisToDecideToPopup
-   * @returns int
+   * Returns the amount of milliseconds to wait
+   * until the ProgressMonitor should decide whether
+   * a progress dialog is to be shown or not.
+   *
+   * @returns The duration in milliseconds.
    */
   public int getMillisToDecideToPopup()
   {
-    return millisToDecideToPopup; // TODO
+    return millisToDecideToPopup;
   }
 
   /**
-   * setMillisToDecideToPopup
-   * @param time TODO
+   * Sets the amount of milliseconds to wait until the
+   * ProgressMonitor should decide whether a progress dialog
+   * is to be shown or not.
+   *
+   * <p>This method has no effect when the progress dialog
+   * is already visible.</p>
+   *
+   * @param time The duration in milliseconds.
    */
   public void setMillisToDecideToPopup(int time)
   {
     millisToDecideToPopup = time;
-    // TODO
   }
 
   /**
@@ -192,7 +271,7 @@
    */
   public int getMillisToPopup()
   {
-    return millisToPopup; // TODO
+    return millisToPopup;
   }
 
   /**
@@ -202,26 +281,134 @@
   public void setMillisToPopup(int time)
   {
     millisToPopup = time;
-    // TODO
   }
 
   /**
-   * getNote
-   * @returns String
+   * Returns a message which is shown in the progress dialog.
+   *
+   * @returns The changeable message visible in the progress dialog.
    */
   public String getNote()
   {
-    return note; // TODO
+    return note;
   }
 
   /**
-   * setNote
-   * @param note TODO
+   * <p>Set the message shown in the progess dialog.</p>
+   *
+   * <p>Changing the note while the progress dialog is visible
+   * is possible.</p>
+   *
+   * @param note A message shown in the progress dialog.
    */
   public void setNote(String note)
   {
-    this.note = note;
-    // TODO
+    if ( noteLabel != null )
+    {
+       noteLabel.setText(note);
+    }
+    else
+    {
+      this.note = note;
+    }
+  }
+
+  /** Internal method that creates the progress dialog.
+   */
+  void createDialog()
+  {
+    Object[] tmp = new Object[]
+      { 
+        message,
+        noteLabel = new JLabel(note),
+        progressBar = new JProgressBar(min, max)
+      };
+
+    JOptionPane pane = new JOptionPane(tmp, JOptionPane.INFORMATION_MESSAGE);
+
+    // FIXME: Internationalize the button
+    JButton cancelButton = new JButton("Cancel");
+    cancelButton.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent ae)
+      {
+        canceled = true;
+      }
+    });
+
+    pane.setOptions(new Object[] { cancelButton });
+
+    // FIXME: Internationalize the title
+    progressDialog = pane.createDialog(component, "Progress ...");
+    progressDialog.setModal(false);
+    progressDialog.setResizable(true);
+
+    progressDialog.pack();
+    progressDialog.setVisible(true);
+
+  }
+
+  /** An ActionListener implementation which does the measurements
+   * and estimations of the ProgressMonitor.
+   */
+  class TimerListener implements ActionListener
+  {
+    long timestamp;
+
+    int lastProgress;
+
+    boolean first = true;
+
+    TimerListener()
+    {
+       timestamp = System.currentTimeMillis();
+    }
+
+    public void actionPerformed(ActionEvent ae)
+    {
+       long now = System.currentTimeMillis();
+
+       if ( first )
+       {
+         if (( now - timestamp ) > millisToDecideToPopup )
+         {
+           first = false;
+           long expected = ( now - timestamp ) * ( max - min ) / ( progress - 
min );
+
+           if ( expected > millisToPopup )
+           {
+             createDialog();
+           }
+         }
+         else
+         {
+           // We have not waited long enough to make a decision,
+           // so return and try again when the timer is invoked.
+           return;
+         }
+       }
+       else if ( progressDialog != null )
+       {
+         // The progress dialog is being displayed. We now calculate
+         // whether setting the progress bar to the current progress
+         // value would result in a visual difference. 
+         int delta = progress - progressBar.getValue();
+
+         if ( ( delta * progressBar.getWidth() / (max - min) ) > 0 )
+         {
+           // At least one pixel would change.
+           progressBar.setValue(progress);
+         }
+       }
+       else
+       {
+         // No dialog necessary
+         timer.stop();
+         timer = null;
+       }
+
+      timestamp = now;
+    }
   }
 
 }

reply via email to

[Prev in Thread] Current Thread [Next in Thread]