src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java
changeset 48271 95f173494fe9
parent 48270 f27aad5782da
child 48272 128de6a38f8e
equal deleted inserted replaced
48270:f27aad5782da 48271:95f173494fe9
     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 }