001: /*
002: * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.java.swing.plaf.windows;
027:
028: import javax.swing.plaf.basic.*;
029: import javax.swing.plaf.*;
030: import javax.swing.*;
031: import java.awt.*;
032:
033: import static com.sun.java.swing.plaf.windows.TMSchema.*;
034: import static com.sun.java.swing.plaf.windows.XPStyle.Skin;
035:
036: /**
037: * Windows rendition of the component.
038: * <p>
039: * <strong>Warning:</strong>
040: * Serialized objects of this class will not be compatible with
041: * future Swing releases. The current serialization support is appropriate
042: * for short term storage or RMI between applications running the same
043: * version of Swing. A future release of Swing will provide support for
044: * long term persistence.
045: *
046: * @version 1.38 05/05/07
047: * @author Michael C. Albers
048: */
049: public class WindowsProgressBarUI extends BasicProgressBarUI {
050:
051: private Rectangle previousFullBox;
052: private Insets indeterminateInsets;
053:
054: public static ComponentUI createUI(JComponent x) {
055: return new WindowsProgressBarUI();
056: }
057:
058: protected void installDefaults() {
059: super .installDefaults();
060:
061: if (XPStyle.getXP() != null) {
062: LookAndFeel.installProperty(progressBar, "opaque",
063: Boolean.FALSE);
064: progressBar.setBorder(null);
065: indeterminateInsets = UIManager
066: .getInsets("ProgressBar.indeterminateInsets");
067: }
068: }
069:
070: /**
071: * Returns the baseline.
072: *
073: * @throws NullPointerException {@inheritDoc}
074: * @throws IllegalArgumentException {@inheritDoc}
075: * @see javax.swing.JComponent#getBaseline(int, int)
076: * @since 1.6
077: */
078: public int getBaseline(JComponent c, int width, int height) {
079: int baseline = super .getBaseline(c, width, height);
080: if (XPStyle.getXP() != null
081: && progressBar.isStringPainted()
082: && progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
083: FontMetrics metrics = progressBar
084: .getFontMetrics(progressBar.getFont());
085: int y = progressBar.getInsets().top;
086: if (progressBar.isIndeterminate()) {
087: y = -1;
088: height--;
089: } else {
090: y = 0;
091: height -= 3;
092: }
093: baseline = y
094: + (height + metrics.getAscent()
095: - metrics.getLeading() - metrics
096: .getDescent()) / 2;
097: }
098: return baseline;
099: }
100:
101: protected Dimension getPreferredInnerHorizontal() {
102: XPStyle xp = XPStyle.getXP();
103: if (xp != null) {
104: Skin skin = xp.getSkin(progressBar, Part.PP_BAR);
105: return new Dimension((int) super
106: .getPreferredInnerHorizontal().getWidth(), skin
107: .getHeight());
108: }
109: return super .getPreferredInnerHorizontal();
110: }
111:
112: protected Dimension getPreferredInnerVertical() {
113: XPStyle xp = XPStyle.getXP();
114: if (xp != null) {
115: Skin skin = xp.getSkin(progressBar, Part.PP_BARVERT);
116: return new Dimension(skin.getWidth(), (int) super
117: .getPreferredInnerVertical().getHeight());
118: }
119: return super .getPreferredInnerVertical();
120: }
121:
122: protected void paintDeterminate(Graphics g, JComponent c) {
123: XPStyle xp = XPStyle.getXP();
124: if (xp != null) {
125: boolean vertical = (progressBar.getOrientation() == JProgressBar.VERTICAL);
126: boolean isLeftToRight = WindowsGraphicsUtils
127: .isLeftToRight(c);
128: int barRectWidth = progressBar.getWidth();
129: int barRectHeight = progressBar.getHeight() - 1;
130: // amount of progress to draw
131: int amountFull = getAmountFull(null, barRectWidth,
132: barRectHeight);
133:
134: paintXPBackground(g, vertical, barRectWidth, barRectHeight);
135: // Paint progress
136: if (progressBar.isStringPainted()) {
137: // Do not paint the standard stripes from the skin, because they obscure
138: // the text
139: g.setColor(progressBar.getForeground());
140: barRectHeight -= 2;
141: barRectWidth -= 2;
142: Graphics2D g2 = (Graphics2D) g;
143: g2.setStroke(new BasicStroke(
144: (float) (vertical ? barRectWidth
145: : barRectHeight), BasicStroke.CAP_BUTT,
146: BasicStroke.JOIN_BEVEL));
147: if (!vertical) {
148: if (isLeftToRight) {
149: g2.drawLine(2, barRectHeight / 2 + 1,
150: amountFull - 2, barRectHeight / 2 + 1);
151: } else {
152: g2.drawLine(2 + barRectWidth,
153: barRectHeight / 2 + 1, 2 + barRectWidth
154: - (amountFull - 2),
155: barRectHeight / 2 + 1);
156: }
157: paintString(g, 0, 0, barRectWidth, barRectHeight,
158: amountFull, null);
159: } else {
160: g2.drawLine(barRectWidth / 2 + 1,
161: barRectHeight + 1, barRectWidth / 2 + 1,
162: barRectHeight + 1 - amountFull + 2);
163: paintString(g, 2, 2, barRectWidth, barRectHeight,
164: amountFull, null);
165: }
166:
167: } else {
168: Skin skin = xp.getSkin(progressBar,
169: vertical ? Part.PP_CHUNKVERT : Part.PP_CHUNK);
170: int thickness;
171: if (vertical) {
172: thickness = barRectWidth - 5;
173: } else {
174: thickness = barRectHeight - 5;
175: }
176:
177: int chunkSize = xp.getInt(progressBar,
178: Part.PP_PROGRESS, null, Prop.PROGRESSCHUNKSIZE,
179: 2);
180: int spaceSize = xp.getInt(progressBar,
181: Part.PP_PROGRESS, null, Prop.PROGRESSSPACESIZE,
182: 0);
183: int nChunks = (amountFull - 4)
184: / (chunkSize + spaceSize);
185:
186: // See if we can squeeze in an extra chunk without spacing after
187: if (spaceSize > 0
188: && (nChunks * (chunkSize + spaceSize) + chunkSize) < (amountFull - 4)) {
189: nChunks++;
190: }
191:
192: for (int i = 0; i < nChunks; i++) {
193: if (vertical) {
194: skin.paintSkin(g, 3, barRectHeight - i
195: * (chunkSize + spaceSize) - chunkSize
196: - 2, thickness, chunkSize, null);
197: } else {
198: if (isLeftToRight) {
199: skin.paintSkin(g, 4 + i
200: * (chunkSize + spaceSize), 2,
201: chunkSize, thickness, null);
202: } else {
203: skin.paintSkin(g, barRectWidth
204: - (2 + (i + 1)
205: * (chunkSize + spaceSize)),
206: 2, chunkSize, thickness, null);
207: }
208: }
209: }
210: }
211: } else {
212: super .paintDeterminate(g, c);
213: }
214: }
215:
216: /**
217: * {@inheritDoc}
218: * @since 1.6
219: */
220: protected void setAnimationIndex(int newValue) {
221: super .setAnimationIndex(newValue);
222: XPStyle xp = XPStyle.getXP();
223: if (xp != null) {
224: if (boxRect != null) {
225: // get the full repaint area and add it the
226: // previous one so we can erase it
227: Rectangle chunk = getFullChunkBounds(boxRect);
228: if (previousFullBox != null) {
229: chunk.add(previousFullBox);
230: }
231: progressBar.repaint(chunk);
232: } else {
233: progressBar.repaint();
234: }
235: }
236: }
237:
238: /**
239: * {@inheritDoc}
240: * @since 1.6
241: */
242: protected int getBoxLength(int availableLength, int otherDimension) {
243: XPStyle xp = XPStyle.getXP();
244: if (xp != null) {
245: return 6; // an apparently hard coded value in Windows
246: }
247: return super .getBoxLength(availableLength, otherDimension);
248: }
249:
250: /**
251: * {@inheritDoc}
252: * @since 1.6
253: */
254: protected Rectangle getBox(Rectangle r) {
255: Rectangle rect = super .getBox(r);
256:
257: XPStyle xp = XPStyle.getXP();
258: if (xp != null) {
259: boolean vertical = (progressBar.getOrientation() == JProgressBar.VERTICAL);
260: Part part = vertical ? Part.PP_BARVERT : Part.PP_BAR;
261: Insets ins = indeterminateInsets;
262:
263: int currentFrame = getAnimationIndex();
264: int framecount = getFrameCount() / 2;
265:
266: int gap = xp.getInt(progressBar, Part.PP_PROGRESS, null,
267: Prop.PROGRESSSPACESIZE, 0);
268: currentFrame = currentFrame % framecount;
269:
270: // this code adjusts the chunk size to properly account for the
271: // size and gap specified in the XP style. It also does it's own
272: // box placement for the chunk animation. This is required because
273: // the inherited algorithm from BasicProgressBarUI goes back and
274: // forth whereas XP only goes in one direction. XP also has ghosted
275: // trailing chunks to create the illusion of speed. This code
276: // adjusts the pixel length of the animation to account for the
277: // trails.
278: if (!vertical) {
279: rect.y = rect.y + ins.top;
280: rect.height = progressBar.getHeight() - ins.top
281: - ins.bottom;
282: int len = progressBar.getWidth() - ins.left - ins.right;
283: len += (rect.width + gap) * 2; // add 2x for the trails
284: double delta = (double) (len) / (double) framecount;
285: rect.x = (int) (delta * currentFrame) + ins.left;
286: } else {
287: rect.x = rect.x + ins.left;
288: rect.width = progressBar.getWidth() - ins.left
289: - ins.right;
290: int len = progressBar.getHeight() - ins.top
291: - ins.bottom;
292: len += (rect.height + gap) * 2; // add 2x for the trails
293: double delta = (double) (len) / (double) framecount;
294: rect.y = (int) (delta * currentFrame) + ins.top;
295: }
296: }
297: return rect;
298: }
299:
300: protected void paintIndeterminate(Graphics g, JComponent c) {
301: XPStyle xp = XPStyle.getXP();
302: if (xp != null) {
303: boolean vertical = (progressBar.getOrientation() == JProgressBar.VERTICAL);
304: int barRectWidth = progressBar.getWidth();
305: int barRectHeight = progressBar.getHeight();
306: paintXPBackground(g, vertical, barRectWidth, barRectHeight);
307:
308: // Paint the bouncing box.
309: boxRect = getBox(boxRect);
310: if (boxRect != null) {
311: g.setColor(progressBar.getForeground());
312: if (!(g instanceof Graphics2D)) {
313: return;
314: }
315: paintIndeterminateFrame(boxRect, (Graphics2D) g,
316: vertical, barRectWidth, barRectHeight);
317: if (progressBar.isStringPainted()) {
318: if (!vertical) {
319: paintString(g, -1, -1, barRectWidth,
320: barRectHeight, 0, null);
321: } else {
322: paintString(g, 1, 1, barRectWidth,
323: barRectHeight, 0, null);
324: }
325: }
326: }
327: } else {
328: super .paintIndeterminate(g, c);
329: }
330: }
331:
332: private Rectangle getFullChunkBounds(Rectangle box) {
333: boolean vertical = (progressBar.getOrientation() == JProgressBar.VERTICAL);
334: XPStyle xp = XPStyle.getXP();
335: int gap = xp.getInt(progressBar, Part.PP_PROGRESS, null,
336: Prop.PROGRESSSPACESIZE, 0);
337:
338: if (!vertical) {
339: int chunksize = box.width + gap;
340: return new Rectangle(box.x - chunksize * 2, box.y,
341: chunksize * 3, box.height);
342: } else {
343: int chunksize = box.height + gap;
344: return new Rectangle(box.x, box.y - chunksize * 2,
345: box.width, chunksize * 3);
346: }
347: }
348:
349: private void paintIndeterminateFrame(Rectangle box, Graphics2D g,
350: boolean vertical, int bgwidth, int bgheight) {
351: XPStyle xp = XPStyle.getXP();
352:
353: // create a new graphics to keep drawing surface state
354: Graphics2D gfx = (Graphics2D) g.create();
355:
356: Part part = vertical ? Part.PP_BARVERT : Part.PP_BAR;
357: Part chunk = vertical ? Part.PP_CHUNKVERT : Part.PP_CHUNK;
358:
359: // calculate the chunk offsets
360: int gap = xp.getInt(progressBar, Part.PP_PROGRESS, null,
361: Prop.PROGRESSSPACESIZE, 0);
362: int deltax = 0;
363: int deltay = 0;
364: if (!vertical) {
365: deltax = -box.width - gap;
366: deltay = 0;
367: } else {
368: deltax = 0;
369: deltay = -box.height - gap;
370: }
371:
372: // Calculate the area of the chunks combined
373: Rectangle fullBox = getFullChunkBounds(box);
374:
375: // save this box for the next time
376: previousFullBox = fullBox;
377:
378: // this is the entire progress bar minus the track and borders
379: Insets ins = indeterminateInsets;
380: Rectangle progbarExtents = new Rectangle(ins.left, ins.top,
381: bgwidth - ins.left - ins.right, bgheight - ins.top
382: - ins.bottom);
383:
384: // only paint where the chunks overlap with the progress bar drawing area
385: Rectangle repaintArea = progbarExtents.intersection(fullBox);
386:
387: // adjust the cliprect to chop the chunks when they go off the end
388: gfx.clip(repaintArea);
389:
390: // get the skin
391: XPStyle.Skin skin = xp.getSkin(progressBar, chunk);
392:
393: // do the drawing
394: gfx.setComposite(AlphaComposite.getInstance(
395: AlphaComposite.SRC_OVER, 0.8f));
396: skin.paintSkin(gfx, box.x, box.y, box.width, box.height, null);
397: box.translate(deltax, deltay);
398: gfx.setComposite(AlphaComposite.getInstance(
399: AlphaComposite.SRC_OVER, 0.5f));
400: skin.paintSkin(gfx, box.x, box.y, box.width, box.height, null);
401: box.translate(deltax, deltay);
402: gfx.setComposite(AlphaComposite.getInstance(
403: AlphaComposite.SRC_OVER, 0.2f));
404: skin.paintSkin(gfx, box.x, box.y, box.width, box.height, null);
405:
406: // get rid of our clip and composite changes
407: gfx.dispose();
408: }
409:
410: private void paintXPBackground(Graphics g, boolean vertical,
411: int barRectWidth, int barRectHeight) {
412: XPStyle xp = XPStyle.getXP();
413: Part part = vertical ? Part.PP_BARVERT : Part.PP_BAR;
414: Skin skin = xp.getSkin(progressBar, part);
415:
416: // Paint background
417: skin.paintSkin(g, 0, 0, barRectWidth, barRectHeight, null);
418: }
419: }
|