1 /* |
|
2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. 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. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package com.sun.java.swing.plaf.windows; |
|
27 |
|
28 import javax.swing.plaf.basic.*; |
|
29 import javax.swing.plaf.*; |
|
30 import javax.swing.*; |
|
31 import java.awt.*; |
|
32 |
|
33 import static com.sun.java.swing.plaf.windows.TMSchema.*; |
|
34 import 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 */ |
|
49 public 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 |
|
141 if (barRectWidth <= 0 || barRectHeight <= 0) { |
|
142 return; |
|
143 } |
|
144 |
|
145 Graphics2D g2 = (Graphics2D)g; |
|
146 g2.setStroke(new BasicStroke((float)(vertical ? barRectWidth : barRectHeight), |
|
147 BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); |
|
148 if (!vertical) { |
|
149 if (isLeftToRight) { |
|
150 g2.drawLine(2, barRectHeight / 2 + 1, |
|
151 amountFull - 2, barRectHeight / 2 + 1); |
|
152 } else { |
|
153 g2.drawLine(2 + barRectWidth, |
|
154 barRectHeight / 2 + 1, |
|
155 2 + barRectWidth - (amountFull - 2), |
|
156 barRectHeight / 2 + 1); |
|
157 } |
|
158 paintString(g, 0, 0, barRectWidth, barRectHeight, amountFull, null); |
|
159 } else { |
|
160 g2.drawLine(barRectWidth/2 + 1, barRectHeight + 1, |
|
161 barRectWidth/2 + 1, barRectHeight + 1 - amountFull + 2); |
|
162 paintString(g, 2, 2, barRectWidth, barRectHeight, amountFull, null); |
|
163 } |
|
164 |
|
165 } else { |
|
166 Skin skin = xp.getSkin(progressBar, vertical ? Part.PP_CHUNKVERT : Part.PP_CHUNK); |
|
167 int thickness; |
|
168 if (vertical) { |
|
169 thickness = barRectWidth - 5; |
|
170 } else { |
|
171 thickness = barRectHeight - 5; |
|
172 } |
|
173 |
|
174 int chunkSize = xp.getInt(progressBar, Part.PP_PROGRESS, null, Prop.PROGRESSCHUNKSIZE, 2); |
|
175 int spaceSize = xp.getInt(progressBar, Part.PP_PROGRESS, null, Prop.PROGRESSSPACESIZE, 0); |
|
176 int nChunks = (amountFull-4) / (chunkSize + spaceSize); |
|
177 |
|
178 // See if we can squeeze in an extra chunk without spacing after |
|
179 if (spaceSize > 0 && (nChunks * (chunkSize + spaceSize) + chunkSize) < (amountFull-4)) { |
|
180 nChunks++; |
|
181 } |
|
182 |
|
183 for (int i = 0; i < nChunks; i++) { |
|
184 if (vertical) { |
|
185 skin.paintSkin(g, |
|
186 3, barRectHeight - i * (chunkSize + spaceSize) - chunkSize - 2, |
|
187 thickness, chunkSize, null); |
|
188 } else { |
|
189 if (isLeftToRight) { |
|
190 skin.paintSkin(g, |
|
191 4 + i * (chunkSize + spaceSize), 2, |
|
192 chunkSize, thickness, null); |
|
193 } else { |
|
194 skin.paintSkin(g, |
|
195 barRectWidth - (2 + (i+1) * (chunkSize + spaceSize)), 2, |
|
196 chunkSize, thickness, null); |
|
197 } |
|
198 } |
|
199 } |
|
200 } |
|
201 } else { |
|
202 super.paintDeterminate(g, c); |
|
203 } |
|
204 } |
|
205 |
|
206 |
|
207 /** |
|
208 * {@inheritDoc} |
|
209 * @since 1.6 |
|
210 */ |
|
211 protected void setAnimationIndex(int newValue) { |
|
212 super.setAnimationIndex(newValue); |
|
213 XPStyle xp = XPStyle.getXP(); |
|
214 if (xp != null) { |
|
215 if (boxRect != null) { |
|
216 // get the full repaint area and add it the |
|
217 // previous one so we can erase it |
|
218 Rectangle chunk = getFullChunkBounds(boxRect); |
|
219 if (previousFullBox != null) { |
|
220 chunk.add(previousFullBox); |
|
221 } |
|
222 progressBar.repaint(chunk); |
|
223 } else { |
|
224 progressBar.repaint(); |
|
225 } |
|
226 } |
|
227 } |
|
228 |
|
229 |
|
230 /** |
|
231 * {@inheritDoc} |
|
232 * @since 1.6 |
|
233 */ |
|
234 protected int getBoxLength(int availableLength, int otherDimension) { |
|
235 XPStyle xp = XPStyle.getXP(); |
|
236 if (xp != null) { |
|
237 return 6; // an apparently hard coded value in Windows |
|
238 } |
|
239 return super.getBoxLength(availableLength, otherDimension); |
|
240 } |
|
241 |
|
242 /** |
|
243 * {@inheritDoc} |
|
244 * @since 1.6 |
|
245 */ |
|
246 protected Rectangle getBox(Rectangle r) { |
|
247 Rectangle rect = super.getBox(r); |
|
248 |
|
249 XPStyle xp = XPStyle.getXP(); |
|
250 if (xp != null) { |
|
251 boolean vertical = (progressBar.getOrientation() |
|
252 == JProgressBar.VERTICAL); |
|
253 Part part = vertical ? Part.PP_BARVERT : Part.PP_BAR; |
|
254 Insets ins = indeterminateInsets; |
|
255 |
|
256 int currentFrame = getAnimationIndex(); |
|
257 int framecount = getFrameCount()/2; |
|
258 |
|
259 int gap = xp.getInt(progressBar, Part.PP_PROGRESS, null, |
|
260 Prop.PROGRESSSPACESIZE, 0); |
|
261 currentFrame = currentFrame % framecount; |
|
262 |
|
263 // this code adjusts the chunk size to properly account for the |
|
264 // size and gap specified in the XP style. It also does it's own |
|
265 // box placement for the chunk animation. This is required because |
|
266 // the inherited algorithm from BasicProgressBarUI goes back and |
|
267 // forth whereas XP only goes in one direction. XP also has ghosted |
|
268 // trailing chunks to create the illusion of speed. This code |
|
269 // adjusts the pixel length of the animation to account for the |
|
270 // trails. |
|
271 if (!vertical) { |
|
272 rect.y = rect.y + ins.top; |
|
273 rect.height = progressBar.getHeight() - ins.top - ins.bottom; |
|
274 int len = progressBar.getWidth() - ins.left - ins.right; |
|
275 len += (rect.width+gap)*2; // add 2x for the trails |
|
276 double delta = (double)(len) / (double)framecount; |
|
277 rect.x = (int)(delta * currentFrame) + ins.left; |
|
278 } else { |
|
279 rect.x = rect.x + ins.left; |
|
280 rect.width = progressBar.getWidth() - ins.left - ins.right; |
|
281 int len = progressBar.getHeight() - ins.top - ins.bottom; |
|
282 len += (rect.height+gap)*2; // add 2x for the trails |
|
283 double delta = (double)(len) / (double)framecount; |
|
284 rect.y = (int)(delta * currentFrame) + ins.top; |
|
285 } |
|
286 } |
|
287 return rect; |
|
288 } |
|
289 |
|
290 |
|
291 protected void paintIndeterminate(Graphics g, JComponent c) { |
|
292 XPStyle xp = XPStyle.getXP(); |
|
293 if (xp != null) { |
|
294 boolean vertical = (progressBar.getOrientation() |
|
295 == JProgressBar.VERTICAL); |
|
296 int barRectWidth = progressBar.getWidth(); |
|
297 int barRectHeight = progressBar.getHeight(); |
|
298 paintXPBackground(g, vertical, barRectWidth, barRectHeight); |
|
299 |
|
300 // Paint the bouncing box. |
|
301 boxRect = getBox(boxRect); |
|
302 if (boxRect != null) { |
|
303 g.setColor(progressBar.getForeground()); |
|
304 if (!(g instanceof Graphics2D)) { |
|
305 return; |
|
306 } |
|
307 paintIndeterminateFrame(boxRect, (Graphics2D)g, vertical, |
|
308 barRectWidth, barRectHeight); |
|
309 if (progressBar.isStringPainted()) { |
|
310 if (!vertical) { |
|
311 paintString(g, -1, -1, barRectWidth, barRectHeight, 0, null); |
|
312 } else { |
|
313 paintString(g, 1, 1, barRectWidth, barRectHeight, 0, null); |
|
314 } |
|
315 } |
|
316 } |
|
317 } else { |
|
318 super.paintIndeterminate(g, c); |
|
319 } |
|
320 } |
|
321 |
|
322 private Rectangle getFullChunkBounds(Rectangle box) { |
|
323 boolean vertical = (progressBar.getOrientation() == JProgressBar.VERTICAL); |
|
324 XPStyle xp = XPStyle.getXP(); |
|
325 int gap = (xp != null) ? xp.getInt(progressBar, Part.PP_PROGRESS, |
|
326 null, Prop.PROGRESSSPACESIZE, 0) |
|
327 : 0; |
|
328 |
|
329 if (!vertical) { |
|
330 int chunksize = box.width+gap; |
|
331 return new Rectangle(box.x-chunksize*2, box.y, chunksize*3, box.height); |
|
332 } else { |
|
333 int chunksize = box.height+gap; |
|
334 return new Rectangle(box.x, box.y-chunksize*2, box.width, chunksize*3); |
|
335 } |
|
336 } |
|
337 |
|
338 private void paintIndeterminateFrame(Rectangle box, Graphics2D g, |
|
339 boolean vertical, |
|
340 int bgwidth, int bgheight) { |
|
341 XPStyle xp = XPStyle.getXP(); |
|
342 if (xp == null) { |
|
343 return; |
|
344 } |
|
345 |
|
346 // create a new graphics to keep drawing surface state |
|
347 Graphics2D gfx = (Graphics2D)g.create(); |
|
348 |
|
349 Part part = vertical ? Part.PP_BARVERT : Part.PP_BAR; |
|
350 Part chunk = vertical ? Part.PP_CHUNKVERT : Part.PP_CHUNK; |
|
351 |
|
352 // calculate the chunk offsets |
|
353 int gap = xp.getInt(progressBar, Part.PP_PROGRESS, null, |
|
354 Prop.PROGRESSSPACESIZE, 0); |
|
355 int deltax = 0; |
|
356 int deltay = 0; |
|
357 if (!vertical) { |
|
358 deltax = -box.width - gap; |
|
359 deltay = 0; |
|
360 } else { |
|
361 deltax = 0; |
|
362 deltay = -box.height - gap; |
|
363 } |
|
364 |
|
365 // Calculate the area of the chunks combined |
|
366 Rectangle fullBox = getFullChunkBounds(box); |
|
367 |
|
368 // save this box for the next time |
|
369 previousFullBox = fullBox; |
|
370 |
|
371 // this is the entire progress bar minus the track and borders |
|
372 Insets ins = indeterminateInsets; |
|
373 Rectangle progbarExtents = new Rectangle(ins.left, ins.top, |
|
374 bgwidth - ins.left - ins.right, |
|
375 bgheight - ins.top - ins.bottom); |
|
376 |
|
377 // only paint where the chunks overlap with the progress bar drawing area |
|
378 Rectangle repaintArea = progbarExtents.intersection(fullBox); |
|
379 |
|
380 // adjust the cliprect to chop the chunks when they go off the end |
|
381 gfx.clip(repaintArea); |
|
382 |
|
383 // get the skin |
|
384 XPStyle.Skin skin = xp.getSkin(progressBar, chunk); |
|
385 |
|
386 // do the drawing |
|
387 gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f)); |
|
388 skin.paintSkin(gfx, box.x, box.y, box.width, box.height, null); |
|
389 box.translate(deltax, deltay); |
|
390 gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); |
|
391 skin.paintSkin(gfx, box.x, box.y, box.width, box.height, null); |
|
392 box.translate(deltax, deltay); |
|
393 gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f)); |
|
394 skin.paintSkin(gfx, box.x, box.y, box.width, box.height, null); |
|
395 |
|
396 // get rid of our clip and composite changes |
|
397 gfx.dispose(); |
|
398 } |
|
399 |
|
400 private void paintXPBackground(Graphics g, boolean vertical, |
|
401 int barRectWidth, int barRectHeight) { |
|
402 XPStyle xp = XPStyle.getXP(); |
|
403 if (xp == null) { |
|
404 return; |
|
405 } |
|
406 Part part = vertical ? Part.PP_BARVERT : Part.PP_BAR; |
|
407 Skin skin = xp.getSkin(progressBar, part); |
|
408 |
|
409 // Paint background |
|
410 skin.paintSkin(g, 0, 0, barRectWidth, barRectHeight, null); |
|
411 } |
|
412 } |
|