1 /* 2 * Copyright (c) 1997, 2006, 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 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 }