Source for javax.swing.plaf.basic.BasicProgressBarUI

   1: /* BasicProgressBarUI.java --
   2:    Copyright (C) 2004, 2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.plaf.basic;
  40: 
  41: import java.awt.Color;
  42: import java.awt.Dimension;
  43: import java.awt.Font;
  44: import java.awt.FontMetrics;
  45: import java.awt.Graphics;
  46: import java.awt.Insets;
  47: import java.awt.Point;
  48: import java.awt.Rectangle;
  49: import java.awt.Shape;
  50: import java.awt.event.ActionEvent;
  51: import java.awt.event.ActionListener;
  52: import java.awt.event.ComponentAdapter;
  53: import java.awt.event.ComponentEvent;
  54: import java.awt.event.ComponentListener;
  55: import java.awt.geom.AffineTransform;
  56: import java.beans.PropertyChangeEvent;
  57: import java.beans.PropertyChangeListener;
  58: 
  59: import javax.swing.JComponent;
  60: import javax.swing.JProgressBar;
  61: import javax.swing.LookAndFeel;
  62: import javax.swing.SwingConstants;
  63: import javax.swing.SwingUtilities;
  64: import javax.swing.Timer;
  65: import javax.swing.UIManager;
  66: import javax.swing.event.AncestorEvent;
  67: import javax.swing.event.AncestorListener;
  68: import javax.swing.event.ChangeEvent;
  69: import javax.swing.event.ChangeListener;
  70: import javax.swing.plaf.ComponentUI;
  71: import javax.swing.plaf.ProgressBarUI;
  72: 
  73: /**
  74:  * The Basic Look and Feel UI delegate for the
  75:  * JProgressBar.
  76:  */
  77: public class BasicProgressBarUI extends ProgressBarUI
  78: {
  79:   /**
  80:    * A helper class that listens for ChangeEvents
  81:    * from the progressBar's model.
  82:    *
  83:    * @specnote Apparently this class was intended to be protected,
  84:    *           but was made public by a compiler bug and is now
  85:    *           public for compatibility.
  86:    */
  87:   public class ChangeHandler implements ChangeListener
  88:   {
  89:     /**
  90:      * Called every time the state of the model changes.
  91:      *
  92:      * @param e The ChangeEvent given by the model.
  93:      */
  94:     public void stateChanged(ChangeEvent e)
  95:     {
  96:       // Nothing to do but repaint.
  97:       progressBar.repaint();
  98:     }
  99:   }
 100: 
 101:   /**
 102:    * This helper class is used to listen for
 103:    * PropertyChangeEvents from the progressBar.
 104:    */
 105:   private class PropertyChangeHandler implements PropertyChangeListener
 106:   {
 107:     /**
 108:      * Called every time the properties of the
 109:      * progressBar change.
 110:      *
 111:      * @param e The PropertyChangeEvent given by the progressBar.
 112:      */
 113:     public void propertyChange(PropertyChangeEvent e)
 114:     {
 115:       // Only need to listen for indeterminate changes.
 116:       // All other things are done on a repaint.
 117:       if (e.getPropertyName().equals("indeterminate"))
 118:         if (((Boolean) e.getNewValue()).booleanValue()
 119:             && progressBar.isShowing())
 120:           startAnimationTimer();
 121:         else
 122:           stopAnimationTimer();
 123:     }
 124:   }
 125: 
 126:   /**
 127:    * Receives notification when the progressbar is becoming visible or
 128:    * invisible and starts/stops the animation timer accordingly.
 129:    *
 130:    * @author Roman Kennke (kennke@aicas.com)
 131:    */
 132:   private class AncestorHandler implements AncestorListener
 133:   {
 134: 
 135:     /**
 136:      * Receives notification when the progressbar is becoming visible. This
 137:      * starts the animation timer if the progressbar is indeterminate.
 138:      *
 139:      * @param event the ancestor event
 140:      */
 141:     public void ancestorAdded(AncestorEvent event)
 142:     {
 143:       if (progressBar.isIndeterminate())
 144:         startAnimationTimer();
 145:     }
 146: 
 147:     /**
 148:      * Receives notification when the progressbar is becoming invisible. This
 149:      * stops the animation timer if the progressbar is indeterminate.
 150:      *
 151:      * @param event the ancestor event
 152:      */
 153:     public void ancestorRemoved(AncestorEvent event)
 154:     {
 155:       stopAnimationTimer();
 156:     }
 157: 
 158:     /**
 159:      * Receives notification when an ancestor has been moved. We don't need to
 160:      * do anything here.
 161:      */
 162:     public void ancestorMoved(AncestorEvent event)
 163:     {
 164:       // Nothing to do here.
 165:     }
 166: 
 167:   }
 168: 
 169:   /**
 170:    * This helper class is used to listen for
 171:    * the animationTimer's intervals. On every interval,
 172:    * the bouncing box should move.
 173:    */
 174:   private class Animator implements ActionListener
 175:   {
 176:     /**
 177:      * Called every time the animationTimer reaches
 178:      * its interval.
 179:      *
 180:      * @param e The ActionEvent given by the timer.
 181:      */
 182:     public void actionPerformed(ActionEvent e)
 183:     {
 184:       // Incrementing the animation index will cause
 185:       // a repaint.
 186:       incrementAnimationIndex();
 187:     }
 188:   }
 189: 
 190:   /**
 191:    * Receives notification when the size of the progress bar changes and
 192:    * invalidates the layout information for the box calculation in
 193:    * {@link BasicProgressBarUI#getBox(Rectangle)}.
 194:    *
 195:    * @author Roman Kennke (kennke@aicas.com)
 196:    */
 197:   private class ComponentHandler extends ComponentAdapter
 198:   {
 199:     /**
 200:      * Receives notification when the size of the progress bar changes and
 201:      * invalidates the layout information for the box calculation in
 202:      * {@link BasicProgressBarUI#getBox}.
 203:      *
 204:      * @param e the component event
 205:      */
 206:     public void componentResized(ComponentEvent e)
 207:     {
 208:       boxDependent = -1;
 209:       boxIndependent = -1;
 210:       incr = -1;
 211:     }
 212:   }
 213: 
 214:   /**
 215:    * Holds the value of the bouncing box that is returned by {@link #getBox}.
 216:    *
 217:    * @since 1.5
 218:    */
 219:   protected Rectangle boxRect;
 220: 
 221:   /** The timer used to move the bouncing box. */
 222:   private transient Timer animationTimer;
 223: 
 224:   // The total number of frames must be an even number.
 225:   // The total number of frames is calculated from
 226:   // the cycleTime and repaintInterval given by
 227:   // the basic Look and Feel defaults.
 228:   //
 229:   // +-----------------------------------------------+
 230:   // | frame0 | frame1 | frame2 | frame 3 | frame 4  |
 231:   // |        | frame7 | frame6 | frame 5 |          |
 232:   // +-----------------------------------------------+
 233: 
 234:   /** The current animation index. */
 235:   private transient int animationIndex;
 236: 
 237:   /** The total number of frames.*/
 238:   private transient int numFrames;
 239: 
 240:   /** The helper that moves the bouncing box. */
 241:   private transient Animator animation;
 242: 
 243:   /** The helper that listens for property change events. */
 244:   private transient PropertyChangeHandler propertyListener;
 245: 
 246:   /** The Listener for the model. */
 247:   protected ChangeListener changeListener;
 248: 
 249:   /** The progressBar for this UI. */
 250:   protected JProgressBar progressBar;
 251: 
 252: 
 253:   /**
 254:    * The size of the box returned by {@link #getBox} in the orientation
 255:    * direction of the progress bar. This is package private to avoid accessor
 256:    * method.
 257:    */
 258:   transient double boxDependent = - 1;
 259: 
 260:   /**
 261:    * The size of the box returned by {@link #getBox} against the orientation
 262:    * direction of the progress bar. This is package private to avoid accessor
 263:    * method.
 264:    */
 265:   transient int boxIndependent = - 1;
 266: 
 267:   /**
 268:    * The increment for box animation. This is package private to avoid accessor
 269:    * method.
 270:    */
 271:   transient double incr = -1;
 272: 
 273:   /** The length of the cell. The cell is the painted part. */
 274:   private transient int cellLength;
 275: 
 276:   /** The gap between cells. */
 277:   private transient int cellSpacing;
 278: 
 279:   /** The color of the text when the bar is not over it.*/
 280:   private transient Color selectionBackground;
 281: 
 282:   /** The color of the text when the bar is over it. */
 283:   private transient Color selectionForeground;
 284: 
 285:   /**
 286:    * Listens for notification when the component becomes showing and
 287:    * starts/stops the animation timer.
 288:    */
 289:   private AncestorListener ancestorListener;
 290: 
 291:   /**
 292:    * Listens for resize events on the progress bar and invalidates some
 293:    * layout info.
 294:    */
 295:   private ComponentListener componentListener;
 296: 
 297:   /**
 298:    * Creates a new BasicProgressBarUI object.
 299:    */
 300:   public BasicProgressBarUI()
 301:   {
 302:     super();
 303:   }
 304: 
 305:   /**
 306:    * Creates a new BasicProgressBarUI for the component.
 307:    *
 308:    * @param x The JComponent to create the UI for.
 309:    *
 310:    * @return A new BasicProgressBarUI.
 311:    */
 312:   public static ComponentUI createUI(JComponent x)
 313:   {
 314:     return new BasicProgressBarUI();
 315:   }
 316: 
 317:   /**
 318:    * This method returns the length of the bar (from the minimum)
 319:    * in pixels (or units that the Graphics object draws in) based
 320:    * on the progressBar's getPercentComplete() value.
 321:    *
 322:    * @param b The insets of the progressBar.
 323:    * @param width The width of the progressBar.
 324:    * @param height The height of the progressBar.
 325:    *
 326:    * @return The length of the bar that should be painted in pixels.
 327:    */
 328:   protected int getAmountFull(Insets b, int width, int height)
 329:   {
 330:     double percentDone = progressBar.getPercentComplete();
 331:     if (progressBar.getOrientation() == JProgressBar.HORIZONTAL)
 332:       return (int) (percentDone * (width - b.left - b.right));
 333:     else
 334:       return (int) (percentDone * (height - b.top - b.bottom));
 335:   }
 336: 
 337:   /**
 338:    * The current animation index.
 339:    *
 340:    * @return The current animation index.
 341:    */
 342:   protected int getAnimationIndex()
 343:   {
 344:     return animationIndex;
 345:   }
 346: 
 347:   /**
 348:    * This method returns the size and position of the bouncing box
 349:    * for the current animation index. It stores the values in the
 350:    * given rectangle and returns it. It returns null if no box should
 351:    * be drawn.
 352:    *
 353:    * @param r The bouncing box rectangle.
 354:    *
 355:    * @return The bouncing box rectangle.
 356:    */
 357:   protected Rectangle getBox(Rectangle r)
 358:   {
 359:     if (!progressBar.isIndeterminate())
 360:       return null;
 361:     if (r == null)
 362:       r = new Rectangle();
 363: 
 364:     Rectangle vr = new Rectangle();
 365:     SwingUtilities.calculateInnerArea(progressBar, vr);
 366: 
 367:     // Recalculate the metrics only when size of the progressbar has changed.
 368:     if (incr == -1 || boxDependent == -1 || boxIndependent == -1)
 369:       {
 370:         //numFrames has to be an even number as defined by spec.
 371:         int iterations = numFrames / 2;
 372:         if (progressBar.getOrientation() == JProgressBar.HORIZONTAL)
 373:           {
 374:             boxDependent = vr.width / 6.;
 375:             incr = ((double) (vr.width - boxDependent)) / (double) iterations;
 376:             boxIndependent = vr.height;
 377:           }
 378:         else
 379:           {
 380:             boxDependent = vr.height / 6.;
 381:             incr = ((double) (vr.height - boxDependent)) / (double) iterations;
 382:             boxIndependent = vr.width;
 383:           }
 384:       }
 385: 
 386:     int index = getAnimationIndex();
 387:     if (animationIndex > numFrames / 2)
 388:       index = numFrames - getAnimationIndex();
 389: 
 390:     if (progressBar.getOrientation() == JProgressBar.HORIZONTAL)
 391:       {
 392:         r.x = vr.x + (int) (incr * index);
 393:         r.y = vr.y;
 394:         r.width = (int) boxDependent;
 395:         r.height = (int) boxIndependent;
 396:       }
 397:     else
 398:       {
 399:         r.x = vr.x;
 400:         r.y = vr.height - (int) (incr * index) + vr.y - (int) boxDependent;
 401:         r.width = (int) boxIndependent;
 402:         r.height = (int) boxDependent;
 403:       }
 404:     return r;
 405:   }
 406: 
 407:   /**
 408:    * This method returns the length of the cells.
 409:    *
 410:    * @return The cell length.
 411:    */
 412:   protected int getCellLength()
 413:   {
 414:     return cellLength;
 415:   }
 416: 
 417:   /**
 418:    * This method returns the spacing between cells.
 419:    *
 420:    * @return The cell gap.
 421:    */
 422:   protected int getCellSpacing()
 423:   {
 424:     return cellSpacing;
 425:   }
 426: 
 427:   /**
 428:    * This method returns the maximum size of the JComponent.
 429:    * If it returns null, it is up to the LayoutManager
 430:    * to give it a size.
 431:    *
 432:    * @param c The component to find a maximum size for.
 433:    *
 434:    * @return The maximum size.
 435:    */
 436:   public Dimension getMaximumSize(JComponent c)
 437:   {
 438:     Insets insets = c.getInsets();
 439:     Dimension ret;
 440:     int orientation = progressBar.getOrientation();
 441:     if (orientation == JProgressBar.VERTICAL)
 442:       {
 443:         ret = getPreferredInnerVertical();
 444:         ret.height = Short.MAX_VALUE;
 445:         ret.width += insets.left + insets.right;
 446:       }
 447:     else
 448:       {
 449:         ret = getPreferredInnerHorizontal();
 450:         ret.width = Short.MAX_VALUE;
 451:         ret.height += insets.top + insets.bottom;
 452:       }
 453:     return ret;
 454:   }
 455: 
 456:   /**
 457:    * This method returns the minimum size of the JComponent.
 458:    * If it returns null, it is up to the LayoutManager to
 459:    * give it a size.
 460:    *
 461:    * @param c The component to find a minimum size for.
 462:    *
 463:    * @return The minimum size.
 464:    */
 465:   public Dimension getMinimumSize(JComponent c)
 466:   {
 467:     Insets insets = c.getInsets();
 468:     Dimension ret;
 469:     int orientation = progressBar.getOrientation();
 470:     if (orientation == JProgressBar.VERTICAL)
 471:       {
 472:         ret = getPreferredInnerVertical();
 473:         ret.height = 10;
 474:         ret.width += insets.left + insets.right;
 475:       }
 476:     else
 477:       {
 478:         ret = getPreferredInnerHorizontal();
 479:         ret.width = 10;
 480:         ret.height += insets.top + insets.bottom;
 481:       }
 482:     return ret;
 483:   }
 484: 
 485:   /**
 486:    * This method returns the preferred size of the inner
 487:    * rectangle (the bounds without the insets) if the
 488:    * progressBar is horizontal.
 489:    *
 490:    * @return The preferred size of the progressBar minus
 491:    *         insets if it's horizontal.
 492:    */
 493:   protected Dimension getPreferredInnerHorizontal()
 494:   {
 495:     Font font = progressBar.getFont();
 496:     FontMetrics fm = progressBar.getFontMetrics(font);
 497: 
 498:     int stringWidth = 0;
 499:     String str = progressBar.getString();
 500:     if (str != null)
 501:       stringWidth = fm.stringWidth(progressBar.getString());
 502:     Insets i = progressBar.getInsets();
 503:     int prefWidth = Math.max(200 - i.left - i.right, stringWidth);
 504: 
 505:     int stringHeight = 0;
 506:     if (str != null)
 507:       stringHeight = fm.getHeight();
 508:     int prefHeight = Math.max(16 - i.top - i.bottom, stringHeight);
 509: 
 510:     return new Dimension(prefWidth, prefHeight);
 511:   }
 512: 
 513:   /**
 514:    * This method returns the preferred size of the inner
 515:    * rectangle (the bounds without insets) if the
 516:    * progressBar is vertical.
 517:    *
 518:    * @return The preferred size of the progressBar minus
 519:    *         insets if it's vertical.
 520:    */
 521:   protected Dimension getPreferredInnerVertical()
 522:   {
 523:     Font font = progressBar.getFont();
 524:     FontMetrics fm = progressBar.getFontMetrics(font);
 525: 
 526:     int stringWidth = 0;
 527:     String str = progressBar.getString();
 528:     if (str != null)
 529:       stringWidth = fm.stringWidth(progressBar.getString());
 530:     Insets i = progressBar.getInsets();
 531:     int prefHeight = Math.max(200 - i.left - i.right, stringWidth);
 532: 
 533:     int stringHeight = 0;
 534:     if (str != null)
 535:       stringHeight = fm.getHeight();
 536:     int prefWidth = Math.max(16 - i.top - i.bottom, stringHeight);
 537: 
 538:     return new Dimension(prefWidth, prefHeight);
 539:   }
 540: 
 541:   /**
 542:    * This method returns the preferred size of the
 543:    * given JComponent. If it returns null, then it
 544:    * is up to the LayoutManager to give it a size.
 545:    *
 546:    * @param c The component to find the preferred size for.
 547:    *
 548:    * @return The preferred size of the component.
 549:    */
 550:   public Dimension getPreferredSize(JComponent c)
 551:   {
 552:     Insets insets = c.getInsets();
 553:     Dimension ret;
 554:     int orientation = progressBar.getOrientation();
 555:     if (orientation == JProgressBar.VERTICAL)
 556:       ret = getPreferredInnerVertical();
 557:     else
 558:       ret = getPreferredInnerHorizontal();
 559:     ret.width += insets.left + insets.right;
 560:     ret.height += insets.top + insets.bottom;
 561:     return ret;
 562:   }
 563: 
 564:   /**
 565:    * This method returns the Color that the text is shown in when the bar is
 566:    * not over the text.
 567:    *
 568:    * @return The color of the text when the bar is not over it.
 569:    */
 570:   protected Color getSelectionBackground()
 571:   {
 572:     return selectionBackground;
 573:   }
 574: 
 575:   /**
 576:    * This method returns the Color that the text is shown in  when the bar is
 577:    * over the text.
 578:    *
 579:    * @return The color of the text when the bar is over it.
 580:    */
 581:   protected Color getSelectionForeground()
 582:   {
 583:     return selectionForeground;
 584:   }
 585: 
 586:   /**
 587:    * This method returns the point (the top left of the bounding box)
 588:    * where the text should be painted.
 589:    *
 590:    * @param g The Graphics object to measure FontMetrics with.
 591:    * @param progressString The string to paint.
 592:    * @param x The x coordinate of the overall bounds box.
 593:    * @param y The y coordinate of the overall bounds box.
 594:    * @param width The width of the overall bounds box.
 595:    * @param height The height of the overall bounds box.
 596:    *
 597:    * @return The top left of the bounding box where text should be painted.
 598:    */
 599:   protected Point getStringPlacement(Graphics g, String progressString, int x,
 600:                                      int y, int width, int height)
 601:   {
 602:     Rectangle tr = new Rectangle();
 603:     Rectangle vr = new Rectangle();
 604:     Rectangle ir = new Rectangle();
 605: 
 606:     if (progressBar.getOrientation() == JProgressBar.HORIZONTAL)
 607:       vr.setBounds(x, y, width, height);
 608:     else
 609:       vr.setBounds(y, x, height, width);
 610: 
 611:     Font f = g.getFont();
 612:     FontMetrics fm = g.getFontMetrics(f);
 613: 
 614:     SwingUtilities.layoutCompoundLabel(progressBar, fm, progressString, null,
 615:                                        SwingConstants.CENTER,
 616:                                        SwingConstants.CENTER,
 617:                                        SwingConstants.CENTER,
 618:                                        SwingConstants.CENTER, vr, ir, tr, 0);
 619: 
 620:     if (progressBar.getOrientation() == JProgressBar.HORIZONTAL)
 621:       return new Point(tr.x, tr.y);
 622:     else
 623:       return new Point(tr.y, tr.x);
 624:   }
 625: 
 626:   /**
 627:    * This method increments the animation index.
 628:    */
 629:   protected void incrementAnimationIndex()
 630:   {
 631:     animationIndex++;
 632:     //numFrames is like string length, it should be named numFrames or something
 633:     if (animationIndex >= numFrames)
 634:       animationIndex = 0;
 635:     progressBar.repaint();
 636:   }
 637: 
 638:   /**
 639:    * This method paints the progressBar. It delegates its responsibilities
 640:    * to paintDeterminate and paintIndeterminate.
 641:    *
 642:    * @param g The Graphics object to paint with.
 643:    * @param c The JComponent to paint.
 644:    */
 645:   public void paint(Graphics g, JComponent c)
 646:   {
 647:     if (! progressBar.isIndeterminate())
 648:       paintDeterminate(g, c);
 649:     else
 650:       paintIndeterminate(g, c);
 651:   }
 652: 
 653:   /**
 654:    * This method is called if the painting to be done is
 655:    * for a determinate progressBar.
 656:    *
 657:    * @param g The Graphics object to paint with.
 658:    * @param c The JComponent to paint.
 659:    */
 660:   protected void paintDeterminate(Graphics g, JComponent c)
 661:   {
 662:     Color saved = g.getColor();
 663:     int space = getCellSpacing();
 664:     int len = getCellLength();
 665:     int max = progressBar.getMaximum();
 666:     int min = progressBar.getMinimum();
 667:     int value = progressBar.getValue();
 668: 
 669:     Rectangle vr = SwingUtilities.calculateInnerArea(c, new Rectangle());
 670:     Rectangle or = progressBar.getBounds();
 671:     Insets insets = c.getInsets();
 672: 
 673:     int amountFull = getAmountFull(insets, or.width, or.height);
 674: 
 675:         if (progressBar.getOrientation() == JProgressBar.HORIZONTAL)
 676:           {
 677:             g.setColor(c.getForeground());
 678:             g.fillRect(vr.x, vr.y, amountFull, vr.height);
 679:           }
 680:         else
 681:           {
 682:             g.setColor(c.getForeground());
 683:             g.fillRect(vr.x, vr.y + vr.height - amountFull, vr.width,
 684:                        amountFull);
 685:           }
 686: 
 687:     if (progressBar.isStringPainted() && !progressBar.getString().equals(""))
 688:       paintString(g, 0, 0, or.width, or.height, amountFull, insets);
 689:     g.setColor(saved);
 690:   }
 691: 
 692:   /**
 693:    * This method is called if the painting to be done is for
 694:    * an indeterminate progressBar.
 695:    *
 696:    * @param g The Graphics object to paint with.
 697:    * @param c The JComponent to paint.
 698:    */
 699:   protected void paintIndeterminate(Graphics g, JComponent c)
 700:   {
 701:     //need to paint the box at it's current position. no text is painted since
 702:     //all we're doing is bouncing back and forth
 703:     Color saved = g.getColor();
 704:     Insets insets = c.getInsets();
 705: 
 706:     Rectangle or = c.getBounds();
 707:     Rectangle vr = new Rectangle();
 708:     SwingUtilities.calculateInnerArea(c, vr);
 709: 
 710:     g.setColor(c.getBackground());
 711:     g.fillRect(vr.x, vr.y, vr.width, vr.height);
 712: 
 713:     boxRect = getBox(boxRect);
 714: 
 715:     g.setColor(c.getForeground());
 716:     g.fillRect(boxRect.x, boxRect.y, boxRect.width, boxRect.height);
 717: 
 718:     if (progressBar.isStringPainted() && !progressBar.getString().equals(""))
 719:       paintString(g, 0, 0, or.width, or.height,
 720:                   getAmountFull(insets, or.width, or.height), insets);
 721: 
 722:     g.setColor(saved);
 723:   }
 724: 
 725:   /**
 726:    * This method paints the string for the progressBar.
 727:    *
 728:    * @param g The Graphics object to paint with.
 729:    * @param x The x coordinate of the progressBar.
 730:    * @param y The y coordinate of the progressBar.
 731:    * @param width The width of the progressBar.
 732:    * @param height The height of the progressBar.
 733:    * @param amountFull The amount of the progressBar that has its bar filled.
 734:    * @param b The insets of the progressBar.
 735:    */
 736:   protected void paintString(Graphics g, int x, int y, int width, int height,
 737:                              int amountFull, Insets b)
 738:   {
 739:     String str = progressBar.getString();
 740:     int full = getAmountFull(b, width, height);
 741:     Point placement = getStringPlacement(g, progressBar.getString(),
 742:                                          x + b.left, y + b.top,
 743:                                          width - b.left - b.right,
 744:                                          height - b.top - b.bottom);
 745:     Color savedColor = g.getColor();
 746:     Shape savedClip = g.getClip();
 747:     FontMetrics fm = g.getFontMetrics(progressBar.getFont());
 748: 
 749:     if (progressBar.getOrientation() == JProgressBar.VERTICAL)
 750:       {
 751:         AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2);
 752:         g.setFont(progressBar.getFont().deriveFont(rotate));
 753:         placement.x = width - placement.x - fm.getAscent();
 754:       }
 755:     else
 756:       {
 757:         placement.y += fm.getAscent();
 758:       }
 759: 
 760:     g.setColor(getSelectionForeground());
 761:     g.setClip(0, 0, full + b.left, height);
 762:     g.drawString(str, placement.x, placement.y);
 763:     g.setColor(getSelectionBackground());
 764:     g.setClip(full + b.left, 0, width - full, height);
 765:     g.drawString(str, placement.x, placement.y);
 766:     g.setClip(savedClip);
 767:     g.setColor(savedColor);
 768:   }
 769: 
 770:   /**
 771:    * This method sets the current animation index. If the index is greater than
 772:    * the number of frames, it resets to 0.
 773:    *
 774:    * @param newValue The new animation index.
 775:    */
 776:   protected void setAnimationIndex(int newValue)
 777:   {
 778:     animationIndex = (newValue <= numFrames) ? newValue : 0;
 779:     progressBar.repaint();
 780:   }
 781: 
 782:   /**
 783:    * This method sets the cell length.
 784:    *
 785:    * @param cellLen The cell length.
 786:    */
 787:   protected void setCellLength(int cellLen)
 788:   {
 789:     cellLength = cellLen;
 790:   }
 791: 
 792:   /**
 793:    * This method sets the cell spacing.
 794:    *
 795:    * @param cellSpace The cell spacing.
 796:    */
 797:   protected void setCellSpacing(int cellSpace)
 798:   {
 799:     cellSpacing = cellSpace;
 800:   }
 801: 
 802:   /**
 803:    * This method starts the animation timer. It is called
 804:    * when the propertyChangeListener detects that the progressBar
 805:    * has changed to indeterminate mode.
 806:    *
 807:    * @since 1.4
 808:    */
 809:   protected void startAnimationTimer()
 810:   {
 811:     if (animationTimer != null)
 812:       animationTimer.start();
 813:   }
 814: 
 815:   /**
 816:    * This method stops the animation timer. It is called when
 817:    * the propertyChangeListener detects that the progressBar
 818:    * has changed to determinate mode.
 819:    *
 820:    * @since 1.4
 821:    */
 822:   protected void stopAnimationTimer()
 823:   {
 824:     if (animationTimer != null)
 825:       animationTimer.stop();
 826:     setAnimationIndex(0);
 827:   }
 828: 
 829:   /**
 830:    * This method changes the settings for the progressBar to
 831:    * the defaults provided by the current Look and Feel.
 832:    */
 833:   protected void installDefaults()
 834:   {
 835:     LookAndFeel.installColorsAndFont(progressBar, "ProgressBar.background",
 836:                                      "ProgressBar.foreground",
 837:                                      "ProgressBar.font");
 838:     LookAndFeel.installBorder(progressBar, "ProgressBar.border");
 839:     progressBar.setOpaque(true);
 840: 
 841:     selectionForeground = UIManager.getColor("ProgressBar.selectionForeground");
 842:     selectionBackground = UIManager.getColor("ProgressBar.selectionBackground");
 843:     cellLength = UIManager.getInt("ProgressBar.cellLength");
 844:     cellSpacing = UIManager.getInt("ProgressBar.cellSpacing");
 845: 
 846:     int repaintInterval = UIManager.getInt("ProgressBar.repaintInterval");
 847:     int cycleTime = UIManager.getInt("ProgressBar.cycleTime");
 848: 
 849:     if (cycleTime % repaintInterval != 0
 850:         && (cycleTime / repaintInterval) % 2 != 0)
 851:       {
 852:         int div = (cycleTime / repaintInterval) + 2;
 853:         div /= 2;
 854:         div *= 2;
 855:         cycleTime = div * repaintInterval;
 856:       }
 857:     setAnimationIndex(0);
 858:     numFrames = cycleTime / repaintInterval;
 859:     animationTimer.setDelay(repaintInterval);
 860:   }
 861: 
 862:   /**
 863:    * The method uninstalls any defaults that were
 864:    * set by the current Look and Feel.
 865:    */
 866:   protected void uninstallDefaults()
 867:   {
 868:     progressBar.setFont(null);
 869:     progressBar.setForeground(null);
 870:     progressBar.setBackground(null);
 871: 
 872:     selectionForeground = null;
 873:     selectionBackground = null;
 874:   }
 875: 
 876:   /**
 877:    * This method registers listeners to all the
 878:    * components that this UI delegate needs to listen to.
 879:    */
 880:   protected void installListeners()
 881:   {
 882:     changeListener = new ChangeHandler();
 883:     propertyListener = new PropertyChangeHandler();
 884:     animation = new Animator();
 885: 
 886:     progressBar.addChangeListener(changeListener);
 887:     progressBar.addPropertyChangeListener(propertyListener);
 888:     animationTimer.addActionListener(animation);
 889: 
 890:     ancestorListener = new AncestorHandler();
 891:     progressBar.addAncestorListener(ancestorListener);
 892: 
 893:     componentListener = new ComponentHandler();
 894:     progressBar.addComponentListener(componentListener);
 895:   }
 896: 
 897:   /**
 898:    * This method unregisters listeners to all the
 899:    * components that were listened to.
 900:    */
 901:   protected void uninstallListeners()
 902:   {
 903:     progressBar.removeChangeListener(changeListener);
 904:     progressBar.removePropertyChangeListener(propertyListener);
 905:     animationTimer.removeActionListener(animation);
 906: 
 907:     changeListener = null;
 908:     propertyListener = null;
 909:     animation = null;
 910: 
 911:     if (ancestorListener != null)
 912:       progressBar.removeAncestorListener(ancestorListener);
 913:     ancestorListener = null;
 914: 
 915:     if (componentListener != null)
 916:       progressBar.removeComponentListener(componentListener);
 917:     componentListener = null;
 918:   }
 919: 
 920:   /**
 921:    * This method installs the UI for the given JComponent.
 922:    * This includes setting up defaults and listeners as
 923:    * well as initializing any values or objects that
 924:    * the UI may need.
 925:    *
 926:    * @param c The JComponent that is having this UI installed.
 927:    */
 928:   public void installUI(JComponent c)
 929:   {
 930:     super.installUI(c);
 931:     if (c instanceof JProgressBar)
 932:       {
 933:         progressBar = (JProgressBar) c;
 934: 
 935:         animationTimer = new Timer(200, null);
 936:         animationTimer.setRepeats(true);
 937: 
 938:         installDefaults();
 939:         installListeners();
 940:       }
 941:     if (progressBar.isIndeterminate())
 942:       startAnimationTimer();
 943:   }
 944: 
 945:   /**
 946:    * This method removes the UI for the given JComponent.
 947:    * This includes removing any listeners or defaults
 948:    * that the installUI may have set up.
 949:    *
 950:    * @param c The JComponent that is having this UI uninstalled.
 951:    */
 952:   public void uninstallUI(JComponent c)
 953:   {
 954:     super.uninstallUI(c);
 955:     uninstallListeners();
 956:     uninstallDefaults();
 957: 
 958:     animationTimer = null;
 959:     progressBar = null;
 960:   }
 961: 
 962: }