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 createUI(JComponent x)55 public static ComponentUI createUI(JComponent x) { 56 return new WindowsProgressBarUI(); 57 } 58 59 installDefaults()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 */ getBaseline(JComponent c, int width, int height)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 getPreferredInnerHorizontal()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 getPreferredInnerVertical()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 paintDeterminate(Graphics g, JComponent c)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 */ setAnimationIndex(int newValue)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 */ getBoxLength(int availableLength, int otherDimension)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 */ getBox(Rectangle r)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 paintIndeterminate(Graphics g, JComponent c)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 getFullChunkBounds(Rectangle box)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 paintIndeterminateFrame(Rectangle box, Graphics2D g, boolean vertical, int bgwidth, int bgheight)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 paintXPBackground(Graphics g, boolean vertical, int barRectWidth, int barRectHeight)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 } 413