blob: 4284c3d72f4dcf4b890b2010c7b349f2c87c04c9 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.java.swing.plaf.windows;
27
28import javax.swing.plaf.basic.*;
29import javax.swing.plaf.*;
30import javax.swing.*;
31import java.awt.*;
32
33import static com.sun.java.swing.plaf.windows.TMSchema.*;
34import static com.sun.java.swing.plaf.windows.XPStyle.Skin;
35
36
37/**
38 * Windows rendition of the component.
39 * <p>
40 * <strong>Warning:</strong>
41 * Serialized objects of this class will not be compatible with
42 * future Swing releases. The current serialization support is appropriate
43 * for short term storage or RMI between applications running the same
44 * version of Swing. A future release of Swing will provide support for
45 * long term persistence.
46 *
47 * @author Michael C. Albers
48 */
49public class WindowsProgressBarUI extends BasicProgressBarUI
50{
51
52 private Rectangle previousFullBox;
53 private Insets indeterminateInsets;
54
55 public static ComponentUI createUI(JComponent x) {
56 return new WindowsProgressBarUI();
57 }
58
59
60 protected void installDefaults() {
61 super.installDefaults();
62
63 if (XPStyle.getXP() != null) {
64 LookAndFeel.installProperty(progressBar, "opaque", Boolean.FALSE);
65 progressBar.setBorder(null);
66 indeterminateInsets = UIManager.getInsets("ProgressBar.indeterminateInsets");
67 }
68 }
69
70 /**
71 * Returns the baseline.
72 *
73 * @throws NullPointerException {@inheritDoc}
74 * @throws IllegalArgumentException {@inheritDoc}
75 * @see javax.swing.JComponent#getBaseline(int, int)
76 * @since 1.6
77 */
78 public int getBaseline(JComponent c, int width, int height) {
79 int baseline = super.getBaseline(c, width, height);
80 if (XPStyle.getXP() != null && progressBar.isStringPainted() &&
81 progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
82 FontMetrics metrics = progressBar.
83 getFontMetrics(progressBar.getFont());
84 int y = progressBar.getInsets().top;
85 if (progressBar.isIndeterminate()) {
86 y = -1;
87 height--;
88 }
89 else {
90 y = 0;
91 height -= 3;
92 }
93 baseline = y + (height + metrics.getAscent() -
94 metrics.getLeading() -
95 metrics.getDescent()) / 2;
96 }
97 return baseline;
98 }
99
100 protected Dimension getPreferredInnerHorizontal() {
101 XPStyle xp = XPStyle.getXP();
102 if (xp != null) {
103 Skin skin = xp.getSkin(progressBar, Part.PP_BAR);
104 return new Dimension(
105 (int)super.getPreferredInnerHorizontal().getWidth(),
106 skin.getHeight());
107 }
108 return super.getPreferredInnerHorizontal();
109 }
110
111 protected Dimension getPreferredInnerVertical() {
112 XPStyle xp = XPStyle.getXP();
113 if (xp != null) {
114 Skin skin = xp.getSkin(progressBar, Part.PP_BARVERT);
115 return new Dimension(
116 skin.getWidth(),
117 (int)super.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.isLeftToRight(c);
127 int barRectWidth = progressBar.getWidth();
128 int barRectHeight = progressBar.getHeight()-1;
129 // amount of progress to draw
130 int amountFull = getAmountFull(null, barRectWidth, barRectHeight);
131
132 paintXPBackground(g, vertical, barRectWidth, barRectHeight);
133 // Paint progress
134 if (progressBar.isStringPainted()) {
135 // Do not paint the standard stripes from the skin, because they obscure
136 // the text
137 g.setColor(progressBar.getForeground());
138 barRectHeight -= 2;
139 barRectWidth -= 2;
140 Graphics2D g2 = (Graphics2D)g;
141 g2.setStroke(new BasicStroke((float)(vertical ? barRectWidth : barRectHeight),
142 BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
143 if (!vertical) {
144 if (isLeftToRight) {
145 g2.drawLine(2, barRectHeight / 2 + 1,
146 amountFull - 2, barRectHeight / 2 + 1);
147 } else {
148 g2.drawLine(2 + barRectWidth,
149 barRectHeight / 2 + 1,
150 2 + barRectWidth - (amountFull - 2),
151 barRectHeight / 2 + 1);
152 }
153 paintString(g, 0, 0, barRectWidth, barRectHeight, amountFull, null);
154 } else {
155 g2.drawLine(barRectWidth/2 + 1, barRectHeight + 1,
156 barRectWidth/2 + 1, barRectHeight + 1 - amountFull + 2);
157 paintString(g, 2, 2, barRectWidth, barRectHeight, amountFull, null);
158 }
159
160 } else {
161 Skin skin = xp.getSkin(progressBar, vertical ? Part.PP_CHUNKVERT : Part.PP_CHUNK);
162 int thickness;
163 if (vertical) {
164 thickness = barRectWidth - 5;
165 } else {
166 thickness = barRectHeight - 5;
167 }
168
169 int chunkSize = xp.getInt(progressBar, Part.PP_PROGRESS, null, Prop.PROGRESSCHUNKSIZE, 2);
170 int spaceSize = xp.getInt(progressBar, Part.PP_PROGRESS, null, Prop.PROGRESSSPACESIZE, 0);
171 int nChunks = (amountFull-4) / (chunkSize + spaceSize);
172
173 // See if we can squeeze in an extra chunk without spacing after
174 if (spaceSize > 0 && (nChunks * (chunkSize + spaceSize) + chunkSize) < (amountFull-4)) {
175 nChunks++;
176 }
177
178 for (int i = 0; i < nChunks; i++) {
179 if (vertical) {
180 skin.paintSkin(g,
181 3, barRectHeight - i * (chunkSize + spaceSize) - chunkSize - 2,
182 thickness, chunkSize, null);
183 } else {
184 if (isLeftToRight) {
185 skin.paintSkin(g,
186 4 + i * (chunkSize + spaceSize), 2,
187 chunkSize, thickness, null);
188 } else {
189 skin.paintSkin(g,
190 barRectWidth - (2 + (i+1) * (chunkSize + spaceSize)), 2,
191 chunkSize, thickness, null);
192 }
193 }
194 }
195 }
196 } else {
197 super.paintDeterminate(g, c);
198 }
199 }
200
201
202 /**
203 * {@inheritDoc}
204 * @since 1.6
205 */
206 protected void setAnimationIndex(int newValue) {
207 super.setAnimationIndex(newValue);
208 XPStyle xp = XPStyle.getXP();
209 if (xp != null) {
210 if (boxRect != null) {
211 // get the full repaint area and add it the
212 // previous one so we can erase it
213 Rectangle chunk = getFullChunkBounds(boxRect);
214 if (previousFullBox != null) {
215 chunk.add(previousFullBox);
216 }
217 progressBar.repaint(chunk);
218 } else {
219 progressBar.repaint();
220 }
221 }
222 }
223
224
225 /**
226 * {@inheritDoc}
227 * @since 1.6
228 */
229 protected int getBoxLength(int availableLength, int otherDimension) {
230 XPStyle xp = XPStyle.getXP();
231 if (xp != null) {
232 return 6; // an apparently hard coded value in Windows
233 }
234 return super.getBoxLength(availableLength, otherDimension);
235 }
236
237 /**
238 * {@inheritDoc}
239 * @since 1.6
240 */
241 protected Rectangle getBox(Rectangle r) {
242 Rectangle rect = super.getBox(r);
243
244 XPStyle xp = XPStyle.getXP();
245 if (xp != null) {
246 boolean vertical = (progressBar.getOrientation()
247 == JProgressBar.VERTICAL);
248 Part part = vertical ? Part.PP_BARVERT : Part.PP_BAR;
249 Insets ins = indeterminateInsets;
250
251 int currentFrame = getAnimationIndex();
252 int framecount = getFrameCount()/2;
253
254 int gap = xp.getInt(progressBar, Part.PP_PROGRESS, null,
255 Prop.PROGRESSSPACESIZE, 0);
256 currentFrame = currentFrame % framecount;
257
258 // this code adjusts the chunk size to properly account for the
259 // size and gap specified in the XP style. It also does it's own
260 // box placement for the chunk animation. This is required because
261 // the inherited algorithm from BasicProgressBarUI goes back and
262 // forth whereas XP only goes in one direction. XP also has ghosted
263 // trailing chunks to create the illusion of speed. This code
264 // adjusts the pixel length of the animation to account for the
265 // trails.
266 if (!vertical) {
267 rect.y = rect.y + ins.top;
268 rect.height = progressBar.getHeight() - ins.top - ins.bottom;
269 int len = progressBar.getWidth() - ins.left - ins.right;
270 len += (rect.width+gap)*2; // add 2x for the trails
271 double delta = (double)(len) / (double)framecount;
272 rect.x = (int)(delta * currentFrame) + ins.left;
273 } else {
274 rect.x = rect.x + ins.left;
275 rect.width = progressBar.getWidth() - ins.left - ins.right;
276 int len = progressBar.getHeight() - ins.top - ins.bottom;
277 len += (rect.height+gap)*2; // add 2x for the trails
278 double delta = (double)(len) / (double)framecount;
279 rect.y = (int)(delta * currentFrame) + ins.top;
280 }
281 }
282 return rect;
283 }
284
285
286 protected void paintIndeterminate(Graphics g, JComponent c) {
287 XPStyle xp = XPStyle.getXP();
288 if (xp != null) {
289 boolean vertical = (progressBar.getOrientation()
290 == JProgressBar.VERTICAL);
291 int barRectWidth = progressBar.getWidth();
292 int barRectHeight = progressBar.getHeight();
293 paintXPBackground(g, vertical, barRectWidth, barRectHeight);
294
295 // Paint the bouncing box.
296 boxRect = getBox(boxRect);
297 if (boxRect != null) {
298 g.setColor(progressBar.getForeground());
299 if (!(g instanceof Graphics2D)) {
300 return;
301 }
302 paintIndeterminateFrame(boxRect, (Graphics2D)g, vertical,
303 barRectWidth, barRectHeight);
304 if (progressBar.isStringPainted()) {
305 if (!vertical) {
306 paintString(g, -1, -1, barRectWidth, barRectHeight, 0, null);
307 } else {
308 paintString(g, 1, 1, barRectWidth, barRectHeight, 0, null);
309 }
310 }
311 }
312 } else {
313 super.paintIndeterminate(g, c);
314 }
315 }
316
317 private Rectangle getFullChunkBounds(Rectangle box) {
318 boolean vertical = (progressBar.getOrientation() == JProgressBar.VERTICAL);
319 XPStyle xp = XPStyle.getXP();
320 int gap = xp.getInt(progressBar, Part.PP_PROGRESS, null,
321 Prop.PROGRESSSPACESIZE, 0);
322
323 if (!vertical) {
324 int chunksize = box.width+gap;
325 return new Rectangle(box.x-chunksize*2, box.y, chunksize*3, box.height);
326 } else {
327 int chunksize = box.height+gap;
328 return new Rectangle(box.x, box.y-chunksize*2, box.width, chunksize*3);
329 }
330 }
331
332 private void paintIndeterminateFrame(Rectangle box, Graphics2D g,
333 boolean vertical,
334 int bgwidth, int bgheight) {
335 XPStyle xp = XPStyle.getXP();
336
337 // create a new graphics to keep drawing surface state
338 Graphics2D gfx = (Graphics2D)g.create();
339
340 Part part = vertical ? Part.PP_BARVERT : Part.PP_BAR;
341 Part chunk = vertical ? Part.PP_CHUNKVERT : Part.PP_CHUNK;
342
343 // calculate the chunk offsets
344 int gap = xp.getInt(progressBar, Part.PP_PROGRESS, null,
345 Prop.PROGRESSSPACESIZE, 0);
346 int deltax = 0;
347 int deltay = 0;
348 if (!vertical) {
349 deltax = -box.width - gap;
350 deltay = 0;
351 } else {
352 deltax = 0;
353 deltay = -box.height - gap;
354 }
355
356 // Calculate the area of the chunks combined
357 Rectangle fullBox = getFullChunkBounds(box);
358
359 // save this box for the next time
360 previousFullBox = fullBox;
361
362 // this is the entire progress bar minus the track and borders
363 Insets ins = indeterminateInsets;
364 Rectangle progbarExtents = new Rectangle(ins.left, ins.top,
365 bgwidth - ins.left - ins.right,
366 bgheight - ins.top - ins.bottom);
367
368 // only paint where the chunks overlap with the progress bar drawing area
369 Rectangle repaintArea = progbarExtents.intersection(fullBox);
370
371 // adjust the cliprect to chop the chunks when they go off the end
372 gfx.clip(repaintArea);
373
374 // get the skin
375 XPStyle.Skin skin = xp.getSkin(progressBar, chunk);
376
377 // do the drawing
378 gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f));
379 skin.paintSkin(gfx, box.x, box.y, box.width, box.height, null);
380 box.translate(deltax, deltay);
381 gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
382 skin.paintSkin(gfx, box.x, box.y, box.width, box.height, null);
383 box.translate(deltax, deltay);
384 gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f));
385 skin.paintSkin(gfx, box.x, box.y, box.width, box.height, null);
386
387 // get rid of our clip and composite changes
388 gfx.dispose();
389 }
390
391 private void paintXPBackground(Graphics g, boolean vertical,
392 int barRectWidth, int barRectHeight) {
393 XPStyle xp = XPStyle.getXP();
394 Part part = vertical ? Part.PP_BARVERT : Part.PP_BAR;
395 Skin skin = xp.getSkin(progressBar, part);
396
397 // Paint background
398 skin.paintSkin(g, 0, 0, barRectWidth, barRectHeight, null);
399 }
400}