blob: 8fb15f9492d040366f4f6af584984ea8b4e627f0 [file] [log] [blame]
/*
* 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);
}
}