/**
   * 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);

    if (barRectWidth <= 0 || barRectHeight <= 0) {
      return;
    }

    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);
      }
    }
  }
  /**
   * 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.PI / 2);
      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);
  }
  /**
   * 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 = numFrames / 2;

    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;
  }
  /** 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 an enum indicating how the baseline of the component changes as the size changes.
  *
  * @throws NullPointerException {@inheritDoc}
  * @see javax.swing.JComponent#getBaseline(int, int)
  * @since 1.6
  */
 public Component.BaselineResizeBehavior getBaselineResizeBehavior(JComponent c) {
   super.getBaselineResizeBehavior(c);
   if (progressBar.isStringPainted() && progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
     return Component.BaselineResizeBehavior.CENTER_OFFSET;
   }
   return Component.BaselineResizeBehavior.OTHER;
 }
 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;
 }
 /**
  * Returns the baseline.
  *
  * @throws NullPointerException {@inheritDoc}
  * @throws IllegalArgumentException {@inheritDoc}
  * @see javax.swing.JComponent#getBaseline(int, int)
  * @since 1.6
  */
 public int getBaseline(JComponent c, int width, int height) {
   super.getBaseline(c, width, height);
   if (progressBar.isStringPainted() && progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
     FontMetrics metrics = progressBar.getFontMetrics(progressBar.getFont());
     Insets insets = progressBar.getInsets();
     int y = insets.top;
     height = height - insets.top - insets.bottom;
     return y + (height + metrics.getAscent() - metrics.getLeading() - metrics.getDescent()) / 2;
   }
   return -1;
 }
 // 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(numFrames / 2);
   }
 }
  /**
   * 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;
  }
  /**
   * 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;
  }
  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;
  }
  /**
   * 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(width / 2 - stringWidth / 2),
          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(height / 2 - stringWidth / 2));
    }
  }
 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);
     }
   }
 }
  /**
   * 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);

    if (barRectWidth <= 0 || barRectHeight <= 0) {
      return;
    }

    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, (barRectHeight / 2) + b.top, amountFull + b.left, (barRectHeight / 2) + b.top);
      } else {
        g2.drawLine(
            (barRectWidth + b.left),
            (barRectHeight / 2) + b.top,
            barRectWidth + b.left - amountFull,
            (barRectHeight / 2) + 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(
          barRectWidth / 2 + b.left,
          b.top + barRectHeight,
          barRectWidth / 2 + b.left,
          b.top + barRectHeight - amountFull);
    }

    // Deal with possible text painting
    if (progressBar.isStringPainted()) {
      paintString(g, b.left, b.top, barRectWidth, barRectHeight, amountFull, b);
    }
  }