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