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(x, y, width, height);
 604:     Rectangle ir = new Rectangle();
 605: 
 606:     Font f = g.getFont();
 607:     FontMetrics fm = g.getFontMetrics(f);
 608: 
 609:     SwingUtilities.layoutCompoundLabel(progressBar, fm, progressString, null,
 610:                                        SwingConstants.CENTER,
 611:                                        SwingConstants.CENTER,
 612:                                        SwingConstants.CENTER,
 613:                                        SwingConstants.CENTER, vr, ir, tr, 0);
 614:     return new Point(tr.x, tr.y);
 615:   }
 616: 
 617:   /**
 618:    * This method increments the animation index.
 619:    */
 620:   protected void incrementAnimationIndex()
 621:   {
 622:     animationIndex++;
 623:     //numFrames is like string length, it should be named numFrames or something
 624:     if (animationIndex >= numFrames)
 625:       animationIndex = 0;
 626:     progressBar.repaint();
 627:   }
 628: 
 629:   /**
 630:    * This method paints the progressBar. It delegates its responsibilities
 631:    * to paintDeterminate and paintIndeterminate.
 632:    *
 633:    * @param g The Graphics object to paint with.
 634:    * @param c The JComponent to paint.
 635:    */
 636:   public void paint(Graphics g, JComponent c)
 637:   {
 638:     if (! progressBar.isIndeterminate())
 639:       paintDeterminate(g, c);
 640:     else
 641:       paintIndeterminate(g, c);
 642:   }
 643: 
 644:   /**
 645:    * This method is called if the painting to be done is 
 646:    * for a determinate progressBar.
 647:    *
 648:    * @param g The Graphics object to paint with.
 649:    * @param c The JComponent to paint.
 650:    */
 651:   protected void paintDeterminate(Graphics g, JComponent c)
 652:   {
 653:     Color saved = g.getColor();
 654:     int space = getCellSpacing();
 655:     int len = getCellLength();
 656:     int max = progressBar.getMaximum();
 657:     int min = progressBar.getMinimum();
 658:     int value = progressBar.getValue();
 659: 
 660:     Rectangle vr = SwingUtilities.calculateInnerArea(c, new Rectangle());
 661:     Rectangle or = progressBar.getBounds();
 662:     Insets insets = c.getInsets();
 663: 
 664:     int amountFull = getAmountFull(insets, or.width, or.height);
 665: 
 666:     if (progressBar.getOrientation() == JProgressBar.HORIZONTAL)
 667:       {
 668:         g.setColor(c.getForeground());
 669:         g.fillRect(vr.x, vr.y, amountFull, vr.height);
 670:       }
 671:     else
 672:       {
 673:         g.setColor(c.getForeground());
 674:         g.fillRect(vr.x, vr.y + vr.height - amountFull, vr.width, 
 675:                        amountFull);
 676:       }
 677: 
 678:     if (progressBar.isStringPainted() && !progressBar.getString().equals(""))
 679:       paintString(g, 0, 0, or.width, or.height, amountFull, insets);
 680:     g.setColor(saved);
 681:   }
 682: 
 683:   /**
 684:    * This method is called if the painting to be done is for
 685:    * an indeterminate progressBar.
 686:    *
 687:    * @param g The Graphics object to paint with.
 688:    * @param c The JComponent to paint.
 689:    */
 690:   protected void paintIndeterminate(Graphics g, JComponent c)
 691:   {
 692:     //need to paint the box at it's current position. no text is painted since
 693:     //all we're doing is bouncing back and forth
 694:     Color saved = g.getColor();
 695:     Insets insets = c.getInsets();
 696: 
 697:     Rectangle or = c.getBounds();
 698:     Rectangle vr = new Rectangle();
 699:     SwingUtilities.calculateInnerArea(c, vr);
 700: 
 701:     g.setColor(c.getBackground());
 702:     g.fillRect(vr.x, vr.y, vr.width, vr.height);
 703: 
 704:     boxRect = getBox(boxRect);
 705: 
 706:     g.setColor(c.getForeground());
 707:     g.fillRect(boxRect.x, boxRect.y, boxRect.width, boxRect.height);
 708: 
 709:     if (progressBar.isStringPainted() && !progressBar.getString().equals(""))
 710:       paintString(g, 0, 0, or.width, or.height,
 711:                   getAmountFull(insets, or.width, or.height), insets);
 712: 
 713:     g.setColor(saved);
 714:   }
 715: 
 716:   /**
 717:    * This method paints the string for the progressBar.
 718:    *
 719:    * @param g The Graphics object to paint with.
 720:    * @param x The x coordinate of the progressBar.
 721:    * @param y The y coordinate of the progressBar.
 722:    * @param width The width of the progressBar.
 723:    * @param height The height of the progressBar.
 724:    * @param amountFull The amount of the progressBar that has its bar filled.
 725:    * @param b The insets of the progressBar.
 726:    */
 727:   protected void paintString(Graphics g, int x, int y, int width, int height,
 728:                              int amountFull, Insets b)
 729:   {
 730:     String str = progressBar.getString();
 731:     int full = getAmountFull(b, width, height);
 732:     Point placement = getStringPlacement(g, progressBar.getString(),
 733:                                          x + b.left, y + b.top, 
 734:                                          width - b.left - b.right,
 735:                                          height - b.top - b.bottom);
 736:     Color savedColor = g.getColor();
 737:     Shape savedClip = g.getClip();
 738:     FontMetrics fm = g.getFontMetrics(progressBar.getFont());
 739:     
 740:     if (progressBar.getOrientation() == JProgressBar.VERTICAL)
 741:       {
 742:         AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2);
 743:         g.setFont(progressBar.getFont().deriveFont(rotate));
 744:       }
 745:     
 746:     g.setColor(getSelectionForeground());
 747:     g.setClip(0, 0, full + b.left, height);
 748:     g.drawString(str, placement.x, placement.y + fm.getAscent());
 749:     g.setColor(getSelectionBackground());
 750:     g.setClip(full + b.left, 0, width - full, height);
 751:     g.drawString(str, placement.x, placement.y + fm.getAscent());
 752:     g.setClip(savedClip);
 753:     g.setColor(savedColor);
 754:   }
 755: 
 756:   /**
 757:    * This method sets the current animation index. If the index is greater than
 758:    * the number of frames, it resets to 0.
 759:    * 
 760:    * @param newValue The new animation index.
 761:    */
 762:   protected void setAnimationIndex(int newValue)
 763:   {
 764:     animationIndex = (newValue <= numFrames) ? newValue : 0;
 765:     progressBar.repaint();
 766:   }
 767: 
 768:   /**
 769:    * This method sets the cell length.
 770:    *
 771:    * @param cellLen The cell length.
 772:    */
 773:   protected void setCellLength(int cellLen)
 774:   {
 775:     cellLength = cellLen;
 776:   }
 777: 
 778:   /**
 779:    * This method sets the cell spacing.
 780:    *
 781:    * @param cellSpace The cell spacing.
 782:    */
 783:   protected void setCellSpacing(int cellSpace)
 784:   {
 785:     cellSpacing = cellSpace;
 786:   }
 787: 
 788:   /**
 789:    * This method starts the animation timer. It is called
 790:    * when the propertyChangeListener detects that the progressBar
 791:    * has changed to indeterminate mode.
 792:    *
 793:    * @since 1.4
 794:    */
 795:   protected void startAnimationTimer()
 796:   {
 797:     if (animationTimer != null)
 798:       animationTimer.start();
 799:   }
 800: 
 801:   /**
 802:    * This method stops the animation timer. It is called when
 803:    * the propertyChangeListener detects that the progressBar
 804:    * has changed to determinate mode.
 805:    *
 806:    * @since 1.4
 807:    */
 808:   protected void stopAnimationTimer()
 809:   {
 810:     if (animationTimer != null)
 811:       animationTimer.stop();
 812:     setAnimationIndex(0);
 813:   }
 814: 
 815:   /**
 816:    * This method changes the settings for the progressBar to
 817:    * the defaults provided by the current Look and Feel.
 818:    */
 819:   protected void installDefaults()
 820:   {
 821:     LookAndFeel.installColorsAndFont(progressBar, "ProgressBar.background",
 822:                                      "ProgressBar.foreground",
 823:                                      "ProgressBar.font");
 824:     LookAndFeel.installBorder(progressBar, "ProgressBar.border");
 825:     progressBar.setOpaque(true);
 826: 
 827:     selectionForeground = UIManager.getColor("ProgressBar.selectionForeground");
 828:     selectionBackground = UIManager.getColor("ProgressBar.selectionBackground");
 829:     cellLength = UIManager.getInt("ProgressBar.cellLength");
 830:     cellSpacing = UIManager.getInt("ProgressBar.cellSpacing");
 831: 
 832:     int repaintInterval = UIManager.getInt("ProgressBar.repaintInterval");
 833:     int cycleTime = UIManager.getInt("ProgressBar.cycleTime");
 834: 
 835:     if (cycleTime % repaintInterval != 0
 836:         && (cycleTime / repaintInterval) % 2 != 0)
 837:       {
 838:     int div = (cycleTime / repaintInterval) + 2;
 839:     div /= 2;
 840:     div *= 2;
 841:     cycleTime = div * repaintInterval;
 842:       }
 843:     setAnimationIndex(0);
 844:     numFrames = cycleTime / repaintInterval;
 845:     animationTimer.setDelay(repaintInterval);
 846:   }
 847: 
 848:   /**
 849:    * The method uninstalls any defaults that were
 850:    * set by the current Look and Feel.
 851:    */
 852:   protected void uninstallDefaults()
 853:   {
 854:     progressBar.setFont(null);
 855:     progressBar.setForeground(null);
 856:     progressBar.setBackground(null);
 857: 
 858:     selectionForeground = null;
 859:     selectionBackground = null;
 860:   }
 861: 
 862:   /**
 863:    * This method registers listeners to all the 
 864:    * components that this UI delegate needs to listen to.
 865:    */
 866:   protected void installListeners()
 867:   {
 868:     changeListener = new ChangeHandler();
 869:     propertyListener = new PropertyChangeHandler();
 870:     animation = new Animator();
 871: 
 872:     progressBar.addChangeListener(changeListener);
 873:     progressBar.addPropertyChangeListener(propertyListener);
 874:     animationTimer.addActionListener(animation);
 875: 
 876:     ancestorListener = new AncestorHandler();
 877:     progressBar.addAncestorListener(ancestorListener);
 878: 
 879:     componentListener = new ComponentHandler();
 880:     progressBar.addComponentListener(componentListener);
 881:   }
 882: 
 883:   /**
 884:    * This method unregisters listeners to all the 
 885:    * components that were listened to.
 886:    */
 887:   protected void uninstallListeners()
 888:   {
 889:     progressBar.removeChangeListener(changeListener);
 890:     progressBar.removePropertyChangeListener(propertyListener);
 891:     animationTimer.removeActionListener(animation);
 892: 
 893:     changeListener = null;
 894:     propertyListener = null;
 895:     animation = null;
 896: 
 897:     if (ancestorListener != null)
 898:       progressBar.removeAncestorListener(ancestorListener);
 899:     ancestorListener = null;
 900: 
 901:     if (componentListener != null)
 902:       progressBar.removeComponentListener(componentListener);
 903:     componentListener = null;
 904:   }
 905: 
 906:   /**
 907:    * This method installs the UI for the given JComponent.
 908:    * This includes setting up defaults and listeners as
 909:    * well as initializing any values or objects that
 910:    * the UI may need.
 911:    *
 912:    * @param c The JComponent that is having this UI installed.
 913:    */
 914:   public void installUI(JComponent c)
 915:   {
 916:     super.installUI(c);
 917:     if (c instanceof JProgressBar)
 918:       {
 919:     progressBar = (JProgressBar) c;
 920: 
 921:     animationTimer = new Timer(200, null);
 922:     animationTimer.setRepeats(true);
 923: 
 924:     installDefaults();
 925:     installListeners();
 926:       }
 927:     if (progressBar.isIndeterminate())
 928:       startAnimationTimer();
 929:   }
 930: 
 931:   /**
 932:    * This method removes the UI for the given JComponent.
 933:    * This includes removing any listeners or defaults
 934:    * that the installUI may have set up.
 935:    *
 936:    * @param c The JComponent that is having this UI uninstalled.
 937:    */
 938:   public void uninstallUI(JComponent c)
 939:   {
 940:     super.uninstallUI(c);
 941:     uninstallListeners();
 942:     uninstallDefaults();
 943: 
 944:     animationTimer = null;
 945:     progressBar = null;
 946:   }
 947: 
 948: }