| /* |
| * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.java.swing.plaf.windows; |
| |
| import javax.swing.plaf.basic.*; |
| import javax.swing.plaf.*; |
| import javax.swing.*; |
| import java.awt.*; |
| |
| import static com.sun.java.swing.plaf.windows.TMSchema.*; |
| import static com.sun.java.swing.plaf.windows.XPStyle.Skin; |
| |
| |
| /** |
| * Windows rendition of the component. |
| * <p> |
| * <strong>Warning:</strong> |
| * Serialized objects of this class will not be compatible with |
| * future Swing releases. The current serialization support is appropriate |
| * for short term storage or RMI between applications running the same |
| * version of Swing. A future release of Swing will provide support for |
| * long term persistence. |
| * |
| * @author Michael C. Albers |
| */ |
| public class WindowsProgressBarUI extends BasicProgressBarUI |
| { |
| |
| private Rectangle previousFullBox; |
| private Insets indeterminateInsets; |
| |
| public static ComponentUI createUI(JComponent x) { |
| return new WindowsProgressBarUI(); |
| } |
| |
| |
| protected void installDefaults() { |
| super.installDefaults(); |
| |
| if (XPStyle.getXP() != null) { |
| LookAndFeel.installProperty(progressBar, "opaque", Boolean.FALSE); |
| progressBar.setBorder(null); |
| indeterminateInsets = UIManager.getInsets("ProgressBar.indeterminateInsets"); |
| } |
| } |
| |
| /** |
| * Returns the baseline. |
| * |
| * @throws NullPointerException {@inheritDoc} |
| * @throws IllegalArgumentException {@inheritDoc} |
| * @see javax.swing.JComponent#getBaseline(int, int) |
| * @since 1.6 |
| */ |
| public int getBaseline(JComponent c, int width, int height) { |
| int baseline = super.getBaseline(c, width, height); |
| if (XPStyle.getXP() != null && progressBar.isStringPainted() && |
| progressBar.getOrientation() == JProgressBar.HORIZONTAL) { |
| FontMetrics metrics = progressBar. |
| getFontMetrics(progressBar.getFont()); |
| int y = progressBar.getInsets().top; |
| if (progressBar.isIndeterminate()) { |
| y = -1; |
| height--; |
| } |
| else { |
| y = 0; |
| height -= 3; |
| } |
| baseline = y + (height + metrics.getAscent() - |
| metrics.getLeading() - |
| metrics.getDescent()) / 2; |
| } |
| return baseline; |
| } |
| |
| protected Dimension getPreferredInnerHorizontal() { |
| XPStyle xp = XPStyle.getXP(); |
| if (xp != null) { |
| Skin skin = xp.getSkin(progressBar, Part.PP_BAR); |
| return new Dimension( |
| (int)super.getPreferredInnerHorizontal().getWidth(), |
| skin.getHeight()); |
| } |
| return super.getPreferredInnerHorizontal(); |
| } |
| |
| protected Dimension getPreferredInnerVertical() { |
| XPStyle xp = XPStyle.getXP(); |
| if (xp != null) { |
| Skin skin = xp.getSkin(progressBar, Part.PP_BARVERT); |
| return new Dimension( |
| skin.getWidth(), |
| (int)super.getPreferredInnerVertical().getHeight()); |
| } |
| return super.getPreferredInnerVertical(); |
| } |
| |
| protected void paintDeterminate(Graphics g, JComponent c) { |
| XPStyle xp = XPStyle.getXP(); |
| if (xp != null) { |
| boolean vertical = (progressBar.getOrientation() == JProgressBar.VERTICAL); |
| boolean isLeftToRight = WindowsGraphicsUtils.isLeftToRight(c); |
| int barRectWidth = progressBar.getWidth(); |
| int barRectHeight = progressBar.getHeight()-1; |
| // amount of progress to draw |
| int amountFull = getAmountFull(null, barRectWidth, barRectHeight); |
| |
| paintXPBackground(g, vertical, barRectWidth, barRectHeight); |
| // Paint progress |
| if (progressBar.isStringPainted()) { |
| // Do not paint the standard stripes from the skin, because they obscure |
| // the text |
| g.setColor(progressBar.getForeground()); |
| barRectHeight -= 2; |
| barRectWidth -= 2; |
| Graphics2D g2 = (Graphics2D)g; |
| g2.setStroke(new BasicStroke((float)(vertical ? barRectWidth : barRectHeight), |
| BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); |
| if (!vertical) { |
| if (isLeftToRight) { |
| g2.drawLine(2, barRectHeight / 2 + 1, |
| amountFull - 2, barRectHeight / 2 + 1); |
| } else { |
| g2.drawLine(2 + barRectWidth, |
| barRectHeight / 2 + 1, |
| 2 + barRectWidth - (amountFull - 2), |
| barRectHeight / 2 + 1); |
| } |
| paintString(g, 0, 0, barRectWidth, barRectHeight, amountFull, null); |
| } else { |
| g2.drawLine(barRectWidth/2 + 1, barRectHeight + 1, |
| barRectWidth/2 + 1, barRectHeight + 1 - amountFull + 2); |
| paintString(g, 2, 2, barRectWidth, barRectHeight, amountFull, null); |
| } |
| |
| } else { |
| Skin skin = xp.getSkin(progressBar, vertical ? Part.PP_CHUNKVERT : Part.PP_CHUNK); |
| int thickness; |
| if (vertical) { |
| thickness = barRectWidth - 5; |
| } else { |
| thickness = barRectHeight - 5; |
| } |
| |
| int chunkSize = xp.getInt(progressBar, Part.PP_PROGRESS, null, Prop.PROGRESSCHUNKSIZE, 2); |
| int spaceSize = xp.getInt(progressBar, Part.PP_PROGRESS, null, Prop.PROGRESSSPACESIZE, 0); |
| int nChunks = (amountFull-4) / (chunkSize + spaceSize); |
| |
| // See if we can squeeze in an extra chunk without spacing after |
| if (spaceSize > 0 && (nChunks * (chunkSize + spaceSize) + chunkSize) < (amountFull-4)) { |
| nChunks++; |
| } |
| |
| for (int i = 0; i < nChunks; i++) { |
| if (vertical) { |
| skin.paintSkin(g, |
| 3, barRectHeight - i * (chunkSize + spaceSize) - chunkSize - 2, |
| thickness, chunkSize, null); |
| } else { |
| if (isLeftToRight) { |
| skin.paintSkin(g, |
| 4 + i * (chunkSize + spaceSize), 2, |
| chunkSize, thickness, null); |
| } else { |
| skin.paintSkin(g, |
| barRectWidth - (2 + (i+1) * (chunkSize + spaceSize)), 2, |
| chunkSize, thickness, null); |
| } |
| } |
| } |
| } |
| } else { |
| super.paintDeterminate(g, c); |
| } |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| * @since 1.6 |
| */ |
| protected void setAnimationIndex(int newValue) { |
| super.setAnimationIndex(newValue); |
| XPStyle xp = XPStyle.getXP(); |
| if (xp != null) { |
| if (boxRect != null) { |
| // get the full repaint area and add it the |
| // previous one so we can erase it |
| Rectangle chunk = getFullChunkBounds(boxRect); |
| if (previousFullBox != null) { |
| chunk.add(previousFullBox); |
| } |
| progressBar.repaint(chunk); |
| } else { |
| progressBar.repaint(); |
| } |
| } |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| * @since 1.6 |
| */ |
| protected int getBoxLength(int availableLength, int otherDimension) { |
| XPStyle xp = XPStyle.getXP(); |
| if (xp != null) { |
| return 6; // an apparently hard coded value in Windows |
| } |
| return super.getBoxLength(availableLength, otherDimension); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * @since 1.6 |
| */ |
| protected Rectangle getBox(Rectangle r) { |
| Rectangle rect = super.getBox(r); |
| |
| XPStyle xp = XPStyle.getXP(); |
| if (xp != null) { |
| boolean vertical = (progressBar.getOrientation() |
| == JProgressBar.VERTICAL); |
| Part part = vertical ? Part.PP_BARVERT : Part.PP_BAR; |
| Insets ins = indeterminateInsets; |
| |
| int currentFrame = getAnimationIndex(); |
| int framecount = getFrameCount()/2; |
| |
| int gap = xp.getInt(progressBar, Part.PP_PROGRESS, null, |
| Prop.PROGRESSSPACESIZE, 0); |
| currentFrame = currentFrame % framecount; |
| |
| // this code adjusts the chunk size to properly account for the |
| // size and gap specified in the XP style. It also does it's own |
| // box placement for the chunk animation. This is required because |
| // the inherited algorithm from BasicProgressBarUI goes back and |
| // forth whereas XP only goes in one direction. XP also has ghosted |
| // trailing chunks to create the illusion of speed. This code |
| // adjusts the pixel length of the animation to account for the |
| // trails. |
| if (!vertical) { |
| rect.y = rect.y + ins.top; |
| rect.height = progressBar.getHeight() - ins.top - ins.bottom; |
| int len = progressBar.getWidth() - ins.left - ins.right; |
| len += (rect.width+gap)*2; // add 2x for the trails |
| double delta = (double)(len) / (double)framecount; |
| rect.x = (int)(delta * currentFrame) + ins.left; |
| } else { |
| rect.x = rect.x + ins.left; |
| rect.width = progressBar.getWidth() - ins.left - ins.right; |
| int len = progressBar.getHeight() - ins.top - ins.bottom; |
| len += (rect.height+gap)*2; // add 2x for the trails |
| double delta = (double)(len) / (double)framecount; |
| rect.y = (int)(delta * currentFrame) + ins.top; |
| } |
| } |
| return rect; |
| } |
| |
| |
| protected void paintIndeterminate(Graphics g, JComponent c) { |
| XPStyle xp = XPStyle.getXP(); |
| if (xp != null) { |
| boolean vertical = (progressBar.getOrientation() |
| == JProgressBar.VERTICAL); |
| int barRectWidth = progressBar.getWidth(); |
| int barRectHeight = progressBar.getHeight(); |
| paintXPBackground(g, vertical, barRectWidth, barRectHeight); |
| |
| // Paint the bouncing box. |
| boxRect = getBox(boxRect); |
| if (boxRect != null) { |
| g.setColor(progressBar.getForeground()); |
| if (!(g instanceof Graphics2D)) { |
| return; |
| } |
| paintIndeterminateFrame(boxRect, (Graphics2D)g, vertical, |
| barRectWidth, barRectHeight); |
| if (progressBar.isStringPainted()) { |
| if (!vertical) { |
| paintString(g, -1, -1, barRectWidth, barRectHeight, 0, null); |
| } else { |
| paintString(g, 1, 1, barRectWidth, barRectHeight, 0, null); |
| } |
| } |
| } |
| } else { |
| super.paintIndeterminate(g, c); |
| } |
| } |
| |
| private Rectangle getFullChunkBounds(Rectangle box) { |
| boolean vertical = (progressBar.getOrientation() == JProgressBar.VERTICAL); |
| XPStyle xp = XPStyle.getXP(); |
| int gap = xp.getInt(progressBar, Part.PP_PROGRESS, null, |
| Prop.PROGRESSSPACESIZE, 0); |
| |
| if (!vertical) { |
| int chunksize = box.width+gap; |
| return new Rectangle(box.x-chunksize*2, box.y, chunksize*3, box.height); |
| } else { |
| int chunksize = box.height+gap; |
| return new Rectangle(box.x, box.y-chunksize*2, box.width, chunksize*3); |
| } |
| } |
| |
| private void paintIndeterminateFrame(Rectangle box, Graphics2D g, |
| boolean vertical, |
| int bgwidth, int bgheight) { |
| XPStyle xp = XPStyle.getXP(); |
| |
| // create a new graphics to keep drawing surface state |
| Graphics2D gfx = (Graphics2D)g.create(); |
| |
| Part part = vertical ? Part.PP_BARVERT : Part.PP_BAR; |
| Part chunk = vertical ? Part.PP_CHUNKVERT : Part.PP_CHUNK; |
| |
| // calculate the chunk offsets |
| int gap = xp.getInt(progressBar, Part.PP_PROGRESS, null, |
| Prop.PROGRESSSPACESIZE, 0); |
| int deltax = 0; |
| int deltay = 0; |
| if (!vertical) { |
| deltax = -box.width - gap; |
| deltay = 0; |
| } else { |
| deltax = 0; |
| deltay = -box.height - gap; |
| } |
| |
| // Calculate the area of the chunks combined |
| Rectangle fullBox = getFullChunkBounds(box); |
| |
| // save this box for the next time |
| previousFullBox = fullBox; |
| |
| // this is the entire progress bar minus the track and borders |
| Insets ins = indeterminateInsets; |
| Rectangle progbarExtents = new Rectangle(ins.left, ins.top, |
| bgwidth - ins.left - ins.right, |
| bgheight - ins.top - ins.bottom); |
| |
| // only paint where the chunks overlap with the progress bar drawing area |
| Rectangle repaintArea = progbarExtents.intersection(fullBox); |
| |
| // adjust the cliprect to chop the chunks when they go off the end |
| gfx.clip(repaintArea); |
| |
| // get the skin |
| XPStyle.Skin skin = xp.getSkin(progressBar, chunk); |
| |
| // do the drawing |
| gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f)); |
| skin.paintSkin(gfx, box.x, box.y, box.width, box.height, null); |
| box.translate(deltax, deltay); |
| gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); |
| skin.paintSkin(gfx, box.x, box.y, box.width, box.height, null); |
| box.translate(deltax, deltay); |
| gfx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f)); |
| skin.paintSkin(gfx, box.x, box.y, box.width, box.height, null); |
| |
| // get rid of our clip and composite changes |
| gfx.dispose(); |
| } |
| |
| private void paintXPBackground(Graphics g, boolean vertical, |
| int barRectWidth, int barRectHeight) { |
| XPStyle xp = XPStyle.getXP(); |
| Part part = vertical ? Part.PP_BARVERT : Part.PP_BAR; |
| Skin skin = xp.getSkin(progressBar, part); |
| |
| // Paint background |
| skin.paintSkin(g, 0, 0, barRectWidth, barRectHeight, null); |
| } |
| } |