001/* BasicProgressBarUI.java -- 002 Copyright (C) 2004, 2005 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package javax.swing.plaf.basic; 040 041import java.awt.Color; 042import java.awt.Dimension; 043import java.awt.Font; 044import java.awt.FontMetrics; 045import java.awt.Graphics; 046import java.awt.Insets; 047import java.awt.Point; 048import java.awt.Rectangle; 049import java.awt.Shape; 050import java.awt.event.ActionEvent; 051import java.awt.event.ActionListener; 052import java.awt.event.ComponentAdapter; 053import java.awt.event.ComponentEvent; 054import java.awt.event.ComponentListener; 055import java.awt.geom.AffineTransform; 056import java.beans.PropertyChangeEvent; 057import java.beans.PropertyChangeListener; 058 059import javax.swing.JComponent; 060import javax.swing.JProgressBar; 061import javax.swing.LookAndFeel; 062import javax.swing.SwingConstants; 063import javax.swing.SwingUtilities; 064import javax.swing.Timer; 065import javax.swing.UIManager; 066import javax.swing.event.AncestorEvent; 067import javax.swing.event.AncestorListener; 068import javax.swing.event.ChangeEvent; 069import javax.swing.event.ChangeListener; 070import javax.swing.plaf.ComponentUI; 071import javax.swing.plaf.ProgressBarUI; 072 073/** 074 * The Basic Look and Feel UI delegate for the 075 * JProgressBar. 076 */ 077public class BasicProgressBarUI extends ProgressBarUI 078{ 079 /** 080 * A helper class that listens for ChangeEvents 081 * from the progressBar's model. 082 * 083 * @specnote Apparently this class was intended to be protected, 084 * but was made public by a compiler bug and is now 085 * public for compatibility. 086 */ 087 public class ChangeHandler implements ChangeListener 088 { 089 /** 090 * Called every time the state of the model changes. 091 * 092 * @param e The ChangeEvent given by the model. 093 */ 094 public void stateChanged(ChangeEvent e) 095 { 096 // Nothing to do but repaint. 097 progressBar.repaint(); 098 } 099 } 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}