001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Dennis Ushakov
019: * @version $Revision$
020: */package javax.swing.plaf.basic;
021:
022: import java.awt.Color;
023: import java.awt.Dimension;
024: import java.awt.Font;
025: import java.awt.FontMetrics;
026: import java.awt.Graphics;
027: import java.awt.Insets;
028: import java.awt.Point;
029: import java.awt.Rectangle;
030: import java.awt.event.ActionEvent;
031: import java.awt.event.ActionListener;
032: import java.awt.geom.AffineTransform;
033: import java.beans.PropertyChangeEvent;
034: import java.beans.PropertyChangeListener;
035:
036: import javax.swing.JComponent;
037: import javax.swing.JProgressBar;
038: import javax.swing.LookAndFeel;
039: import javax.swing.SwingUtilities;
040: import javax.swing.Timer;
041: import javax.swing.UIManager;
042: import javax.swing.event.ChangeEvent;
043: import javax.swing.event.ChangeListener;
044: import javax.swing.plaf.ComponentUI;
045: import javax.swing.plaf.ProgressBarUI;
046:
047: import org.apache.harmony.x.swing.StringConstants;
048: import org.apache.harmony.x.swing.Utilities;
049:
050: import org.apache.harmony.x.swing.internal.nls.Messages;
051:
052: public class BasicProgressBarUI extends ProgressBarUI {
053:
054: public class ChangeHandler implements ChangeListener {
055: public void stateChanged(final ChangeEvent event) {
056: progressBar.repaint();
057: }
058: }
059:
060: private class PropertyChangeHandler implements
061: PropertyChangeListener {
062: public void propertyChange(final PropertyChangeEvent event) {
063: String changedProperty = event.getPropertyName();
064:
065: if (StringConstants.PROGRESS_STRING_PAINTED_PROPERTY
066: .equals(changedProperty)) {
067: progressBar.revalidate();
068: }
069: if (StringConstants.ORIENTATION.equals(changedProperty)) {
070: updateRotatedFont(progressBar.getFont());
071: progressBar.revalidate();
072: }
073: if (StringConstants.FONT_PROPERTY_CHANGED
074: .equals(changedProperty)) {
075: updateRotatedFont((Font) event.getNewValue());
076: }
077: if (StringConstants.INDETERMINATE_PROPERTY
078: .equals(changedProperty)) {
079: if (progressBar.isIndeterminate()) {
080: setAnimationIndex(0);
081: startAnimationTimer();
082: } else {
083: stopAnimationTimer();
084: }
085: }
086: progressBar.repaint();
087: }
088: }
089:
090: protected JProgressBar progressBar;
091: protected ChangeListener changeListener;
092: protected Rectangle boxRect;
093:
094: private static final int NOTEXT_HEIGHT_ADDITION = 5;
095: private static final int MIN_WIDTH = 10;
096: private static final int STRING_PAINTED_CELL_LENGTH = 1;
097: private static final int STRING_PAINTED_CELL_SPACING = 0;
098:
099: private int cellLength;
100: private int cellSpacing;
101: private PropertyChangeListener propertyChangeListener;
102: private Color selectionBackground;
103: private Color selectionForeground;
104:
105: private int cycleTime;
106: private int repaintInterval;
107: private int animationIndex;
108: private int maxAnimationIndex;
109: private Timer animationTimer;
110:
111: private Dimension verticalSize;
112: private Dimension horizontalSize;
113: private AffineTransform rotateFont;
114: private Font rotatedFont;
115:
116: public static ComponentUI createUI(final JComponent c) {
117: return new BasicProgressBarUI();
118: }
119:
120: public void installUI(final JComponent c) {
121: progressBar = (JProgressBar) c;
122: installDefaults();
123: installListeners();
124: }
125:
126: public void uninstallUI(final JComponent c) {
127: uninstallDefaults();
128: uninstallListeners();
129: progressBar = null;
130: }
131:
132: public void paint(final Graphics g, final JComponent c) {
133: Color oldColor = g.getColor();
134:
135: if (progressBar.isIndeterminate()) {
136: paintIndeterminate(g, progressBar);
137: } else {
138: paintDeterminate(g, progressBar);
139: }
140:
141: if (progressBar.isStringPainted()) {
142: String paintString = getPaintedString();
143: Insets border = progressBar.getInsets();
144: Rectangle innerArea = SwingUtilities.calculateInnerArea(
145: progressBar, null);
146: int actualWidth = innerArea.width;
147: int actualHeight = innerArea.height;
148:
149: Point stringPosition = getStringPlacement(g, paintString,
150: border.left, border.top, actualWidth, actualHeight);
151: paintString(g, stringPosition.x, stringPosition.y,
152: actualWidth, actualHeight, getAmountFull(border,
153: actualWidth, actualHeight), border);
154: }
155: g.setColor(oldColor);
156: }
157:
158: public Dimension getPreferredSize(final JComponent c) {
159: return new Dimension(calculateWidth(true),
160: calculateHeight(true));
161: }
162:
163: public Dimension getMinimumSize(final JComponent c) {
164: return new Dimension(MIN_WIDTH, calculateHeight(true));
165: }
166:
167: public Dimension getMaximumSize(final JComponent c) {
168: return new Dimension(Short.MAX_VALUE, calculateHeight(true));
169: }
170:
171: protected void installDefaults() {
172: rotateFont = new AffineTransform();
173: rotateFont.rotate(Math.PI / 2);
174: LookAndFeel.installColorsAndFont(progressBar,
175: "ProgressBar.background", "ProgressBar.foreground",
176: "ProgressBar.font");
177: LookAndFeel.installBorder(progressBar, "ProgressBar.border");
178: LookAndFeel
179: .installProperty(progressBar, "opaque", Boolean.TRUE);
180: selectionBackground = UIManager
181: .getColor("ProgressBar.selectionBackground");
182: selectionForeground = UIManager
183: .getColor("ProgressBar.selectionForeground");
184:
185: cellLength = UIManager.getInt("ProgressBar.cellLength");
186: cellSpacing = UIManager.getInt("ProgressBar.cellSpacing");
187:
188: cycleTime = UIManager.getInt("ProgressBar.cycleTime");
189: repaintInterval = UIManager
190: .getInt("ProgressBar.repaintInterval");
191: maxAnimationIndex = cycleTime / repaintInterval;
192: animationTimer = new Timer(repaintInterval,
193: new ActionListener() {
194: public void actionPerformed(final ActionEvent e) {
195: incrementAnimationIndex();
196: progressBar.repaint();
197: }
198: });
199:
200: verticalSize = (Dimension) UIManager
201: .get("ProgressBar.verticalSize");
202: horizontalSize = (Dimension) UIManager
203: .get("ProgressBar.horizontalSize");
204: updateRotatedFont(progressBar.getFont());
205:
206: }
207:
208: protected void uninstallDefaults() {
209: Utilities.uninstallColorsAndFont(progressBar);
210: LookAndFeel.uninstallBorder(progressBar);
211: }
212:
213: protected void installListeners() {
214: changeListener = new ChangeHandler();
215: progressBar.addChangeListener(changeListener);
216: propertyChangeListener = new PropertyChangeHandler();
217: progressBar.addPropertyChangeListener(propertyChangeListener);
218: }
219:
220: protected void uninstallListeners() {
221: progressBar.removeChangeListener(changeListener);
222: progressBar
223: .removePropertyChangeListener(propertyChangeListener);
224: }
225:
226: protected void startAnimationTimer() {
227: if (animationTimer != null) {
228: animationTimer.start();
229: }
230: }
231:
232: protected void stopAnimationTimer() {
233: if (animationTimer != null) {
234: animationTimer.stop();
235: }
236: }
237:
238: protected Dimension getPreferredInnerHorizontal() {
239: if (progressBar == null) {
240: throw new NullPointerException();
241: }
242: return horizontalSize;
243: }
244:
245: protected Dimension getPreferredInnerVertical() {
246: if (progressBar == null) {
247: throw new NullPointerException();
248: }
249: return verticalSize;
250: }
251:
252: protected Color getSelectionForeground() {
253: return selectionForeground;
254: }
255:
256: protected Color getSelectionBackground() {
257: return selectionBackground;
258: }
259:
260: protected int getCellLength() {
261: return !progressBar.isStringPainted() ? cellLength
262: : STRING_PAINTED_CELL_LENGTH;
263: }
264:
265: protected void setCellLength(final int cellLen) {
266: cellLength = cellLen;
267: }
268:
269: protected int getCellSpacing() {
270: return !progressBar.isStringPainted() ? cellSpacing
271: : STRING_PAINTED_CELL_SPACING;
272: }
273:
274: protected void setCellSpacing(final int cellSpace) {
275: cellSpacing = cellSpace;
276: }
277:
278: protected int getAmountFull(final Insets b, final int width,
279: final int height) {
280: return isVertical() ? (int) (height * progressBar
281: .getPercentComplete()) : (int) (width * progressBar
282: .getPercentComplete());
283: }
284:
285: protected Rectangle getBox(final Rectangle r) {
286: boxRect = getFilledArea(r, 0);
287: return boxRect;
288: }
289:
290: protected int getBoxLength(final int length,
291: final int otherDimension) {
292: return length / 6;
293: }
294:
295: protected void paintIndeterminate(final Graphics g,
296: final JComponent c) {
297: Rectangle innerArea = SwingUtilities.calculateInnerArea(
298: progressBar, null);
299: Rectangle filledArea = getFilledArea(innerArea, 0);
300:
301: g.setColor(c.getForeground());
302: g.fillRect(filledArea.x, filledArea.y, filledArea.width,
303: filledArea.height);
304: }
305:
306: protected void paintDeterminate(final Graphics g, final JComponent c) {
307: Insets insets = progressBar.getInsets();
308: Rectangle innerArea = SwingUtilities.calculateInnerArea(
309: progressBar, null);
310: int actualWidth = innerArea.width;
311: int actualHeight = innerArea.height;
312:
313: g.setColor(progressBar.getForeground());
314: int amountFull = getAmountFull(insets, actualWidth,
315: actualHeight);
316: if (!isVertical()) {
317: if (getCellSpacing() == 0) {
318: g.fillRect(insets.left, insets.top, amountFull,
319: actualHeight);
320: } else {
321: g.clipRect(insets.left, insets.top, amountFull,
322: actualHeight);
323: for (int i = 0; i < amountFull; i += cellLength
324: + cellSpacing) {
325: g.fillRect(i, insets.top, cellLength, actualHeight);
326: }
327: }
328: } else {
329: if (getCellSpacing() == 0) {
330: g.fillRect(insets.left, insets.top - amountFull
331: + actualHeight, actualWidth, amountFull);
332: } else {
333: g.clipRect(insets.left, insets.top - amountFull
334: + actualHeight, actualWidth, amountFull);
335: for (int i = 0; i < amountFull; i += cellLength
336: + cellSpacing) {
337: g.fillRect(insets.left, insets.top - i
338: + actualHeight, actualWidth, cellLength);
339: }
340: }
341: }
342: }
343:
344: protected void paintString(final Graphics g, final int x,
345: final int y, final int width, final int height,
346: final int amountFull, final Insets insets) {
347:
348: Rectangle innerArea = SwingUtilities.calculateInnerArea(
349: progressBar, null);
350:
351: Rectangle filledArea;
352: if (progressBar.isIndeterminate()) {
353: filledArea = getBox(innerArea);
354: } else {
355: filledArea = getFilledArea(innerArea, amountFull);
356: }
357:
358: if (isVertical()) {
359: paintString(g, filledArea, x, y, width, height, amountFull,
360: insets, rotatedFont);
361: } else {
362: paintString(g, filledArea, x, y, width, height, amountFull,
363: insets, progressBar.getFont());
364: }
365: }
366:
367: protected Point getStringPlacement(final Graphics g,
368: final String progressString, final int x, final int y,
369: final int width, final int height) {
370: FontMetrics fm = Utilities.getFontMetrics(progressBar);
371: Dimension size = Utilities.getStringSize(progressString, fm);
372: size.height -= (fm.getAscent() - fm.getDescent());
373:
374: return isVertical() ? new Point(x + (width - size.height) / 2,
375: y + (height - size.width) / 2) : new Point(x
376: + (width - size.width) / 2, y + (height + size.height)
377: / 2);
378: }
379:
380: protected int getAnimationIndex() {
381: return animationIndex;
382: }
383:
384: protected void setAnimationIndex(final int newValue) {
385: if (progressBar == null) {
386: throw new NullPointerException(Messages.getString(
387: "swing.03", "progressBar")); //$NON-NLS-1$ //$NON-NLS-2$
388: }
389: animationIndex = newValue % maxAnimationIndex;
390: }
391:
392: protected void incrementAnimationIndex() {
393: setAnimationIndex(getAnimationIndex() + 1);
394: }
395:
396: private int calculateHeight(final boolean checkVertical) {
397: if (checkVertical && isVertical()) {
398: return calculateWidth(false);
399: }
400: Insets insets = progressBar.getInsets();
401: int height = insets.top + insets.bottom + horizontalSize.height;
402: if (progressBar.isStringPainted()) {
403: height -= NOTEXT_HEIGHT_ADDITION;
404: height += progressBar.getFontMetrics(progressBar.getFont())
405: .getHeight();
406: }
407: return height;
408: }
409:
410: private int calculateWidth(final boolean checkVertical) {
411: if (checkVertical && isVertical()) {
412: return calculateHeight(false);
413: }
414: Insets insets = progressBar.getInsets();
415: int width = insets.left
416: + insets.right
417: + Utilities.getStringSize(getPaintedString(),
418: progressBar.getFontMetrics(progressBar
419: .getFont())).width;
420: return Math.max(horizontalSize.width + insets.left
421: + insets.right, width);
422: }
423:
424: private String getPaintedString() {
425: String result = progressBar.getString();
426: return result != null ? result
427: : progressBar.isIndeterminate() ? null : Integer
428: .toString((int) (progressBar
429: .getPercentComplete() * 100))
430: + "%";
431: }
432:
433: private boolean isVertical() {
434: return progressBar.getOrientation() == JProgressBar.VERTICAL;
435: }
436:
437: private void updateRotatedFont(final Font font) {
438: if (font != null) {
439: rotatedFont = font.deriveFont(rotateFont);
440: }
441: }
442:
443: private void paintString(final Graphics g,
444: final Rectangle filledArea, final int x, final int y,
445: final int width, final int height, final int amountFull,
446: final Insets insets, final Font font) {
447:
448: final Rectangle oldClip = g.getClipBounds();
449: final String paintedString = getPaintedString();
450: final FontMetrics fm = progressBar.getFontMetrics(font);
451:
452: Utilities.drawString(g, paintedString, x, y, fm,
453: getSelectionBackground(), -1);
454:
455: g.clipRect(filledArea.x, filledArea.y, filledArea.width,
456: filledArea.height);
457: Utilities.drawString(g, paintedString, x, y, fm,
458: getSelectionForeground(), -1);
459: g.setClip(oldClip);
460: }
461:
462: private Rectangle getFilledArea(final Rectangle innerArea,
463: final int amountFull) {
464: Rectangle result = new Rectangle();
465: if (!progressBar.isIndeterminate()) {
466: result.x = innerArea.x;
467: if (isVertical()) {
468: result.y = innerArea.y + innerArea.height - amountFull;
469: result.width = innerArea.width;
470: result.height = amountFull;
471: } else {
472: result.y = innerArea.y;
473: result.width = amountFull;
474: result.height = innerArea.height;
475: }
476: } else {
477: if (isVertical()) {
478: result.x = innerArea.x;
479: result.y = innerArea.y
480: + calculatePosition(innerArea.height);
481: result.width = innerArea.width;
482: result.height = getBoxLength(innerArea.height,
483: innerArea.width);
484: } else {
485: result.x = innerArea.x
486: + calculatePosition(innerArea.width);
487: result.y = innerArea.y;
488: result.width = getBoxLength(innerArea.width,
489: innerArea.height);
490: result.height = innerArea.height;
491: }
492: }
493: return result;
494: }
495:
496: private int calculatePosition(final int length) {
497: int animationIndex = getAnimationIndex();
498: return (length - getBoxLength(length, 0))
499: * 2
500: * Math.min(animationIndex,
501: (maxAnimationIndex - animationIndex))
502: / maxAnimationIndex;
503: }
504: }
|