- /*
- * @(#)BasicProgressBarUI.java 1.68 04/03/11
- *
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package javax.swing.plaf.basic;
-
- import com.sun.java.swing.SwingUtilities2;
- import java.awt.*;
- import java.awt.geom.AffineTransform;
- import java.awt.event.*;
- import javax.swing.*;
- import javax.swing.event.*;
- import javax.swing.plaf.*;
- import java.beans.PropertyChangeListener;
- import java.beans.PropertyChangeEvent;
- import java.io.Serializable;
- import sun.swing.DefaultLookup;
-
- /**
- * A Basic L&F implementation of ProgressBarUI.
- *
- * @version 1.68 03/11/04
- * @author Michael C. Albers
- * @author Kathy Walrath
- */
- public class BasicProgressBarUI extends ProgressBarUI {
- private int cachedPercent;
- private int cellLength, cellSpacing;
- // The "selectionForeground" is the color of the text when it is painted
- // over a filled area of the progress bar. The "selectionBackground"
- // is for the text over the unfilled progress bar area.
- private Color selectionForeground, selectionBackground;
-
- private Animator animator;
-
- protected JProgressBar progressBar;
- protected ChangeListener changeListener;
- private Handler handler;
-
- /**
- * The current state of the indeterminate animation's cycle.
- * 0, the initial value, means paint the first frame.
- * When the progress bar is indeterminate and showing,
- * the default animation thread updates this variable
- * by invoking incrementAnimationIndex()
- * every repaintInterval milliseconds.
- */
- private int animationIndex = 0;
-
- /**
- * The number of frames per cycle. Under the default implementation,
- * this depends on the cycleTime and repaintInterval. It
- * must be an even number for the default painting algorithm. This
- * value is set in the initIndeterminateValues method.
- */
- private int numFrames; //0 1|numFrames-1 ... numFrames/2
-
- /**
- * Interval (in ms) between repaints of the indeterminate progress bar.
- * The value of this method is set
- * (every time the progress bar changes to indeterminate mode)
- * using the
- * "ProgressBar.repaintInterval" key in the defaults table.
- */
- private int repaintInterval;
-
- /**
- * The number of milliseconds until the animation cycle repeats.
- * The value of this method is set
- * (every time the progress bar changes to indeterminate mode)
- * using the
- * "ProgressBar.cycleTime" key in the defaults table.
- */
- private int cycleTime; //must be repaintInterval*2*aPositiveInteger
-
- //performance stuff
- private static boolean ADJUSTTIMER = true; //makes a BIG difference;
- //make this false for
- //performance tests
-
- /**
- * Used to hold the location and size of the bouncing box (returned
- * by getBox) to be painted.
- *
- * @since 1.5
- */
- protected Rectangle boxRect;
-
- /**
- * The rectangle to be updated the next time the
- * animation thread calls repaint. For bouncing-box
- * animation this rect should include the union of
- * the currently displayed box (which needs to be erased)
- * and the box to be displayed next.
- * This rectangle's values are set in
- * the setAnimationIndex method.
- */
- private Rectangle nextPaintRect;
-
- //cache
- /** The component's painting area, not including the border. */
- private Rectangle componentInnards; //the current painting area
- private Rectangle oldComponentInnards; //used to see if the size changed
-
- /** For bouncing-box animation, the change in position per frame. */
- private double delta = 0.0;
-
- private int maxPosition = 0; //maximum X (horiz) or Y box location
-
-
- public static ComponentUI createUI(JComponent x) {
- return new BasicProgressBarUI();
- }
-
- public void installUI(JComponent c) {
- progressBar = (JProgressBar)c;
- installDefaults();
- installListeners();
- if (progressBar.isIndeterminate()) {
- initIndeterminateValues();
- }
- }
-
- public void uninstallUI(JComponent c) {
- if (progressBar.isIndeterminate()) {
- cleanUpIndeterminateValues();
- }
- uninstallDefaults();
- uninstallListeners();
- progressBar = null;
- }
-
- protected void installDefaults() {
- LookAndFeel.installProperty(progressBar, "opaque", Boolean.TRUE);
- LookAndFeel.installBorder(progressBar,"ProgressBar.border");
- LookAndFeel.installColorsAndFont(progressBar,
- "ProgressBar.background",
- "ProgressBar.foreground",
- "ProgressBar.font");
- cellLength = UIManager.getInt("ProgressBar.cellLength");
- cellSpacing = UIManager.getInt("ProgressBar.cellSpacing");
- selectionForeground = UIManager.getColor("ProgressBar.selectionForeground");
- selectionBackground = UIManager.getColor("ProgressBar.selectionBackground");
- }
-
- protected void uninstallDefaults() {
- LookAndFeel.uninstallBorder(progressBar);
- }
-
- protected void installListeners() {
- //Listen for changes in the progress bar's data.
- changeListener = getHandler();
- progressBar.addChangeListener(changeListener);
-
- //Listen for changes between determinate and indeterminate state.
- progressBar.addPropertyChangeListener(getHandler());
- }
-
- private Handler getHandler() {
- if (handler == null) {
- handler = new Handler();
- }
- return handler;
- }
-
- /**
- * Starts the animation thread, creating and initializing
- * it if necessary. This method is invoked when an
- * indeterminate progress bar should start animating.
- * Reasons for this may include:
- * <ul>
- * <li>The progress bar is determinate and becomes displayable
- * <li>The progress bar is displayable and becomes determinate
- * <li>The progress bar is displayable and determinate and this
- * UI is installed
- * </ul>
- * If you implement your own animation thread,
- * you must override this method.
- *
- * @since 1.4
- * @see #stopAnimationTimer
- */
- protected void startAnimationTimer() {
- if (animator == null) {
- animator = new Animator();
- }
-
- animator.start(getRepaintInterval());
- }
-
- /**
- * Stops the animation thread.
- * This method is invoked when the indeterminate
- * animation should be stopped. Reasons for this may include:
- * <ul>
- * <li>The progress bar changes to determinate
- * <li>The progress bar is no longer part of a displayable hierarchy
- * <li>This UI in uninstalled
- * </ul>
- * If you implement your own animation thread,
- * you must override this method.
- *
- * @since 1.4
- * @see #startAnimationTimer
- */
- protected void stopAnimationTimer() {
- if (animator != null) {
- animator.stop();
- }
- }
-
- /**
- * Removes all listeners installed by this object.
- */
- protected void uninstallListeners() {
- progressBar.removeChangeListener(changeListener);
- progressBar.removePropertyChangeListener(getHandler());
- handler = null;
- }
-
-
- // Many of the Basic*UI components have the following methods.
- // This component does not have these methods because *ProgressBarUI
- // is not a compound component and does not accept input.
- //
- // protected void installComponents()
- // protected void uninstallComponents()
- // protected void installKeyboardActions()
- // protected void uninstallKeyboardActions()
-
- protected Dimension getPreferredInnerHorizontal() {
- Dimension horizDim = (Dimension)DefaultLookup.get(progressBar, this,
- "ProgressBar.horizontalSize");
- if (horizDim == null) {
- horizDim = new Dimension(146, 12);
- }
- return horizDim;
- }
-
- protected Dimension getPreferredInnerVertical() {
- Dimension vertDim = (Dimension)DefaultLookup.get(progressBar, this,
- "ProgressBar.vertictalSize");
- if (vertDim == null) {
- vertDim = new Dimension(12, 146);
- }
- return vertDim;
- }
-
- /**
- * The "selectionForeground" is the color of the text when it is painted
- * over a filled area of the progress bar.
- */
- protected Color getSelectionForeground() {
- return selectionForeground;
- }
-
- /**
- * The "selectionBackground" is the color of the text when it is painted
- * over an unfilled area of the progress bar.
- */
- protected Color getSelectionBackground() {
- return selectionBackground;
- }
-
- private int getCachedPercent() {
- return cachedPercent;
- }
-
- private void setCachedPercent(int cachedPercent) {
- this.cachedPercent = cachedPercent;
- }
-
- /**
- * Returns the width (if HORIZONTAL) or height (if VERTICAL)
- * of each of the indivdual cells/units to be rendered in the
- * progress bar. However, for text rendering simplification and
- * aesthetic considerations, this function will return 1 when
- * the progress string is being rendered.
- *
- * @return the value representing the spacing between cells
- * @see #setCellLength
- * @see JProgressBar#isStringPainted
- */
- protected int getCellLength() {
- if (progressBar.isStringPainted()) {
- return 1;
- } else {
- return cellLength;
- }
- }
-
- protected void setCellLength(int cellLen) {
- this.cellLength = cellLen;
- }
-
- /**
- * Returns the spacing between each of the cells/units in the
- * progress bar. However, for text rendering simplification and
- * aesthetic considerations, this function will return 0 when
- * the progress string is being rendered.
- *
- * @return the value representing the spacing between cells
- * @see #setCellSpacing
- * @see JProgressBar#isStringPainted
- */
- protected int getCellSpacing() {
- if (progressBar.isStringPainted()) {
- return 0;
- } else {
- return cellSpacing;
- }
- }
-
- protected void setCellSpacing(int cellSpace) {
- this.cellSpacing = cellSpace;
- }
-
- /**
- * This determines the amount of the progress bar that should be filled
- * based on the percent done gathered from the model. This is a common
- * operation so it was abstracted out. It assumes that your progress bar
- * is linear. That is, if you are making a circular progress indicator,
- * you will want to override this method.
- */
- protected int getAmountFull(Insets b, int width, int height) {
- int amountFull = 0;
- BoundedRangeModel model = progressBar.getModel();
-
- if ( (model.getMaximum() - model.getMinimum()) != 0) {
- if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
- amountFull = (int)Math.round(width *
- progressBar.getPercentComplete());
- } else {
- amountFull = (int)Math.round(height *
- progressBar.getPercentComplete());
- }
- }
- return amountFull;
- }
-
- /**
- * Delegates painting to one of two methods:
- * paintDeterminate or paintIndeterminate.
- */
- public void paint(Graphics g, JComponent c) {
- if (progressBar.isIndeterminate()) {
- paintIndeterminate(g, c);
- } else {
- paintDeterminate(g, c);
- }
- }
-
- /**
- * Stores the position and size of
- * the bouncing box that would be painted for the current animation index
- * in <code>r</code> and returns <code>r</code>.
- * Subclasses that add to the painting performed
- * in this class's implementation of <code>paintIndeterminate</code> --
- * to draw an outline around the bouncing box, for example --
- * can use this method to get the location of the bouncing
- * box that was just painted.
- * By overriding this method,
- * you have complete control over the size and position
- * of the bouncing box,
- * without having to reimplement <code>paintIndeterminate</code>.
- *
- * @param r the Rectangle instance to be modified;
- * may be <code>null</code>
- * @return <code>null</code> if no box should be drawn;
- * otherwise, returns the passed-in rectangle
- * (if non-null)
- * or a new rectangle
- *
- * @see #setAnimationIndex
- * @since 1.4
- */
- protected Rectangle getBox(Rectangle r) {
- int currentFrame = getAnimationIndex();
- int middleFrame = numFrames2;
-
- if (sizeChanged() || delta == 0.0 || maxPosition == 0.0) {
- updateSizes();
- }
-
- r = getGenericBox(r);
-
- if (r == null) {
- return null;
- }
- if (middleFrame <= 0) {
- return null;
- }
-
- //assert currentFrame >= 0 && currentFrame < numFrames
- if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
- if (currentFrame < middleFrame) {
- r.x = componentInnards.x
- + (int)Math.round(delta * (double)currentFrame);
- } else {
- r.x = maxPosition
- - (int)Math.round(delta *
- (currentFrame - middleFrame));
- }
- } else { //VERTICAL indeterminate progress bar
- if (currentFrame < middleFrame) {
- r.y = componentInnards.y
- + (int)Math.round(delta * currentFrame);
- } else {
- r.y = maxPosition
- - (int)Math.round(delta *
- (currentFrame - middleFrame));
- }
- }
- return r;
- }
-
- /**
- * Updates delta, max position.
- * Assumes componentInnards is correct (e.g. call after sizeChanged()).
- */
- private void updateSizes() {
- int length = 0;
-
- if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
- length = getBoxLength(componentInnards.width,
- componentInnards.height);
- maxPosition = componentInnards.x + componentInnards.width
- - length;
-
- } else { //VERTICAL progress bar
- length = getBoxLength(componentInnards.height,
- componentInnards.width);
- maxPosition = componentInnards.y + componentInnards.height
- - length;
- }
-
- //If we're doing bouncing-box animation, update delta.
- delta = 2.0 * (double)maxPosition(double)numFrames;
- }
-
- /**
- * Assumes that the component innards, max position, etc. are up-to-date.
- */
- private Rectangle getGenericBox(Rectangle r) {
- if (r == null) {
- r = new Rectangle();
- }
-
- if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
- r.width = getBoxLength(componentInnards.width,
- componentInnards.height);
- if (r.width < 0) {
- r = null;
- } else {
- r.height = componentInnards.height;
- r.y = componentInnards.y;
- }
- // end of HORIZONTAL
-
- } else { //VERTICAL progress bar
- r.height = getBoxLength(componentInnards.height,
- componentInnards.width);
- if (r.height < 0) {
- r = null;
- } else {
- r.width = componentInnards.width;
- r.x = componentInnards.x;
- }
- } // end of VERTICAL
-
- return r;
- }
-
- /**
- * Returns the length
- * of the "bouncing box" to be painted.
- * This method is invoked by the
- * default implementation of <code>paintIndeterminate</code>
- * to get the width (if the progress bar is horizontal)
- * or height (if vertical) of the box.
- * For example:
- * <blockquote>
- * <pre>
- *boxRect.width = getBoxLength(componentInnards.width,
- * componentInnards.height);
- * </pre>
- * </blockquote>
- *
- * @param availableLength the amount of space available
- * for the bouncing box to move in;
- * for a horizontal progress bar,
- * for example,
- * this should be
- * the inside width of the progress bar
- * (the component width minus borders)
- * @param otherDimension for a horizontal progress bar, this should be
- * the inside height of the progress bar; this
- * value might be used to constrain or determine
- * the return value
- *
- * @return the size of the box dimension being determined;
- * must be no larger than <code>availableLength</code>
- *
- * @see javax.swing.SwingUtilities#calculateInnerArea
- * @since 1.5
- */
- protected int getBoxLength(int availableLength, int otherDimension) {
- return (int)Math.round(availableLength6.0);
- }
-
- /**
- * All purpose paint method that should do the right thing for all
- * linear bouncing-box progress bars.
- * Override this if you are making another kind of
- * progress bar.
- *
- * @see #paintDeterminate
- *
- * @since 1.4
- */
- protected void paintIndeterminate(Graphics g, JComponent c) {
- if (!(g instanceof Graphics2D)) {
- return;
- }
-
- Insets b = progressBar.getInsets(); // area for border
- int barRectWidth = progressBar.getWidth() - (b.right + b.left);
- int barRectHeight = progressBar.getHeight() - (b.top + b.bottom);
-
- Graphics2D g2 = (Graphics2D)g;
-
- // Paint the bouncing box.
- boxRect = getBox(boxRect);
- if (boxRect != null) {
- g2.setColor(progressBar.getForeground());
- g2.fillRect(boxRect.x, boxRect.y,
- boxRect.width, boxRect.height);
- }
-
- // Deal with possible text painting
- if (progressBar.isStringPainted()) {
- if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
- paintString(g2, b.left, b.top,
- barRectWidth, barRectHeight,
- boxRect.x, boxRect.width, b);
- }
- else {
- paintString(g2, b.left, b.top,
- barRectWidth, barRectHeight,
- boxRect.y, boxRect.height, b);
- }
- }
- }
-
-
- /**
- * All purpose paint method that should do the right thing for almost
- * all linear, determinate progress bars. By setting a few values in
- * the defaults
- * table, things should work just fine to paint your progress bar.
- * Naturally, override this if you are making a circular or
- * semi-circular progress bar.
- *
- * @see #paintIndeterminate
- *
- * @since 1.4
- */
- protected void paintDeterminate(Graphics g, JComponent c) {
- if (!(g instanceof Graphics2D)) {
- return;
- }
-
- Insets b = progressBar.getInsets(); // area for border
- int barRectWidth = progressBar.getWidth() - (b.right + b.left);
- int barRectHeight = progressBar.getHeight() - (b.top + b.bottom);
-
- int cellLength = getCellLength();
- int cellSpacing = getCellSpacing();
- // amount of progress to draw
- int amountFull = getAmountFull(b, barRectWidth, barRectHeight);
-
- Graphics2D g2 = (Graphics2D)g;
- g2.setColor(progressBar.getForeground());
-
- if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
- // draw the cells
- if (cellSpacing == 0 && amountFull > 0) {
- // draw one big Rect because there is no space between cells
- g2.setStroke(new BasicStroke((float)barRectHeight,
- BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
- } else {
- // draw each individual cell
- g2.setStroke(new BasicStroke((float)barRectHeight,
- BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL,
- 0.f, new float[] { cellLength, cellSpacing }, 0.f));
- }
-
- if (BasicGraphicsUtils.isLeftToRight(c)) {
- g2.drawLine(b.left, (barRectHeight2) + b.top,
- amountFull + b.left, (barRectHeight2) + b.top);
- } else {
- g2.drawLine((barRectWidth + b.left),
- (barRectHeight2) + b.top,
- barRectWidth + b.left - amountFull,
- (barRectHeight2) + b.top);
- }
-
- } else { // VERTICAL
- // draw the cells
- if (cellSpacing == 0 && amountFull > 0) {
- // draw one big Rect because there is no space between cells
- g2.setStroke(new BasicStroke((float)barRectWidth,
- BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
- } else {
- // draw each individual cell
- g2.setStroke(new BasicStroke((float)barRectWidth,
- BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL,
- 0f, new float[] { cellLength, cellSpacing }, 0f));
- }
-
- g2.drawLine(barRectWidth2 + b.left,
- b.top + barRectHeight,
- barRectWidth2 + b.left,
- b.top + barRectHeight - amountFull);
- }
-
- // Deal with possible text painting
- if (progressBar.isStringPainted()) {
- paintString(g, b.left, b.top,
- barRectWidth, barRectHeight,
- amountFull, b);
- }
- }
-
-
- protected void paintString(Graphics g, int x, int y,
- int width, int height,
- int amountFull, Insets b) {
- if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
- if (BasicGraphicsUtils.isLeftToRight(progressBar)) {
- if (progressBar.isIndeterminate()) {
- boxRect = getBox(boxRect);
- paintString(g, x, y, width, height,
- boxRect.x, boxRect.width, b);
- } else {
- paintString(g, x, y, width, height, x, amountFull, b);
- }
- }
- else {
- paintString(g, x, y, width, height, x + width - amountFull,
- amountFull, b);
- }
- }
- else {
- if (progressBar.isIndeterminate()) {
- boxRect = getBox(boxRect);
- paintString(g, x, y, width, height,
- boxRect.y, boxRect.height, b);
- } else {
- paintString(g, x, y, width, height, y + height - amountFull,
- amountFull, b);
- }
- }
- }
-
- /**
- * Paints the progress string.
- *
- * @param g Graphics used for drawing.
- * @param x x location of bounding box
- * @param y y location of bounding box
- * @param width width of bounding box
- * @param height height of bounding box
- * @param fillStart start location, in x or y depending on orientation,
- * of the filled portion of the progress bar.
- * @param amountFull size of the fill region, either width or height
- * depending upon orientation.
- * @param b Insets of the progress bar.
- */
- private void paintString(Graphics g, int x, int y, int width, int height,
- int fillStart, int amountFull, Insets b) {
- if (!(g instanceof Graphics2D)) {
- return;
- }
-
- Graphics2D g2 = (Graphics2D)g;
- String progressString = progressBar.getString();
- g2.setFont(progressBar.getFont());
- Point renderLocation = getStringPlacement(g2, progressString,
- x, y, width, height);
- Rectangle oldClip = g2.getClipBounds();
-
- if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
- g2.setColor(getSelectionBackground());
- SwingUtilities2.drawString(progressBar, g2, progressString,
- renderLocation.x, renderLocation.y);
- g2.setColor(getSelectionForeground());
- g2.clipRect(fillStart, y, amountFull, height);
- SwingUtilities2.drawString(progressBar, g2, progressString,
- renderLocation.x, renderLocation.y);
- } else { // VERTICAL
- g2.setColor(getSelectionBackground());
- AffineTransform rotate =
- AffineTransform.getRotateInstance(Math.PI2);
- g2.setFont(progressBar.getFont().deriveFont(rotate));
- renderLocation = getStringPlacement(g2, progressString,
- x, y, width, height);
- SwingUtilities2.drawString(progressBar, g2, progressString,
- renderLocation.x, renderLocation.y);
- g2.setColor(getSelectionForeground());
- g2.clipRect(x, fillStart, width, amountFull);
- SwingUtilities2.drawString(progressBar, g2, progressString,
- renderLocation.x, renderLocation.y);
- }
- g2.setClip(oldClip);
- }
-
-
- /**
- * Designate the place where the progress string will be painted.
- * This implementation places it at the center of the progress
- * bar (in both x and y). Override this if you want to right,
- * left, top, or bottom align the progress string or if you need
- * to nudge it around for any reason.
- */
- protected Point getStringPlacement(Graphics g, String progressString,
- int x,int y,int width,int height) {
- FontMetrics fontSizer = SwingUtilities2.getFontMetrics(progressBar, g,
- progressBar.getFont());
- int stringWidth = SwingUtilities2.stringWidth(progressBar, fontSizer,
- progressString);
-
- if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
- return new Point(x + Math.round(width2 - stringWidth2),
- y + ((height +
- fontSizer.getAscent() -
- fontSizer.getLeading() -
- fontSizer.getDescent()) / 2));
- } else { // VERTICAL
- return new Point(x + ((width - fontSizer.getAscent() +
- fontSizer.getLeading() + fontSizer.getDescent()) / 2),
- y + Math.round(height2 - stringWidth2));
- }
- }
-
-
- public Dimension getPreferredSize(JComponent c) {
- Dimension size;
- Insets border = progressBar.getInsets();
- FontMetrics fontSizer = progressBar.getFontMetrics(
- progressBar.getFont());
-
- if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
- size = new Dimension(getPreferredInnerHorizontal());
- // Ensure that the progress string will fit
- if (progressBar.isStringPainted()) {
- // I'm doing this for completeness.
- String progString = progressBar.getString();
- int stringWidth = SwingUtilities2.stringWidth(
- progressBar, fontSizer, progString);
- if (stringWidth > size.width) {
- size.width = stringWidth;
- }
- // This uses both Height and Descent to be sure that
- // there is more than enough room in the progress bar
- // for everything.
- // This does have a strange dependency on
- // getStringPlacememnt() in a funny way.
- int stringHeight = fontSizer.getHeight() +
- fontSizer.getDescent();
- if (stringHeight > size.height) {
- size.height = stringHeight;
- }
- }
- } else {
- size = new Dimension(getPreferredInnerVertical());
- // Ensure that the progress string will fit.
- if (progressBar.isStringPainted()) {
- String progString = progressBar.getString();
- int stringHeight = fontSizer.getHeight() +
- fontSizer.getDescent();
- if (stringHeight > size.width) {
- size.width = stringHeight;
- }
- // This is also for completeness.
- int stringWidth = SwingUtilities2.stringWidth(
- progressBar, fontSizer, progString);
- if (stringWidth > size.height) {
- size.height = stringWidth;
- }
- }
- }
-
- size.width += border.left + border.right;
- size.height += border.top + border.bottom;
- return size;
- }
-
- /**
- * The Minimum size for this component is 10. The rationale here
- * is that there should be at least one pixel per 10 percent.
- */
- public Dimension getMinimumSize(JComponent c) {
- Dimension pref = getPreferredSize(progressBar);
- if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
- pref.width = 10;
- } else {
- pref.height = 10;
- }
- return pref;
- }
-
- public Dimension getMaximumSize(JComponent c) {
- Dimension pref = getPreferredSize(progressBar);
- if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
- pref.width = Short.MAX_VALUE;
- } else {
- pref.height = Short.MAX_VALUE;
- }
- return pref;
- }
-
- /**
- * Gets the index of the current animation frame.
- *
- * @since 1.4
- */
- protected int getAnimationIndex() {
- return animationIndex;
- }
-
- /**
- * Sets the index of the current animation frame
- * to the specified value and requests that the
- * progress bar be repainted.
- * Subclasses that don't use the default painting code
- * might need to override this method
- * to change the way that the <code>repaint</code> method
- * is invoked.
- *
- * @param newValue the new animation index; no checking
- * is performed on its value
- * @see #incrementAnimationIndex
- *
- * @since 1.4
- */
- protected void setAnimationIndex(int newValue) {
- if (animationIndex != newValue) {
- if (sizeChanged()) {
- animationIndex = newValue;
- maxPosition = 0; //needs to be recalculated
- delta = 0.0; //needs to be recalculated
- progressBar.repaint();
- return;
- }
-
- //Get the previous box drawn.
- nextPaintRect = getBox(nextPaintRect);
-
- //Update the frame number.
- animationIndex = newValue;
-
- //Get the next box to draw.
- if (nextPaintRect != null) {
- boxRect = getBox(boxRect);
- if (boxRect != null) {
- nextPaintRect.add(boxRect);
- }
- }
- } else { //animationIndex == newValue
- return;
- }
-
- if (nextPaintRect != null) {
- progressBar.repaint(nextPaintRect);
- } else {
- progressBar.repaint();
- }
- }
-
- private boolean sizeChanged() {
- if ((oldComponentInnards == null) || (componentInnards == null)) {
- return true;
- }
-
- oldComponentInnards.setRect(componentInnards);
- componentInnards = SwingUtilities.calculateInnerArea(progressBar,
- componentInnards);
- return !oldComponentInnards.equals(componentInnards);
- }
-
- /**
- * Sets the index of the current animation frame,
- * to the next valid value,
- * which results in the progress bar being repainted.
- * The next valid value is, by default,
- * the current animation index plus one.
- * If the new value would be too large,
- * this method sets the index to 0.
- * Subclasses might need to override this method
- * to ensure that the index does not go over
- * the number of frames needed for the particular
- * progress bar instance.
- * This method is invoked by the default animation thread
- * every <em>X</em> milliseconds,
- * where <em>X</em> is specified by the "ProgressBar.repaintInterval"
- * UI default.
- *
- * @see #setAnimationIndex
- * @since 1.4
- */
- protected void incrementAnimationIndex() {
- int newValue = getAnimationIndex() + 1;
-
- if (newValue < numFrames) {
- setAnimationIndex(newValue);
- } else {
- setAnimationIndex(0);
- }
- }
-
- /**
- * Returns the desired number of milliseconds between repaints.
- * This value is meaningful
- * only if the progress bar is in indeterminate mode.
- * The repaint interval determines how often the
- * default animation thread's timer is fired.
- * It's also used by the default indeterminate progress bar
- * painting code when determining
- * how far to move the bouncing box per frame.
- * The repaint interval is specified by
- * the "ProgressBar.repaintInterval" UI default.
- *
- * @return the repaint interval, in milliseconds
- */
- private int getRepaintInterval() {
- return repaintInterval;
- }
-
- private int initRepaintInterval() {
- repaintInterval = DefaultLookup.getInt(progressBar,
- this, "ProgressBar.repaintInterval", 50);
- return repaintInterval;
- }
-
- /**
- * Returns the number of milliseconds per animation cycle.
- * This value is meaningful
- * only if the progress bar is in indeterminate mode.
- * The cycle time is used by the default indeterminate progress bar
- * painting code when determining
- * how far to move the bouncing box per frame.
- * The cycle time is specified by
- * the "ProgressBar.cycleTime" UI default
- * and adjusted, if necessary,
- * by the initIndeterminateDefaults method.
- *
- * @return the cycle time, in milliseconds
- */
- private int getCycleTime() {
- return cycleTime;
- }
-
- private int initCycleTime() {
- cycleTime = DefaultLookup.getInt(progressBar, this,
- "ProgressBar.cycleTime", 3000);
- return cycleTime;
- }
-
-
- /** Initialize cycleTime, repaintInterval, numFrames, animationIndex. */
- private void initIndeterminateDefaults() {
- initRepaintInterval(); //initialize repaint interval
- initCycleTime(); //initialize cycle length
-
- // Make sure repaintInterval is reasonable.
- if (repaintInterval <= 0) {
- repaintInterval = 100;
- }
-
- // Make sure cycleTime is reasonable.
- if (repaintInterval > cycleTime) {
- cycleTime = repaintInterval * 20;
- } else {
- // Force cycleTime to be a even multiple of repaintInterval.
- int factor = (int)Math.ceil(
- ((double)cycleTime)
- / ((double)repaintInterval*2));
- cycleTime = repaintInterval*factor*2;
- }
- }
-
- /**
- * Invoked by PropertyChangeHandler.
- *
- * NOTE: This might not be invoked until after the first
- * paintIndeterminate call.
- */
- private void initIndeterminateValues() {
- initIndeterminateDefaults();
- //assert cycleTime/repaintInterval is a whole multiple of 2.
- numFrames = cycleTimerepaintInterval;
- initAnimationIndex();
-
- boxRect = new Rectangle();
- nextPaintRect = new Rectangle();
- componentInnards = new Rectangle();
- oldComponentInnards = new Rectangle();
-
- // we only bother installing the HierarchyChangeListener if we
- // are indeterminate
- progressBar.addHierarchyListener(getHandler());
-
- // start the animation thread if necessary
- if (progressBar.isDisplayable()) {
- startAnimationTimer();
- }
- }
-
- /** Invoked by PropertyChangeHandler. */
- private void cleanUpIndeterminateValues() {
- // stop the animation thread if necessary
- if (progressBar.isDisplayable()) {
- stopAnimationTimer();
- }
-
- cycleTime = repaintInterval = 0;
- numFrames = animationIndex = 0;
- maxPosition = 0;
- delta = 0.0;
-
- boxRect = nextPaintRect = null;
- componentInnards = oldComponentInnards = null;
-
- progressBar.removeHierarchyListener(getHandler());
- }
-
- // Called from initIndeterminateValues to initialize the animation index.
- // This assumes that numFrames is set to a correct value.
- private void initAnimationIndex() {
- if ((progressBar.getOrientation() == JProgressBar.HORIZONTAL) &&
- (BasicGraphicsUtils.isLeftToRight(progressBar))) {
- // If this is a left-to-right progress bar,
- // start at the first frame.
- setAnimationIndex(0);
- } else {
- // If we go right-to-left or vertically, start at the right/bottom.
- setAnimationIndex(numFrames2);
- }
- }
-
- //
- // Animation Thread
- //
- /**
- * Implements an animation thread that invokes repaint
- * at a fixed rate. If ADJUSTTIMER is true, this thread
- * will continuously adjust the repaint interval to
- * try to make the actual time between repaints match
- * the requested rate.
- */
- private class Animator implements ActionListener {
- private Timer timer;
- private long previousDelay; //used to tune the repaint interval
- private int interval; //the fixed repaint interval
- private long lastCall; //the last time actionPerformed was called
- private int MINIMUM_DELAY = 5;
-
- /**
- * Creates a timer if one doesn't already exist,
- * then starts the timer thread.
- */
- private void start(int interval) {
- previousDelay = interval;
- lastCall = 0;
-
- if (timer == null) {
- timer = new Timer(interval, this);
- } else {
- timer.setDelay(interval);
- }
-
- if (ADJUSTTIMER) {
- timer.setRepeats(false);
- timer.setCoalesce(false);
- }
-
- timer.start();
- }
-
- /**
- * Stops the timer thread.
- */
- private void stop() {
- timer.stop();
- }
-
- /**
- * Reacts to the timer's action events.
- */
- public void actionPerformed(ActionEvent e) {
- if (ADJUSTTIMER) {
- long time = System.currentTimeMillis();
-
- if (lastCall > 0) { //adjust nextDelay
- //XXX maybe should cache this after a while
- //actual = time - lastCall
- //difference = actual - interval
- //nextDelay = previousDelay - difference
- // = previousDelay - (time - lastCall - interval)
- int nextDelay = (int)(previousDelay
- - time + lastCall
- + getRepaintInterval());
- if (nextDelay < MINIMUM_DELAY) {
- nextDelay = MINIMUM_DELAY;
- }
- timer.setInitialDelay(nextDelay);
- previousDelay = nextDelay;
- }
- timer.start();
- lastCall = time;
- }
-
- incrementAnimationIndex(); //paint next frame
- }
- }
-
-
- /**
- * This inner class is marked "public" due to a compiler bug.
- * This class should be treated as a "protected" inner class.
- * Instantiate it only within subclasses of BasicProgressBarUI.
- */
- public class ChangeHandler implements ChangeListener {
- // NOTE: This class exists only for backward compatability. All
- // its functionality has been moved into Handler. If you need to add
- // new functionality add it to the Handler, but make sure this
- // class calls into the Handler.
- public void stateChanged(ChangeEvent e) {
- getHandler().stateChanged(e);
- }
- }
-
-
- private class Handler implements ChangeListener, PropertyChangeListener, HierarchyListener {
- // ChangeListener
- public void stateChanged(ChangeEvent e) {
- BoundedRangeModel model = progressBar.getModel();
- int newRange = model.getMaximum() - model.getMinimum();
- int newPercent;
- int oldPercent = getCachedPercent();
-
- if (newRange > 0) {
- newPercent = (int)((100 * (long)model.getValue()) / newRange);
- } else {
- newPercent = 0;
- }
-
- if (newPercent != oldPercent) {
- setCachedPercent(newPercent);
- progressBar.repaint();
- }
- }
-
- // PropertyChangeListener
- public void propertyChange(PropertyChangeEvent e) {
- String prop = e.getPropertyName();
- if ("indeterminate" == prop) {
- if (progressBar.isIndeterminate()) {
- initIndeterminateValues();
- } else {
- //clean up
- cleanUpIndeterminateValues();
- }
- progressBar.repaint();
- }
- }
-
- // we don't want the animation to keep running if we're not displayable
- public void hierarchyChanged(HierarchyEvent he) {
- if ((he.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
- if (progressBar.isIndeterminate()) {
- if (progressBar.isDisplayable()) {
- startAnimationTimer();
- } else {
- stopAnimationTimer();
- }
- }
- }
- }
- }
- }