diff options
Diffstat (limited to 'libjava/classpath/javax/swing/plaf/metal')
39 files changed, 18208 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/plaf/metal/DefaultMetalTheme.java b/libjava/classpath/javax/swing/plaf/metal/DefaultMetalTheme.java new file mode 100644 index 000000000..27c569f03 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/DefaultMetalTheme.java @@ -0,0 +1,305 @@ +/* DefaultMetalTheme.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import gnu.classpath.SystemProperties; + +import java.awt.Font; + +import javax.swing.UIManager; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.FontUIResource; + +/** + * The default theme for the {@link MetalLookAndFeel}. + * + * @see MetalLookAndFeel#setCurrentTheme(MetalTheme) + */ +public class DefaultMetalTheme extends MetalTheme +{ + private static final ColorUIResource PRIMARY1 = + new ColorUIResource(102, 102, 153); + private static final ColorUIResource PRIMARY2 = + new ColorUIResource(153, 153, 204); + private static final ColorUIResource PRIMARY3 = + new ColorUIResource(204, 204, 255); + private static final ColorUIResource SECONDARY1 = + new ColorUIResource(102, 102, 102); + private static final ColorUIResource SECONDARY2 = + new ColorUIResource(153, 153, 153); + private static final ColorUIResource SECONDARY3 = + new ColorUIResource(204, 204, 204); + + private static final FontUIResource SUB_TEXT_FONT = + new FontUIResource("Dialog", Font.PLAIN, 10); + private static final FontUIResource SYSTEM_TEXT_FONT = + new FontUIResource("Dialog", Font.PLAIN, 12); + private static final FontUIResource USER_TEXT_FONT = + new FontUIResource("Dialog", Font.PLAIN, 12); + private static final FontUIResource WINDOW_TITLE_FONT = + new FontUIResource("Dialog", Font.BOLD, 12); + + /** + * The control text font for swing.boldMetal=false. + */ + private static final FontUIResource PLAIN_CONTROL_TEXT_FONT = + new FontUIResource("Dialog", Font.PLAIN, 12); + + /** + * The standard control text font. + */ + private static final FontUIResource BOLD_CONTROL_TEXT_FONT = + new FontUIResource("Dialog", Font.BOLD, 12); + + /** + * The menu text font for swing.boldMetal=false. + */ + private static final FontUIResource PLAIN_MENU_TEXT_FONT = + new FontUIResource("Dialog", Font.PLAIN, 12); + + /** + * The menu control text font. + */ + private static final FontUIResource BOLD_MENU_TEXT_FONT = + new FontUIResource("Dialog", Font.BOLD, 12); + + /** + * Indicates the control text font. + */ + static final int CONTROL_TEXT_FONT = 1; + + /** + * Indicates the menu text font. + */ + static final int MENU_TEXT_FONT = 2; + + /** + * Creates a new instance of this theme. + */ + public DefaultMetalTheme() + { + // Do nothing here. + } + + /** + * Returns the name of the theme. + * + * @return <code>"Steel"</code>. + */ + public String getName() + { + return "Steel"; + } + + /** + * Returns the first primary color for this theme. + * + * @return The first primary color. + */ + protected ColorUIResource getPrimary1() + { + return PRIMARY1; + } + + /** + * Returns the second primary color for this theme. + * + * @return The second primary color. + */ + protected ColorUIResource getPrimary2() + { + return PRIMARY2; + } + + /** + * Returns the third primary color for this theme. + * + * @return The third primary color. + */ + protected ColorUIResource getPrimary3() + { + return PRIMARY3; + } + + /** + * Returns the first secondary color for this theme. + * + * @return The first secondary color. + */ + protected ColorUIResource getSecondary1() + { + return SECONDARY1; + } + + /** + * Returns the second secondary color for this theme. + * + * @return The second secondary color. + */ + protected ColorUIResource getSecondary2() + { + return SECONDARY2; + } + + /** + * Returns the third secondary color for this theme. + * + * @return The third secondary color. + */ + protected ColorUIResource getSecondary3() + { + return SECONDARY3; + } + + /** + * Returns the font used for text on controls. In this case, the font is + * <code>FontUIResource("Dialog", Font.BOLD, 12)</code>, unless the + * <code>swing.boldMetal</code> UI default is set to {@link Boolean#FALSE} + * in which case it is <code>FontUIResource("Dialog", Font.PLAIN, 12)</code>. + * + * @return The font. + */ + public FontUIResource getControlTextFont() + { + return getFont(CONTROL_TEXT_FONT); + } + + /** + * Returns the font used for text in menus. In this case, the font is + * <code>FontUIResource("Dialog", Font.BOLD, 12)</code>, unless the + * <code>swing.boldMetal</code> UI default is set to {@link Boolean#FALSE} + * in which case it is <code>FontUIResource("Dialog", Font.PLAIN, 12)</code>. + * + * @return The font used for text in menus. + */ + public FontUIResource getMenuTextFont() + { + return getFont(MENU_TEXT_FONT); + } + + /** + * Returns the font used for sub text. In this case, the font is + * <code>FontUIResource("Dialog", Font.PLAIN, 10)</code>. + * + * @return The font used for sub text. + */ + public FontUIResource getSubTextFont() + { + return SUB_TEXT_FONT; + } + + /** + * Returns the font used for system text. In this case, the font is + * <code>FontUIResource("Dialog", Font.PLAIN, 12)</code>. + * + * @return The font used for system text. + */ + public FontUIResource getSystemTextFont() + { + return SYSTEM_TEXT_FONT; + } + + /** + * Returns the font used for user text. In this case, the font is + * <code>FontUIResource("Dialog", Font.PLAIN, 12)</code>. + * + * @return The font used for user text. + */ + public FontUIResource getUserTextFont() + { + return USER_TEXT_FONT; + } + + /** + * Returns the font used for window titles. In this case, the font is + * <code>FontUIResource("Dialog", Font.BOLD, 12)</code>. + * + * @return The font used for window titles. + */ + public FontUIResource getWindowTitleFont() + { + return WINDOW_TITLE_FONT; + } + + /** + * Returns the appropriate font. The font type to return is identified + * by the specified id. + * + * @param id the font type to return + * + * @return the correct font + */ + private FontUIResource getFont(int id) + { + FontUIResource font = null; + switch (id) + { + case CONTROL_TEXT_FONT: + if (isBoldMetal()) + font = BOLD_CONTROL_TEXT_FONT; + else + font = PLAIN_CONTROL_TEXT_FONT; + break; + case MENU_TEXT_FONT: + if (isBoldMetal()) + font = BOLD_MENU_TEXT_FONT; + else + font = PLAIN_MENU_TEXT_FONT; + break; + // TODO: Add other font types and their mapping here. + } + return font; + } + + /** + * Determines if the theme should be bold or not. The theme is bold by + * default, this can be turned off by setting the system property + * swing.boldMetal to true, or by putting the property with the same name + * into the current UIManager's defaults. + * + * @return <code>true</code>, when the theme is bold, <code>false</code> + * otherwise + */ + private boolean isBoldMetal() + { + Object boldMetal = UIManager.get("swing.boldMetal"); + return (boldMetal == null || ! Boolean.FALSE.equals(boldMetal)) + && ! ("false".equals(SystemProperties.getProperty("swing.boldMetal"))); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java b/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java new file mode 100644 index 000000000..253629998 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java @@ -0,0 +1,1626 @@ +/* MetalBorders.java + Copyright (C) 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JButton; +import javax.swing.JInternalFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicBorders; +import javax.swing.text.JTextComponent; + + +/** + * A factory class that creates borders for the different Swing components. + * + * @author Roman Kennke (roman@kennke.org) + */ +public class MetalBorders +{ + + /** The shared instance for getButtonBorder(). */ + private static Border buttonBorder; + + /** The shared instance for getToggleButtonBorder(). */ + private static Border toggleButtonBorder; + + /** The shared instance for getDesktopIconBorder(). */ + private static Border desktopIconBorder; + + /** The shared instance for getRolloverButtonBorder(). */ + private static Border toolbarButtonBorder; + + /** The shared instance for getTextFieldBorder(). */ + private static Border textFieldBorder; + + /** The shared instance for getTextBorder(). */ + private static Border textBorder; + + /** The shared instance for getRolloverBorder(). */ + private static Border rolloverBorder; + + /** + * A MarginBorder that gets shared by multiple components. + * Created on demand by the private helper function {@link + * #getMarginBorder()}. + */ + private static BasicBorders.MarginBorder marginBorder; + + /** + * <p>A border used for {@link JButton} components.</p> + * + * <p>This {@link Border} implementation can handle only instances of + * {@link AbstractButton} and their subclasses.</p> + * + * <p>If the Metal Look and Feel's current theme is 'Ocean' the border + * will be painted with a special highlight when the mouse cursor if + * over the button (ie. the property <code>rollover</code> of the + * button's model is <code>true</code>) and is not a <b>direct</b> + * child of a {@link JToolBar}.</p> + */ + public static class ButtonBorder extends AbstractBorder implements UIResource + { + /** The borders insets. */ + protected static Insets borderInsets = new Insets(3, 3, 3, 3); + + /** + * Creates a new instance of <code>ButtonBorder</code>. + */ + public ButtonBorder() + { + // Nothing to do here. + } + + /** + * Paints the button border. + * + * @param c the component for which we paint the border + * @param g the Graphics context to use + * @param x the X coordinate of the upper left corner of c + * @param y the Y coordinate of the upper left corner of c + * @param w the width of c + * @param h the height of c + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + // With the OceanTheme the button border is painted entirely different. + // However, I couldn't figure out how this is determined besides checking + // for instanceof OceanTheme. The button painting is definitely not + // influenced by a UI default property and it is definitely performed + // by the same Border class. + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme) + paintOceanButtonBorder(c, g, x, y, w, h); + else + paintDefaultButtonBorder(c, g, x, y, w, h); + } + + /** + * Paints the button border for the DefaultMetalTheme. + * + * @param c the component (button) + * @param g the graphics object to use + * @param x the upper left corner of the component, X coordinate + * @param y the upper left corner of the component, Y coordinate + * @param w the width of the component + * @param h the height of the component + */ + private void paintDefaultButtonBorder(Component c, Graphics g, int x, + int y, int w, int h) + { + ButtonModel bmodel = null; + + // The RI will fail with a ClassCastException in such a situation. + // This code tries to be more helpful. + if (c instanceof AbstractButton) + bmodel = ((AbstractButton) c).getModel(); + else + throw new IllegalStateException("A ButtonBorder is supposed to work " + + "only with AbstractButton and" + + "subclasses."); + + Color darkShadow = MetalLookAndFeel.getControlDarkShadow(); + Color shadow = MetalLookAndFeel.getControlShadow(); + Color light = MetalLookAndFeel.getControlHighlight(); + Color middle = MetalLookAndFeel.getControl(); + + if (c.isEnabled()) + { + // draw dark border + g.setColor(darkShadow); + g.drawRect(x, y, w - 2, h - 2); + + // If the button is the default button, we paint a special border, + // regardless of the pressed state. + if (c instanceof JButton && ((JButton) c).isDefaultButton()) + { + g.drawRect(x + 1, y + 1, w - 4, h - 4); + // Draw white highlight. + g.setColor(light); + g.drawLine(x + 2, y + 2, x + w - 4, y + 2); + g.drawLine(x + 2, y + 2, x + 2, y + h - 4); + g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1); + g.drawLine(x + w - 1, y + 2, x + w - 1, y + h - 1); + // Draw crossing pixels. + g.setColor(middle); + g.fillRect(x + w - 2, y + 2, 1, 1); + g.fillRect(x + 2, y + h - 2, 1, 1); + } + else + { + // The normal border. This is used when the button is not + // pressed or the button is not armed. + if (! (bmodel.isPressed() && bmodel.isArmed())) + { + // draw light border + g.setColor(light); + g.drawRect(x + 1, y + 1, w - 2, h - 2); + + // draw crossing pixels of both borders + g.setColor(middle); + g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); + g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1); + } + // The pressed border. This border is painted only when + // the button is both pressed and armed. + else + { + // draw light border + g.setColor(light); + g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1); + g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1); + + // draw shadow border + g.setColor(middle); + g.drawLine(x + 1, y + 1, x + w - 2, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + h - 2); + + // draw crossing pixels of both borders + g.setColor(shadow); + g.drawRect(x + 1, y + h - 2, 0, 0); + g.drawRect(x + w - 2, y + 1, 0, 0); + } + } + } + else + { + // draw disabled border + g.setColor(MetalLookAndFeel.getInactiveControlTextColor()); + g.drawRect(x, y, w - 2, h - 2); + } + } + + /** + * Paints the button border for the OceanTheme. + * + * @param c the button + * @param g the graphics context + * @param x the X coordinate of the upper left corner of the painting rect + * @param y the Y coordinate of the upper left corner of the painting rect + * @param w the width of the painting rect + * @param h the height of the painting rect + */ + private void paintOceanButtonBorder(Component c, Graphics g, int x, + int y, int w, int h) + { + ButtonModel bmodel = null; + + // The RI will fail with a ClassCastException in such a situation. + // This code tries to be more helpful. + if (c instanceof AbstractButton) + bmodel = ((AbstractButton) c).getModel(); + else + throw new IllegalStateException("A ButtonBorder is supposed to work " + + "only with AbstractButton and" + + "subclasses."); + + Color darkShadow = MetalLookAndFeel.getControlDarkShadow(); + Color shadow = MetalLookAndFeel.getControlShadow(); + Color light = MetalLookAndFeel.getControlHighlight(); + Color middle = MetalLookAndFeel.getControl(); + + if (c.isEnabled()) + { + // Paint the pressed border if the button is pressed, or if + // the button is the default button. In the OceanTheme, the default + // button has the same border as a pressed button. + if (bmodel.isPressed() || ((c instanceof JButton) + && ((JButton) c).isDefaultButton())) + { + // Draw fat border. + g.setColor(darkShadow); + g.drawRect(x, y, w - 1, h - 1); + g.drawRect(x + 1, y + 1, w - 3, h - 3); + } + else if (bmodel.isRollover() && !(c.getParent() instanceof JToolBar)) + { + // Paint a bigger border when the mouse is over the button but + // only if it is *not* part of a JToolBar. + g.setColor(shadow); + g.drawRect(x, y, w - 1, h - 1); + g.drawRect(x + 2, y + 2, w - 5, h - 5); + g.setColor(darkShadow); + g.drawRect(x + 1, y + 1, w - 3, h - 3); + } + else + { + g.setColor(darkShadow); + g.drawRect(x, y, w - 1, h - 1); + } + } + else + { + // draw disabled border + g.setColor(MetalLookAndFeel.getInactiveControlTextColor()); + g.drawRect(x, y, w - 2, h - 2); + } + } + + /** + * Returns the insets of the <code>ButtonBorder</code>. + * + * @param c the component for which the border is used (ignored). + * + * @return The insets of the <code>ButtonBorder</code>. + */ + public Insets getBorderInsets(Component c) + { + return borderInsets; + } + + /** + * Returns the insets of the <code>ButtonBorder</code> in the specified + * <code>newInsets</code> object. + * + * @param c the component for which the border is used (ignored). + * @param newInsets the insets object where to put the values ( + * <code>null</code> not permitted). + * + * @return The <code>newInsets</code> reference. + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + newInsets.bottom = borderInsets.bottom; + newInsets.left = borderInsets.left; + newInsets.right = borderInsets.right; + newInsets.top = borderInsets.top; + return newInsets; + } + } + + /** + * A border used when painting {@link JInternalFrame} instances. + */ + static class DesktopIconBorder extends AbstractBorder + implements UIResource + { + /** + * Creates a new border instance. + */ + public DesktopIconBorder() + { + // Nothing to do here. + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * + * @return The border insets. + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * @return The border insets. + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + if (newInsets == null) + newInsets = new Insets(3, 3, 2, 3); + else + { + newInsets.top = 3; + newInsets.left = 3; + newInsets.bottom = 2; + newInsets.right = 3; + } + return newInsets; + } + + /** + * Paints the border for the specified component. + * + * @param c the component. + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawRect(x, y, w - 1, h - 1); + } + + } + + /** + * A simple 3D border. + */ + public static class Flush3DBorder extends AbstractBorder + implements UIResource + { + private static final Insets borderInsets = new Insets(2, 2, 2, 2); + + /** + * Creates a new border instance. + */ + public Flush3DBorder() + { + // Nothing to do here. + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * + * @return The border insets. + */ + public Insets getBorderInsets(Component c) + { + return borderInsets; + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * @param newInsets an existing insets instance, that will be populated + * with the border insets and returned as the result + * (<code>null</code> not permitted). + * + * @return The <code>newInsets</code> reference. + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + newInsets.top = borderInsets.top; + newInsets.left = borderInsets.left; + newInsets.bottom = borderInsets.bottom; + newInsets.right = borderInsets.right; + return newInsets; + } + + /** + * Paints the border for the specified component. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + Color savedColor = g.getColor(); + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawRect(x, y, w - 2, h - 2); + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawRect(x + 1, y + 1, w - 2, h - 2); + g.setColor(MetalLookAndFeel.getControl()); + g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); + g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1); + g.setColor(savedColor); + } + + } + + /** + * A border used for a {@link JInternalFrame} when it is being used as a + * palette. + * + * @since 1.3 + */ + public static class PaletteBorder extends AbstractBorder + implements UIResource + { + private static final Insets borderInsets = new Insets(1, 1, 1, 1); + + /** + * Creates a new <code>PaletteBorder</code>. + */ + public PaletteBorder() + { + // Nothing to do here. + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * + * @return The border insets. + */ + public Insets getBorderInsets(Component c) + { + return borderInsets; + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * @param newInsets an existing insets instance, that will be populated + * with the border insets and returned as the result + * (<code>null</code> not permitted). + * + * @return The <code>newInsets</code> reference. + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + newInsets.top = borderInsets.top; + newInsets.left = borderInsets.left; + newInsets.bottom = borderInsets.bottom; + newInsets.right = borderInsets.right; + return newInsets; + } + + /** + * Paints the border for the specified component. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + Color savedColor = g.getColor(); + + // draw the outline + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + g.drawRect(x, y, w - 1, h - 1); + + // put a dot in each corner + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(x, y, 1, 1); + g.fillRect(x + w - 1, y, 1, 1); + g.fillRect(x + w - 1, y + h - 1, 1, 1); + g.fillRect(x, y + h - 1, 1, 1); + g.setColor(savedColor); + } + + } + + /** + * A border used for the {@link JTextField} component. + */ + public static class TextFieldBorder extends Flush3DBorder + implements UIResource + { + /** + * Creates a new border instance. + */ + public TextFieldBorder() + { + // Nothing to do here. + } + + /** + * Paints the border for the specified component. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + boolean enabledTextBorder; + if (c instanceof JTextComponent) + { + JTextComponent tc = (JTextComponent) c; + enabledTextBorder = tc.isEnabled() && tc.isEditable(); + } + else + enabledTextBorder = false; + + if (enabledTextBorder) + super.paintBorder(c, g, x, y, w, h); + else + { + Color savedColor = g.getColor(); + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawRect(x, y, w - 1, h - 1); + g.setColor(savedColor); + } + } + + } + + /** + * A border used for the {@link JInternalFrame} component. + */ + public static class InternalFrameBorder extends AbstractBorder + implements UIResource + { + private static final Insets borderInsets = new Insets(5, 5, 5, 5); + + /** + * Creates a new border instance. + */ + public InternalFrameBorder() + { + // Nothing to do here. + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * + * @return The border insets. + */ + public Insets getBorderInsets(Component c) + { + return borderInsets; + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * @param newInsets an existing insets instance, that will be populated + * with the border insets and returned as the result + * (<code>null</code> not permitted). + * + * @return The <code>newInsets</code> reference. + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + newInsets.top = borderInsets.top; + newInsets.left = borderInsets.left; + newInsets.bottom = borderInsets.bottom; + newInsets.right = borderInsets.right; + return newInsets; + } + + /** + * Paints the border for the specified component. + * + * @param c the component. + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + + JInternalFrame f = (JInternalFrame) c; + if (f.isSelected()) + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // fill the border background + g.fillRect(x, y, w, 5); + g.fillRect(x, y, 5, h); + g.fillRect(x + w - 5, y, 5, h); + g.fillRect(x, y + h - 5, w, 5); + + // draw a dot in each corner + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(x, y, 1, 1); + g.fillRect(x + w - 1, y, 1, 1); + g.fillRect(x + w - 1, y + h - 1, 1, 1); + g.fillRect(x, y + h - 1, 1, 1); + + // draw the lines + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 14, y + 2, x + w - 15, y + 2); + g.drawLine(x + 14, y + h - 3, x + w - 15, y + h - 3); + g.drawLine(x + 2, y + 14, x + 2, y + h - 15); + g.drawLine(x + w - 3, y + 14, x + w - 3, y + h - 15); + + // draw the line highlights + if (f.isSelected()) + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x + 15, y + 3, x + w - 14, y + 3); + g.drawLine(x + 15, y + h - 2, x + w - 14, y + h - 2); + g.drawLine(x + 3, y + 15, x + 3, y + h - 14); + g.drawLine(x + w - 2, y + 15, x + w - 2, y + h - 14); + } + + } + + /** + * A border used for {@link JInternalFrame} components that are + * presented as dialogs (by the {@link JOptionPane} class). + */ + public static class OptionDialogBorder extends AbstractBorder + implements UIResource + { + + /** + * Creates a new border instance. + */ + public OptionDialogBorder() + { + // Nothing to do here. + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * + * @return The border insets. + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * @return The border insets. + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + if (newInsets == null) + newInsets = new Insets(3, 3, 3, 3); + else + { + newInsets.top = 3; + newInsets.left = 3; + newInsets.bottom = 3; + newInsets.right = 3; + } + return newInsets; + } + + /** + * Paints the border for the specified component. + * + * @param c the component. + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + + JInternalFrame f = (JInternalFrame) c; + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + if (f.getContentPane() instanceof JOptionPane) + { + JOptionPane pane = (JOptionPane) f.getContentPane(); + int type = pane.getMessageType(); + if (type == JOptionPane.QUESTION_MESSAGE) + { + Color bc = UIManager.getColor( + "OptionPane.questionDialog.border.background"); + if (bc != null) + g.setColor(bc); + } + if (type == JOptionPane.WARNING_MESSAGE) + { + Color bc = UIManager.getColor( + "OptionPane.warningDialog.border.background"); + if (bc != null) + g.setColor(bc); + } + else if (type == JOptionPane.ERROR_MESSAGE) + { + Color bc = UIManager.getColor( + "OptionPane.errorDialog.border.background"); + if (bc != null) + g.setColor(bc); + } + } + + // fill the border background + g.fillRect(x, y, w, 3); + g.fillRect(x, y, 3, h); + g.fillRect(x + w - 3, y, 3, h); + g.fillRect(x, y + h - 3, w, 3); + + // draw a dot in each corner + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(x, y, 1, 1); + g.fillRect(x + w - 1, y, 1, 1); + g.fillRect(x + w - 1, y + h - 1, 1, 1); + g.fillRect(x, y + h - 1, 1, 1); + + } + + } + + /** + * A border used for {@link JMenu} and {@link JMenuItem} components. + */ + public static class MenuItemBorder extends AbstractBorder + implements UIResource + { + /** The border insets. */ + protected static Insets borderInsets = new Insets(2, 2, 2, 2); + + /** + * Creates a new border instance. + */ + public MenuItemBorder() + { + // Nothing to do here. + } + + /** + * Paints the border for the component. A border is painted only if the + * component is a selected {@link JMenu} or an armed {@link JMenuItem}. + * + * @param c the component. + * @param g the graphics device. + * @param x the x-coordinate of the border area. + * @param y the y-coordinate of the border area. + * @param w the width of the border area. + * @param h the height of the border area. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + Color dark = MetalLookAndFeel.getPrimaryControlDarkShadow(); + Color light = MetalLookAndFeel.getPrimaryControlHighlight(); + if (c instanceof JMenu) + { + JMenu menu = (JMenu) c; + if (menu.isSelected()) + { + g.setColor(dark); + g.drawLine(x, y, x, y + h); + g.drawLine(x, y, x + w, y); + g.drawLine(x + w - 2, y + 1, x + w - 2, y + h); + g.setColor(light); + g.drawLine(x + w - 1, y + 1, x + w - 1, y + h); + } + } + else if (c instanceof JMenuItem) + { + JMenuItem item = (JMenuItem) c; + if (item.isArmed()) + { + g.setColor(dark); + g.drawLine(x, y, x + w, y); + g.setColor(light); + g.drawLine(x, y + h - 1, x + w, y + h - 1); + } + else + { + // Normally we draw a light line on the left. + g.setColor(light); + g.drawLine(x, y, x, y + h); + } + } + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * + * @return The border insets. + */ + public Insets getBorderInsets(Component c) + { + return borderInsets; + } + + /** + * Populates <code>insets</code> with the border insets, then returns it. + * + * @param c the component (ignored). + * @param insets the object to populate with the border insets. + * + * @return The border insets. + * + * @throws NullPointerException if <code>insets</code> is <code>null</code>. + */ + public Insets getBorderInsets(Component c, Insets insets) + { + insets.left = borderInsets.left; + insets.top = borderInsets.top; + insets.bottom = borderInsets.bottom; + insets.right = borderInsets.right; + return insets; + } + } + + /** + * A border used for {@link JMenuBar} components. + */ + public static class MenuBarBorder + extends AbstractBorder + implements UIResource + { + /** The border insets. */ + protected static Insets borderInsets = new Insets(1, 0, 1, 0); + + /** + * Creates a new border instance. + */ + public MenuBarBorder() + { + } + + /** + * Paints the border for the component. A border is painted only if the + * component is a selected {@link JMenu} or an armed {@link JMenuItem}. + * + * @param c the component. + * @param g the graphics device. + * @param x the x-coordinate of the border area. + * @param y the y-coordinate of the border area. + * @param w the width of the border area. + * @param h the height of the border area. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + // Although it is not correct to decide on the static property + // currentTheme which color to use the RI does it like that. + // The trouble is that by simply changing the current theme to + // e.g. DefaultMetalLookAndFeel this method will use another color + // although a change in painting behavior should be expected only + // after setting a new look and feel and updating all components. + if(MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme) + g.setColor(UIManager.getColor("MenuBar.borderColor")); + else + g.setColor(MetalLookAndFeel.getControlShadow()); + + g.drawLine(x, y + h - 1, x + w, y + h - 1); + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * + * @return The border insets. + */ + public Insets getBorderInsets(Component c) + { + return borderInsets; + } + + /** + * Populates <code>insets</code> with the border insets, then returns it. + * + * @param c the component (ignored). + * @param insets the object to populate with the border insets. + * + * @return The border insets. + * + * @throws NullPointerException if <code>insets</code> is <code>null</code>. + */ + public Insets getBorderInsets(Component c, Insets insets) + { + insets.left = borderInsets.left; + insets.top = borderInsets.top; + insets.bottom = borderInsets.bottom; + insets.right = borderInsets.right; + return insets; + } + } + + /** + * A border for {@link JScrollPane} components. + */ + public static class ScrollPaneBorder + extends AbstractBorder + implements UIResource + { + /** The border insets. */ + private static Insets insets = new Insets(1, 1, 2, 2); + + /** + * Constructs a new ScrollPaneBorder. + */ + public ScrollPaneBorder() + { + // Nothing to do here. + } + + /** + * Returns the insets of the border for the Component <code>c</code>. + * + * @param c the Component for which we return the border insets + */ + public Insets getBorderInsets(Component c) + { + return insets; + } + + /** + * Paints the border. + * + * @param c the Component for which the border is painted + * @param g the Graphics context + * @param x the X coordinate of the upper left corner of the border + * @param y the Y coordinate of the upper left corner of the border + * @param w the width of the border + * @param h the height of the border + */ + public void paintBorder(Component c, Graphics g, int x, int y, + int w, int h) + { + Color darkShadow = MetalLookAndFeel.getControlDarkShadow(); + Color shadow = MetalLookAndFeel.getControlShadow(); + Color light = MetalLookAndFeel.getWhite(); + Color middle = MetalLookAndFeel.getControl(); + + // paint top border line + g.setColor(darkShadow); + g.drawLine(x, y, x + w - 2, y); + + // paint left border line + g.drawLine(x, y, x, y + h - 2); + + // paint right inner border line + g.drawLine(x + w - 2, y, x + w - 2, y + h + 1); + + // paint bottom inner border line + g.drawLine(x + 2, y + h - 2, x + w - 2, y + h - 2); + + // draw right outer border line + g.setColor(light); + g.drawLine(x + w - 1, y, x + w - 1, y + h - 1); + + // draw bottom outer border line + g.drawLine(x, y + h - 1, x + w - 1, y + h - 1); + + // paint the lighter points + g.setColor(middle); + g.drawLine(x + w - 1, y, x + w - 1, y); + g.drawLine(x + w - 2, y + 2, x + w - 2, y + 2); + g.drawLine(x, y + h - 1, x, y + h - 1); + g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); + + } + + } + + /** + * A button border that is only visible when the mouse pointer is within + * the button's bounds. + */ + public static class RolloverButtonBorder + extends MetalBorders.ButtonBorder + { + /** + * Creates a new border instance. + */ + public RolloverButtonBorder() + { + // Nothing to do here. + } + + /** + * Paints the border. + * + * @param c the component. + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + // TODO: What should be done here? Obviously the ButtonBorder already + // handles the rollover state in Sun's impl. Maybe this is only there + // for backwards compatibility. + super.paintBorder(c, g, x, y, w, h); + } + } + + /** + * This border is used in Toolbar buttons as inner border. + */ + static class RolloverMarginBorder extends AbstractBorder + { + /** The borders insets. */ + protected static Insets borderInsets = new Insets(3, 3, 3, 3); + + /** + * Creates a new instance of RolloverBorder. + */ + public RolloverMarginBorder() + { + // Nothing to do here. + } + + /** + * Returns the insets of the RolloverBorder. + * + * @param c the component for which the border is used + * + * @return the insets of the RolloverBorder + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + /** + * Returns the insets of the RolloverMarginBorder in the specified + * Insets object. + * + * @param c the component for which the border is used + * @param newInsets the insets object where to put the values + * + * @return the insets of the RolloverMarginBorder + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + if (newInsets == null) + newInsets = new Insets(0, 0, 0, 0); + + AbstractButton b = (AbstractButton) c; + Insets margin = b.getMargin(); + newInsets.bottom = borderInsets.bottom; + newInsets.left = borderInsets.left; + newInsets.right = borderInsets.right; + newInsets.top = borderInsets.top; + return newInsets; + } + } + + /** + * A border implementation for popup menus. + */ + public static class PopupMenuBorder + extends AbstractBorder + implements UIResource + { + + /** The border's insets. */ + protected static Insets borderInsets = new Insets(3, 1, 2, 1); + + /** + * Constructs a new PopupMenuBorder. + */ + public PopupMenuBorder() + { + // Nothing to do here. + } + + /** + * Returns the insets of the border, creating a new Insets instance + * with each call. + * + * @param c the component for which we return the border insets + * (not used here) + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + /** + * Returns the insets of the border, using the supplied Insets instance. + * + * @param c the component for which we return the border insets + * (not used here) + * @param i the Insets instance to fill with the Insets values + */ + public Insets getBorderInsets(Component c, Insets i) + { + Insets insets; + if (i == null) + insets = new Insets(borderInsets.top, borderInsets.left, + borderInsets.bottom, borderInsets.right); + else + { + insets = i; + insets.top = borderInsets.top; + insets.left = borderInsets.left; + insets.bottom = borderInsets.bottom; + insets.right = borderInsets.right; + } + + return insets; + } + + /** + * Paints the border for component <code>c</code> using the + * Graphics context <code>g</code> with the dimension + * <code>x, y, w, h</code>. + * + * @param c the component for which we paint the border + * @param g the Graphics context to use + * @param x the X coordinate of the upper left corner of c + * @param y the Y coordinate of the upper left corner of c + * @param w the width of c + * @param h the height of c + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + Color darkShadow = MetalLookAndFeel.getPrimaryControlDarkShadow(); + Color light = MetalLookAndFeel.getPrimaryControlHighlight(); + + // draw dark outer border + g.setColor(darkShadow); + g.drawRect(x, y, w - 1, h - 1); + + // draw highlighted inner border (only top and left) + g.setColor(light); + g.drawLine(x + 1, y + 1, x + w - 2, y + 1); + } + + } + + /** + * A border used for the {@link JToggleButton} component. + * + * @since 1.3 + */ + public static class ToggleButtonBorder + extends ButtonBorder + { + /** + * Creates a new border instance. + */ + public ToggleButtonBorder() + { + // Nothing to do here. + } + + /** + * Paints the toggle button border. + * + * @param c the component for which we paint the border + * @param g the Graphics context to use + * @param x the X coordinate of the upper left corner of c + * @param y the Y coordinate of the upper left corner of c + * @param w the width of c + * @param h the height of c + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + ButtonModel bmodel = null; + + if (c instanceof AbstractButton) + bmodel = ((AbstractButton) c).getModel(); + + Color darkShadow = MetalLookAndFeel.getControlDarkShadow(); + Color shadow = MetalLookAndFeel.getControlShadow(); + Color light = MetalLookAndFeel.getWhite(); + Color middle = MetalLookAndFeel.getControl(); + + if (c.isEnabled()) + { + // draw dark border + g.setColor(darkShadow); + g.drawRect(x, y, w - 2, h - 2); + + if (!bmodel.isArmed()) + { + // draw light border + g.setColor(light); + g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1); + g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1); + if (bmodel.isSelected()) + g.setColor(middle); + g.drawLine(x + 1, y + 1, x + w - 3, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + h - 3); + + // draw crossing pixels of both borders + g.setColor(shadow); + g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); + g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1); + } + else + { + // draw light border + g.setColor(light); + g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1); + g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1); + + // draw shadow border + g.setColor(shadow); + g.drawLine(x + 1, y + 1, x + w - 2, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + h - 2); + + // draw crossing pixels of both borders + g.setColor(shadow); + g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); + g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1); + + } + // draw corners + g.setColor(middle); + g.drawLine(x, y + h - 1, x, y + h - 1); + g.drawLine(x + w - 1, y, x + w - 1, y); + } + else + { + // draw disabled border + g.setColor(MetalLookAndFeel.getControlDisabled()); + g.drawRect(x, y, w - 2, h - 2); + } + } + } + + /** + * A border used for the {@link JToolBar} component. + */ + public static class ToolBarBorder extends AbstractBorder + implements UIResource, SwingConstants + { + /** + * Creates a new border instance. + */ + public ToolBarBorder() + { + // Nothing to do here. + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * + * @return The border insets. + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + /** + * Returns the border insets. + * + * @param c the component (ignored). + * @return The border insets. + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + JToolBar tb = (JToolBar) c; + if (tb.getOrientation() == JToolBar.HORIZONTAL) + { + if (newInsets == null) + newInsets = new Insets(2, 16, 2, 2); + else + { + newInsets.top = 2; + newInsets.left = 16; + newInsets.bottom = 2; + newInsets.right = 2; + } + return newInsets; + } + else // assume JToolBar.VERTICAL + { + if (newInsets == null) + newInsets = new Insets(16, 2, 2, 2); + else + { + newInsets.top = 16; + newInsets.left = 2; + newInsets.bottom = 2; + newInsets.right = 2; + } + return newInsets; + } + + } + + /** + * Paints the border for the specified component. + * + * @param c the component. + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + + JToolBar tb = (JToolBar) c; + if (tb.getOrientation() == JToolBar.HORIZONTAL) + { + MetalUtils.fillMetalPattern(tb, g, x + 2, y + 2, x + 11, y + h - 5, + MetalLookAndFeel.getControlHighlight(), + MetalLookAndFeel.getControlDarkShadow()); + } + else + { + MetalUtils.fillMetalPattern(tb, g, x + 2, y + 2, x + w - 5, y + 11, + MetalLookAndFeel.getControlHighlight(), + MetalLookAndFeel.getControlDarkShadow()); + } + } + + } + + /** + * A border for table header cells. + * + * @since 1.3 + */ + public static class TableHeaderBorder extends AbstractBorder + { + /** + * The insets of this border. + */ + // TODO: According to tests that I have done, this is really the border + // that should be returned by getBorderInsets(). However, the name + // is very distracting. Is there any deeper meaning in it? + protected Insets editorBorderInsets; + + /** + * Creates a new instance of <code>TableHeaderBorder</code>. + */ + public TableHeaderBorder() + { + editorBorderInsets = new Insets(1, 1, 1, 1); + } + + /** + * Return the insets of this border. + * + * @return the insets of this border + */ + public Insets getBorderInsets(Component c) + { + return editorBorderInsets; + } + + /** + * Paints the border. + * + * @param c the component for which to paint the border + * @param g the graphics context to use + * @param x the x cooridinate of the border rectangle + * @param y the y cooridinate of the border rectangle + * @param w the width of the border rectangle + * @param h the height of the border rectangle + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) + { + Color dark = MetalLookAndFeel.getControlDarkShadow(); + Color light = MetalLookAndFeel.getWhite(); + Color old = g.getColor(); + g.setColor(light); + g.drawLine(x, y, x + w - 2, y); + g.drawLine(x, y, x, y + h - 2); + g.setColor(dark); + g.drawLine(x + w - 1, y, x + w - 1, y + h - 1); + g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1); + g.setColor(old); + } + } + + /** + * Returns a border for Swing buttons in the Metal Look & Feel. + * + * @return a border for Swing buttons in the Metal Look & Feel + */ + public static Border getButtonBorder() + { + if (buttonBorder == null) + { + Border outer = new ButtonBorder(); + Border inner = getMarginBorder(); + buttonBorder = new BorderUIResource.CompoundBorderUIResource(outer, + inner); + } + return buttonBorder; + } + + /** + * Returns a border for use with {@link JToggleButton} components. + * + * @return A border. + * + * @since 1.3 + */ + public static Border getToggleButtonBorder() + { + if (toggleButtonBorder == null) + { + Border outer = new ToggleButtonBorder(); + Border inner = getMarginBorder(); + toggleButtonBorder = new BorderUIResource.CompoundBorderUIResource( + outer, inner); + } + return toggleButtonBorder; + } + + /** + * Returns a border instance that is used with a {@link JInternalFrame} when + * it is in the iconified state. + * + * @return A border. + * + * @since 1.3 + */ + public static Border getDesktopIconBorder() + { + if (desktopIconBorder == null) + desktopIconBorder = new DesktopIconBorder(); + return desktopIconBorder; + } + + /** + * Returns a border for use by the {@link JTextField} component. + * + * @return A border. + * + * @since 1.3 + */ + public static Border getTextFieldBorder() + { + if (textFieldBorder == null) + { + Border inner = getMarginBorder(); + Border outer = new TextFieldBorder(); + textFieldBorder = + new BorderUIResource.CompoundBorderUIResource(outer, inner); + } + return textFieldBorder; + } + + /** + * Returns the border that is used for text components (except text fields, + * which use {@link #getTextFieldBorder}. + * + * @return the border that is used for text components + * + * @since 1.3 + */ + public static Border getTextBorder() + { + if (textBorder == null) + { + Border inner = getMarginBorder(); + Border outer = new Flush3DBorder(); + textBorder = + new BorderUIResource.CompoundBorderUIResource(outer, inner); + } + return textBorder; + } + + /** + * Returns a border for Toolbar buttons in the Metal Look & Feel. + * + * @return a border for Toolbar buttons in the Metal Look & Feel + */ + static Border getToolbarButtonBorder() + { + if (toolbarButtonBorder == null) + { + Border outer = new ButtonBorder(); + Border inner = new RolloverMarginBorder(); + toolbarButtonBorder = new CompoundBorder(outer, inner); + } + return toolbarButtonBorder; + } + + /** + * Returns a shared instance of {@link BasicBorders.MarginBorder}. + * + * @return a shared instance of {@link BasicBorders.MarginBorder} + */ + static Border getMarginBorder() + { + if (marginBorder == null) + marginBorder = new BasicBorders.MarginBorder(); + return marginBorder; + } + + /** + * Returns a shared instance of a compound border for rollover buttons. + * + * @return A shared border instance. + */ + static Border getRolloverBorder() + { + if (rolloverBorder == null) + { + Border outer = new MetalBorders.RolloverButtonBorder(); + Border inner = MetalBorders.getMarginBorder(); + rolloverBorder = new BorderUIResource.CompoundBorderUIResource(outer, + inner); + } + return rolloverBorder; + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java b/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java new file mode 100644 index 000000000..7cf84e5f6 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java @@ -0,0 +1,74 @@ +/* MetalButtonListener.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.beans.PropertyChangeEvent; + +import javax.swing.AbstractButton; +import javax.swing.plaf.basic.BasicButtonListener; + +/** + * A listener for buttons under the {@link MetalLookAndFeel}. + * + * @see MetalButtonUI#createButtonListener + */ +class MetalButtonListener extends BasicButtonListener +{ + + /** + * Creates a new instance. + * + * @param button the button. + */ + public MetalButtonListener(AbstractButton button) + { + super(button); + } + + /** + * Handles property change events. + * + * @param e the event. + */ + public void propertyChange(PropertyChangeEvent e) + { + super.propertyChange(e); + // TODO: What should be done here? + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java new file mode 100644 index 000000000..974f0a85a --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java @@ -0,0 +1,298 @@ +/* MetalButtonUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JToolBar; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicButtonUI; + +/** + * A UI delegate for the {@link JButton} component. + * + * @author Roman Kennke (roman@kennke.org) + */ +public class MetalButtonUI + extends BasicButtonUI +{ + + /** + * The shared button UI. + */ + private static MetalButtonUI sharedUI; + + /** + * The color used to draw the focus rectangle around the text and/or icon. + */ + protected Color focusColor; + + /** + * The background color for the button when it is pressed. + */ + protected Color selectColor; + + /** + * The color for disabled button labels. + */ + protected Color disabledTextColor; + + /** + * Returns a UI delegate for the specified component. + * + * @param c the component (should be a subclass of {@link AbstractButton}). + * + * @return A new instance of <code>MetalButtonUI</code>. + */ + public static ComponentUI createUI(JComponent c) + { + if (sharedUI == null) + sharedUI = new MetalButtonUI(); + return sharedUI; + } + + /** + * Creates a new instance. + */ + public MetalButtonUI() + { + super(); + } + + /** + * Returns the color for the focus border. + * + * @return the color for the focus border + */ + protected Color getFocusColor() + { + focusColor = UIManager.getColor(getPropertyPrefix() + "focus"); + return focusColor; + } + + /** + * Returns the color that indicates a selected button. + * + * @return the color that indicates a selected button + */ + protected Color getSelectColor() + { + selectColor = UIManager.getColor(getPropertyPrefix() + "select"); + return selectColor; + } + + /** + * Returns the color for the text label of disabled buttons. + * + * @return the color for the text label of disabled buttons + */ + protected Color getDisabledTextColor() + { + disabledTextColor = UIManager.getColor(getPropertyPrefix() + + "disabledText"); + return disabledTextColor; + } + + /** + * Installs the default settings for the specified button. + * + * @param button the button. + * + * @see #uninstallDefaults(AbstractButton) + */ + public void installDefaults(AbstractButton button) + { + // This is overridden to be public, for whatever reason. + super.installDefaults(button); + } + + /** + * Removes the defaults added by {@link #installDefaults(AbstractButton)}. + */ + public void uninstallDefaults(AbstractButton button) + { + // This is overridden to be public, for whatever reason. + super.uninstallDefaults(button); + } + + /** + * Paints the background of the button to indicate that it is in the + * "pressed" state. + * + * @param g the graphics context. + * @param b the button. + */ + protected void paintButtonPressed(Graphics g, AbstractButton b) + { + if (b.isContentAreaFilled()) + { + g.setColor(getSelectColor()); + g.fillRect(0, 0, b.getWidth(), b.getHeight()); + } + } + + /** + * Paints the focus rectangle around the button text and/or icon. + * + * @param g the graphics context. + * @param b the button. + * @param viewRect the button bounds. + * @param textRect the text bounds. + * @param iconRect the icon bounds. + */ + protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, + Rectangle textRect, Rectangle iconRect) + { + if (b.isEnabled() && b.hasFocus() && b.isFocusPainted()) + { + Color savedColor = g.getColor(); + g.setColor(getFocusColor()); + Rectangle focusRect = iconRect.union(textRect); + g.drawRect(focusRect.x - 1, focusRect.y, + focusRect.width + 1, focusRect.height); + g.setColor(savedColor); + } + } + + /** + * Paints the button text. + * + * @param g the graphics context. + * @param c the button. + * @param textRect the text bounds. + * @param text the text to display. + */ + protected void paintText(Graphics g, JComponent c, Rectangle textRect, + String text) + { + AbstractButton b = (AbstractButton) c; + Font f = b.getFont(); + g.setFont(f); + FontMetrics fm = g.getFontMetrics(f); + + if (b.isEnabled()) + { + g.setColor(b.getForeground()); + g.drawString(text, textRect.x, textRect.y + fm.getAscent()); + } + else + { + g.setColor(getDisabledTextColor()); + g.drawString(text, textRect.x, textRect.y + fm.getAscent()); + } + } + + /** + * If the property <code>Button.gradient</code> is set, then a gradient is + * painted as background, otherwise the normal superclass behaviour is + * called. + */ + public void update(Graphics g, JComponent c) + { + AbstractButton b = (AbstractButton) c; + if ((b.getBackground() instanceof UIResource) + && b.isContentAreaFilled() && b.isEnabled()) + { + ButtonModel m = b.getModel(); + String uiKey = "Button.gradient"; + if (! isToolbarButton(b)) + { + if (! m.isArmed() && ! m.isPressed() && isDrawingGradient(uiKey)) + { + MetalUtils.paintGradient(g, 0, 0, b.getWidth(), b.getHeight(), + SwingConstants.VERTICAL, + uiKey); + paint(g, c); + return; + } + } + else if (m.isRollover() && isDrawingGradient(uiKey)) + { + MetalUtils.paintGradient(g, 0, 0, b.getWidth(), b.getHeight(), + SwingConstants.VERTICAL, + uiKey); + paint(g, c); + return; + } + } + // Fallback if we didn't have any of the two above cases. + super.update(g, c); + } + + /** + * Returns <code>true</code> when the button is a toolbar button, + * <code>false</code> otherwise. + * + * @param b the button component to test + * + * @return <code>true</code> when the button is a toolbar button, + * <code>false</code> otherwise + */ + private boolean isToolbarButton(Component b) + { + Component parent = b.getParent(); + return parent instanceof JToolBar; + } + + /** + * Returns <code>true</code> if we should draw the button gradient, + * <code>false</code> otherwise. + * + * @param uiKey the UIManager key for the gradient + * + * @return <code>true</code> if we should draw the button gradient, + * <code>false</code> otherwise + */ + private boolean isDrawingGradient(String uiKey) + { + return (UIManager.get(uiKey) != null); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxIcon.java b/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxIcon.java new file mode 100644 index 000000000..5e0ac066c --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxIcon.java @@ -0,0 +1,142 @@ +/* MetalCheckBoxIcon.java -- An icon for JCheckBoxes in the Metal L&F + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Component; +import java.awt.Graphics; +import java.io.Serializable; + +import javax.swing.AbstractButton; +import javax.swing.Icon; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.plaf.UIResource; + +/** + * An {@link Icon} used by the {@link MetalCheckBoxUI} class. + * + * @author Roman Kennke (roman@kennke.org) + */ +public class MetalCheckBoxIcon + implements Icon, UIResource, Serializable +{ + + /** Used to paint the border of the icon. */ + MetalBorders.ButtonBorder border; + + /** + * Creates a new MetalCheckBoxIcon instance. + */ + public MetalCheckBoxIcon() + { + border = new MetalBorders.ButtonBorder(); + } + + /** + * Draws the check in the CheckBox. + * + * @param c the component to draw on + * @param g the Graphics context to draw with + * @param x the X position + * @param y the Y position + */ + protected void drawCheck(Component c, Graphics g, int x, int y) + { + if (c.isEnabled()) + g.setColor(MetalLookAndFeel.getBlack()); + else + g.setColor(MetalLookAndFeel.getControlDisabled()); + g.drawLine(3 + x, 5 + y, 3 + x, 9 + y); + g.drawLine(4 + x, 5 + y, 4 + x, 9 + y); + g.drawLine(5 + x, 7 + y, 9 + x, 3 + y); + g.drawLine(5 + x, 8 + y, 9 + x, 4 + y); + } + + /** + * Returns the size (both X and Y) of the checkbox icon. + * + * @return the size of the checkbox icon + */ + protected int getControlSize() + { + return 13; + } + + /** + * Returns the width of the icon in pixels. + * + * @return the width of the icon in pixels + */ + public int getIconWidth() + { + return getControlSize(); + } + + /** + * Returns the height of the icon in pixels. + * + * @return the height of the icon in pixels + */ + public int getIconHeight() + { + return getControlSize(); + } + + /** + * Paints the icon. This first paints the border of the CheckBox and + * if the CheckBox is selected it calls {@link #drawCheck} to draw + * the check. + * + * @param c the Component to draw on (gets casted to JCheckBox) + * @param g the Graphics context to draw with + * @param x the X position + * @param y the Y position + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + if (UIManager.get("CheckBox.gradient") != null) + MetalUtils.paintGradient(g, x, y, getIconWidth(), getIconHeight(), + SwingConstants.VERTICAL, "CheckBox.gradient"); + border.paintBorder(c, g, x, y, getIconWidth(), getIconHeight()); + + AbstractButton b = (AbstractButton) c; + if (b.isSelected()) + drawCheck(b, g, x, y); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxUI.java new file mode 100644 index 000000000..11979e170 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxUI.java @@ -0,0 +1,88 @@ +/* MetalCheckBoxUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.UIDefaults; +import javax.swing.plaf.ComponentUI; + +/** + * A UI delegate for the {@link JCheckBox} component. + */ +public class MetalCheckBoxUI + extends MetalRadioButtonUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for JCheckBoxes. */ + private static MetalCheckBoxUI instance; + + /** + * Constructs a new instance of MetalCheckBoxUI. + */ + public MetalCheckBoxUI() + { + super(); + } + + /** + * Returns a shared instance of <code>MetalCheckBoxUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A shared instance of <code>MetalCheckBoxUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalCheckBoxUI(); + return instance; + } + + /** + * Returns the prefix for properties defined in the {@link UIDefaults} table. + * + * @return The property prefix (<code>"CheckBox."</code>). + */ + public String getPropertyPrefix() + { + return "CheckBox."; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java new file mode 100644 index 000000000..8ec8bad72 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java @@ -0,0 +1,294 @@ +/* MetalComboBoxButton.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.CellRendererPane; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import javax.swing.UIManager; + +/** + * A button used by the {@link MetalComboBoxUI} class. + */ +public class MetalComboBoxButton + extends JButton +{ + + /** A reference to the JComboBox that the button belongs to. */ + protected JComboBox comboBox; + + /** A reference to the JList. */ + protected JList listBox; + + /** + * Used for rendering the selected item. + */ + protected CellRendererPane rendererPane; + + /** The button icon. */ + protected Icon comboIcon; + + /** Display just the icon, or the icon plus the label. */ + protected boolean iconOnly; + + /** + * Creates a new button. + * + * @param cb the combo that the button is used for (<code>null</code> not + * permitted). + * @param i the icon displayed on the button. + * @param pane the rendering pane. + * @param list the list. + */ + public MetalComboBoxButton(JComboBox cb, Icon i, CellRendererPane pane, + JList list) + { + this(cb, i, cb.isEditable(), pane, list); + } + + /** + * Creates a new button. + * + * @param cb the combo that the button is used for (<code>null</code> not + * permitted). + * @param i the icon displayed on the button. + * @param onlyIcon a flag that specifies whether the button displays only an + * icon, or text as well. + * @param pane the rendering pane. + * @param list the list. + */ + public MetalComboBoxButton(JComboBox cb, Icon i, boolean onlyIcon, + CellRendererPane pane, JList list) + { + super(); + if (cb == null) + throw new NullPointerException("Null 'cb' argument"); + comboBox = cb; + comboIcon = i; + iconOnly = onlyIcon; + listBox = list; + rendererPane = pane; + setRolloverEnabled(false); + setEnabled(comboBox.isEnabled()); + setFocusable(comboBox.isEnabled()); + } + + /** + * Returns the combo box that the button is used with. + * + * @return The combo box. + */ + public final JComboBox getComboBox() + { + return comboBox; + } + + /** + * Sets the combo box that the button is used with. + * + * @param cb the combo box. + */ + public final void setComboBox(JComboBox cb) + { + comboBox = cb; + } + + /** + * Returns the icon displayed by the button. By default, this will be an + * instance of {@link MetalComboBoxIcon}. + * + * @return The icon displayed by the button. + */ + public final Icon getComboIcon() + { + return comboIcon; + } + + /** + * Sets the icon displayed by the button. + * + * @param i the icon. + */ + public final void setComboIcon(Icon i) + { + comboIcon = i; + } + + /** + * Returns a flag that controls whether the button displays an icon only, + * or text as well. + * + * @return A boolean. + */ + public final boolean isIconOnly() + { + return iconOnly; + } + + /** + * Sets the flag that controls whether the button displays an icon only, + * or text as well. + * + * @param isIconOnly the flag. + */ + public final void setIconOnly(boolean isIconOnly) + { + iconOnly = isIconOnly; + } + + /** + * Returns <code>false</code>, to indicate that this component is not part + * of the focus traversal group. + * + * @return <code>false</code> + */ + public boolean isFocusTraversable() + { + return false; + } + + /** + * Enables or disables the button. + * + * @param enabled the new status. + */ + public void setEnabled(boolean enabled) + { + super.setEnabled(enabled); + if (enabled) + { + setBackground(comboBox.getBackground()); + setForeground(comboBox.getForeground()); + } + else + { + setBackground(UIManager.getColor("ComboBox.disabledBackground")); + setForeground(UIManager.getColor("ComboBox.disabledForeground")); + } + } + + /** + * Paints the component. + * + * @param g the graphics device. + */ + public void paintComponent(Graphics g) + { + super.paintComponent(g); + Insets insets = this.getInsets(); + int w = getWidth() - (insets.left + insets.right); + int h = getHeight() - (insets.top + insets.bottom); + if (h > 0 && w > 0) + { + int x1 = insets.left; + int y1 = insets.top; + int x2 = x1 + (w - 1); + int y2 = y1 + (h - 1); + int iconWidth = 0; + int iconX = x2; + if (comboIcon != null) + { + iconWidth = comboIcon.getIconWidth(); + int iconHeight = comboIcon.getIconHeight(); + int iconY; + if (iconOnly) + { + iconX = getWidth() / 2 - iconWidth / 2; + iconY = getHeight() / 2 - iconHeight / 2; + } + else + { + iconX = x1 + (w - 1) - iconWidth; + iconY = y1 + (y2 - y1) / 2 - iconHeight / 2; + } + comboIcon.paintIcon(this, g, iconX, iconY); + if (this.hasFocus()) + { + g.setColor(MetalLookAndFeel.getFocusColor()); + g.drawRect(x1 - 1, y1 - 1, w + 3, h + 1); + } + } + if (! iconOnly && comboBox != null) + { + ListCellRenderer renderer = comboBox.getRenderer(); + boolean pressed = this.getModel().isPressed(); + Component comp = renderer.getListCellRendererComponent(listBox, + comboBox.getSelectedItem(), -1, false, false); + comp.setFont(rendererPane.getFont()); + + if ((model.isArmed() && model.isPressed()) + || (comboBox.isFocusOwner() && !comboBox.isPopupVisible())) + { + if (isOpaque()) + { + comp.setBackground(UIManager.getColor("Button.select")); + comp.setForeground(comboBox.getForeground()); + } + } + else if (! comboBox.isEnabled()) + { + if (this.isOpaque()) + { + Color dbg = + UIManager.getColor("ComboBox.disabledBackground"); + comp.setBackground(dbg); + Color dfg = + UIManager.getColor("ComboBox.disabledForeground"); + comp.setForeground(dfg); + } + } + else + { + comp.setForeground(comboBox.getForeground()); + comp.setBackground(comboBox.getBackground()); + } + int wr = w - (insets.right + iconWidth); + rendererPane.paintComponent(g, comp, this, x1, y1, wr, h); + } + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java new file mode 100644 index 000000000..8872d74e2 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java @@ -0,0 +1,190 @@ +/* MetalComboBoxEditor.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.JTextField; +import javax.swing.border.AbstractBorder; +import javax.swing.plaf.basic.BasicComboBoxEditor; +import javax.swing.plaf.metal.MetalLookAndFeel; + +/** + * An editor used by the {@link MetalComboBoxUI} class. + */ +public class MetalComboBoxEditor extends BasicComboBoxEditor +{ + /** + * A border used for the {@link JTextField} component. + */ + static class MetalComboBoxEditorBorder extends AbstractBorder + { + /** + * Creates a new border instance. + */ + public MetalComboBoxEditorBorder() + { + // Nothing to do here. + } + + /** + * Paints the border for the specified component. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + g.translate(x, y); + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(0, 0, w - 1, 0); + g.drawLine(0, 0, 0, h - 1); + g.drawLine(0, h - 1, w - 1, h - 1); + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(1, 1, w - 2, 1); + g.drawLine(1, 1, 1, h - 2); + g.drawLine(1, h - 2, w - 1, h - 2); + g.drawLine(w - 1, 1, w - 1, h - 2); + } + else + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(0, 0, w - 1, 0); + g.drawLine(0, 0, 0, h - 2); + g.drawLine(0, h - 2, w - 1, h - 2); + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(1, 1, w - 1, 1); + g.drawLine(1, 1, 1, h - 1); + g.drawLine(1, h - 1, w - 1, h - 1); + g.setColor(MetalLookAndFeel.getControl()); + g.drawLine(1, h - 2, 1, h - 2); + } + g.translate(-x, -y); + } + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge, which is zero + * for the default implementation provided by AbstractButton. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + return editorBorderInsets; + } + } + + /** + * A subclass of {@link MetalComboBoxEditor} that implements the + * {@link javax.swing.plaf.UIResource} interface. + */ + public static class UIResource extends MetalComboBoxEditor + implements javax.swing.plaf.UIResource + { + /** + * Creates a new instance. + */ + public UIResource() + { + // Nothing to do here. + } + } + + /** + * A special textfield implementation for the MetalComboBoxEditor. + */ + private class EditorTextField extends JTextField + { + EditorTextField(String s, int columns) + { + super(s, columns); + } + + /** + * Tests seem to show that the textfield in MetalComboBoxEditors have + * a height + 4. + */ + public Dimension getPreferredSize() + { + Dimension size = super.getPreferredSize(); + size.height += 4; + return size; + } + + /** + * Tests seem to show that the textfield in MetalComboBoxEditors have + * a height + 4. + */ + public Dimension getMinimumSize() + { + Dimension size = super.getMinimumSize(); + size.height += 4; + return size; + } + } + + /** The editor's border insets. */ + protected static Insets editorBorderInsets = new Insets(2, 2, 2, 0); + + /** + * Creates a new editor. + */ + public MetalComboBoxEditor() + { + editor = new EditorTextField("", 9); + editor.setBorder(new MetalComboBoxEditorBorder()); + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxIcon.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxIcon.java new file mode 100644 index 000000000..45c8eadc5 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxIcon.java @@ -0,0 +1,102 @@ +/* MetalComboBoxIcon.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.io.Serializable; + +import javax.swing.Icon; + +/** + * An icon used by the {@link MetalComboBoxUI} class. + */ +public class MetalComboBoxIcon implements Icon, Serializable +{ + + /** + * Creates a new icon. + */ + public MetalComboBoxIcon() + { + // nothing required. + } + + /** + * Returns the icon width, which for this icon is 10 pixels. + * + * @return <code>10</code>. + */ + public int getIconWidth() + { + return 10; + } + + /** + * Returns the icon height, which for this icon is 5 pixels. + * + * @return <code>5</code>. + */ + public int getIconHeight() + { + return 5; + } + + /** + * Paints the icon at the location (x, y). + * + * @param c the combo box (ignored here). + * @param g the graphics device. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + if (c.isEnabled()) + g.setColor(MetalLookAndFeel.getBlack()); + else + g.setColor(MetalLookAndFeel.getControlDisabled()); + for (int i = 0; i < 5; i++) + g.drawLine(x + i, y + i, x + 9 - i, y + i); + g.setColor(savedColor); + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java new file mode 100644 index 000000000..b9019b70d --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java @@ -0,0 +1,372 @@ +/* MetalComboBoxUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.ComboBoxEditor; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicComboBoxUI; +import javax.swing.plaf.basic.BasicComboPopup; +import javax.swing.plaf.basic.ComboPopup; + + +/** + * A UI delegate for the {@link JComboBox} component. + */ +public class MetalComboBoxUI extends BasicComboBoxUI +{ + /** + * A layout manager that arranges the editor component (if active) and the + * button that make up the combo box. + */ + public class MetalComboBoxLayoutManager + extends BasicComboBoxUI.ComboBoxLayoutManager + { + /** + * Creates a new instance of the layout manager. + */ + public MetalComboBoxLayoutManager() + { + // Nothing to do here. + } + + /** + * Arranges the editor (if visible) and button that comprise the combo + * box. + * + * @param parent the parent. + */ + public void layoutContainer(Container parent) + { + layoutComboBox(parent, this); + } + + /** + * Calls the <code>layoutContainer(Container)</code> method in the super + * class. + * + * @param parent the container. + */ + public void superLayout(Container parent) + { + super.layoutContainer(parent); + } + } + + /** + * A listener used to handle property changes in the {@link JComboBox} + * component, to ensure that the UI delegate accurately reflects the current + * state in the rendering onscreen. + */ + public class MetalPropertyChangeListener + extends BasicComboBoxUI.PropertyChangeHandler + { + /** + * Creates a new listener. + */ + public MetalPropertyChangeListener() + { + // Nothing to do here. + } + + /** + * Handles a property change event, updating the UI components as + * appropriate. + * + * @param e the event. + */ + public void propertyChange(PropertyChangeEvent e) + { + super.propertyChange(e); + String name = e.getPropertyName(); + if (name.equals("editable")) + editablePropertyChanged(e); + else if (name.equals("enabled")) + { + if (arrowButton instanceof MetalComboBoxButton) + { + arrowButton.setFocusable(!comboBox.isEditable() + && comboBox.isEnabled()); + comboBox.repaint(); + } + } + else if (name.equals("background")) + { + Color c = (Color) e.getNewValue(); + arrowButton.setBackground(c); + listBox.setBackground(c); + } + else if (name.equals("foreground")) + { + Color c = (Color) e.getNewValue(); + arrowButton.setForeground(c); + listBox.setForeground(c); + } + } + } + + /** + * A popup menu for the combo-box. + * + * @see #createPopup() + * + * @deprecated 1.4 + */ + public class MetalComboPopup extends BasicComboPopup + { + /** + * Creates a new popup. + * + * @param cBox the combo box. + */ + public MetalComboPopup(JComboBox cBox) + { + super(cBox); + } + + public void delegateFocus(MouseEvent e) + { + super.delegateFocus(e); + } + } + + /** + * Constructs a new instance of MetalComboBoxUI. + */ + public MetalComboBoxUI() + { + super(); + } + + /** + * Returns an instance of MetalComboBoxUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalComboBoxUI + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalComboBoxUI(); + } + + /** + * Creates an editor for the combo box. + * + * @return An editor. + */ + protected ComboBoxEditor createEditor() + { + return new MetalComboBoxEditor.UIResource(); + } + + /** + * Creates a popup for the combo box. + * + * @return A popup. + */ + protected ComboPopup createPopup() + { + return super.createPopup(); + } + + /** + * Creates a new button for use in rendering the JComboBox. + * + * @return A button. + */ + protected JButton createArrowButton() + { + JButton button = new MetalComboBoxButton(comboBox, new MetalComboBoxIcon(), + currentValuePane, listBox); + button.setMargin(new Insets(0, 1, 1, 3)); + return button; + } + + /** + * Creates a new property change listener. + * + * @return A new property change listener. + */ + public PropertyChangeListener createPropertyChangeListener() + { + return new MetalPropertyChangeListener(); + } + + public void paint(Graphics g, JComponent c) + { + // do nothing, the button and text field are painted elsewhere + } + + /** + * Updates the button and text field to reflect a change in the 'editable' + * property. + * + * @param e the event. + * + * @deprecated 1.4 + */ + protected void editablePropertyChanged(PropertyChangeEvent e) + { + if (arrowButton instanceof MetalComboBoxButton) + { + MetalComboBoxButton b = (MetalComboBoxButton) arrowButton; + b.setIconOnly(comboBox.isEditable()); + b.setFocusable(!comboBox.isEditable() && comboBox.isEnabled()); + comboBox.repaint(); + } + } + + /** + * Creates a new layout manager for the UI delegate. + * + * @return A new layout manager. + */ + protected LayoutManager createLayoutManager() + { + return new MetalComboBoxLayoutManager(); + } + + /** + * Not used in Classpath. + * + * @deprecated 1.4 + */ + protected void removeListeners() + { + // no longer used in JDK 1.4 + } + + /** + * Returns the minimum size for the combo. + * + * @param c the component + * + * @return The minimum size for the combo box. + */ + public Dimension getMinimumSize(JComponent c) + { + if (!isMinimumSizeDirty) + return new Dimension(cachedMinimumSize); + + Dimension d; + if (!comboBox.isEditable() && arrowButton != null + && arrowButton instanceof MetalComboBoxButton) + { + MetalComboBoxButton b = (MetalComboBoxButton) arrowButton; + d = getDisplaySize(); + Insets arrowInsets = b.getInsets(); + Insets comboInsets = comboBox.getInsets(); + Icon icon = b.getComboIcon(); + d.width += comboInsets.left + comboInsets.right; + d.width += arrowInsets.left + arrowInsets.right; + d.width += arrowInsets.right + icon.getIconWidth(); + d.height += comboInsets.top + comboInsets.bottom; + d.height += arrowInsets.top + arrowInsets.bottom; + } + else if (comboBox.isEditable() && arrowButton != null && editor != null) + { + d = super.getMinimumSize(c); + Insets arrowMargin = arrowButton.getMargin(); + d.height += arrowMargin.top + arrowMargin.bottom; + d.width += arrowMargin.left + arrowMargin.right; + } + else + { + d = super.getMinimumSize(c); + } + cachedMinimumSize.setSize(d.width, d.height); + isMinimumSizeDirty = false; + return new Dimension(cachedMinimumSize); + } + + /** + * Configures the editor for this combo box. + */ + public void configureEditor() + { + super.configureEditor(); + if (popupKeyListener != null) + editor.removeKeyListener(popupKeyListener); + if (focusListener != null) + editor.addFocusListener(focusListener); + } + + /** + * Unconfigures the editor for this combo box. + */ + public void unconfigureEditor() + { + super.unconfigureEditor(); + if (focusListener != null) + editor.removeFocusListener(focusListener); + } + + /** + * Lays out the ComboBox + */ + public void layoutComboBox(Container parent, + MetalComboBoxUI.MetalComboBoxLayoutManager manager) + { + if (comboBox.isEditable()) + manager.superLayout(parent); + else if (arrowButton != null) + { + Insets comboInsets = comboBox.getInsets(); + int width = comboBox.getWidth(); + int height = comboBox.getHeight(); + arrowButton.setBounds(comboInsets.left, comboInsets.top, + width - (comboInsets.left + comboInsets.right), + height - (comboInsets.top + comboInsets.bottom)); + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java new file mode 100644 index 000000000..0c1163a8e --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java @@ -0,0 +1,72 @@ +/* MetalDesktopIconUI.java + Copyright (C) 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.JInternalFrame; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicDesktopIconUI; + +/** + * A UI delegate for the {@link JInternalFrame.JDesktopIcon} component. + */ +public class MetalDesktopIconUI + extends BasicDesktopIconUI +{ + + /** + * Constructs a new instance of <code>MetalDesktopIconUI</code>. + */ + public MetalDesktopIconUI() + { + super(); + } + + /** + * Returns a new <code>MetalDesktopIconUI</code> instance. + * + * @param component the component (ignored). + * + * @return A new <code>MetalDesktopIconUI</code> instance. + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalDesktopIconUI(); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java new file mode 100644 index 000000000..df49edf61 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java @@ -0,0 +1,2120 @@ +/* MetalFileChooserUI.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Rectangle; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.text.DateFormat; +import java.text.NumberFormat; +import java.util.Date; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.AbstractListModel; +import javax.swing.ActionMap; +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.ComboBoxModel; +import javax.swing.DefaultListCellRenderer; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.JToggleButton; +import javax.swing.ListModel; +import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileSystemView; +import javax.swing.filechooser.FileView; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicFileChooserUI; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.DefaultTableModel; + + +/** + * A UI delegate for the {@link JFileChooser} component. This class is only + * partially implemented and is not usable yet. + */ +public class MetalFileChooserUI + extends BasicFileChooserUI +{ + + /** + * A renderer for the files and directories in the file chooser table. + */ + class TableFileRenderer + extends DefaultTableCellRenderer + { + + /** + * Creates a new renderer. + */ + public TableFileRenderer() + { + super(); + } + + /** + * Returns a component that can render the specified value. + * + * @param table the table + * @param value the string value of the cell + * @param isSelected is the item selected? + * @param hasFocus does the item have the focus? + * @param row the row + * @param column the column + * + * @return The renderer. + */ + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) + { + if (column == 0) + { + FileView v = getFileView(getFileChooser()); + ListModel lm = fileList.getModel(); + if (row < lm.getSize()) + setIcon(v.getIcon((File) lm.getElementAt(row))); + } + else + setIcon(null); + + setText(value.toString()); + setOpaque(true); + setEnabled(table.isEnabled()); + setFont(fileList.getFont()); + + if (startEditing && column == 0 || !isSelected) + { + setBackground(table.getBackground()); + setForeground(table.getForeground()); + } + else + { + setBackground(table.getSelectionBackground()); + setForeground(table.getSelectionForeground()); + } + + if (hasFocus) + setBorder(UIManager.getBorder("Table.focusCellHighlightBorder")); + else + setBorder(noFocusBorder); + + return this; + } + } + + /** + * ActionListener for the list view. + */ + class ListViewActionListener implements ActionListener + { + + /** + * This method is invoked when an action occurs. + * + * @param e - + * the <code>ActionEvent</code> that occurred + */ + public void actionPerformed(ActionEvent e) + { + if (!listView) + { + int[] index = fileTable.getSelectedRows(); + listView = true; + JFileChooser fc = getFileChooser(); + fc.remove(fileTablePanel); + createList(fc); + + fileList.getSelectionModel().clearSelection(); + if (index.length > 0) + for (int i = 0; i < index.length; i++) + fileList.getSelectionModel().addSelectionInterval(index[i], index[i]); + + fc.add(fileListPanel, BorderLayout.CENTER); + fc.revalidate(); + fc.repaint(); + } + } + } + + /** + * ActionListener for the details view. + */ + class DetailViewActionListener implements ActionListener + { + + /** + * This method is invoked when an action occurs. + * + * @param e - + * the <code>ActionEvent</code> that occurred + */ + public void actionPerformed(ActionEvent e) + { + if (listView) + { + int[] index = fileList.getSelectedIndices(); + JFileChooser fc = getFileChooser(); + listView = false; + fc.remove(fileListPanel); + + if (fileTable == null) + createDetailsView(fc); + else + updateTable(); + + fileTable.getSelectionModel().clearSelection(); + if (index.length > 0) + { + for (int i = 0; i < index.length; i++) + fileTable.getSelectionModel().addSelectionInterval(index[i], index[i]); + } + + fc.add(fileTablePanel, BorderLayout.CENTER); + fc.revalidate(); + fc.repaint(); + } + } + } + + /** + * A property change listener. + */ + class MetalFileChooserPropertyChangeListener + implements PropertyChangeListener + { + /** + * Default constructor. + */ + public MetalFileChooserPropertyChangeListener() + { + } + + /** + * Handles a property change event. + * + * @param e the event. + */ + public void propertyChange(PropertyChangeEvent e) + { + JFileChooser filechooser = getFileChooser(); + + String n = e.getPropertyName(); + if (n.equals(JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY)) + { + int mode = -1; + if (filechooser.isMultiSelectionEnabled()) + mode = ListSelectionModel.MULTIPLE_INTERVAL_SELECTION; + else + mode = ListSelectionModel.SINGLE_SELECTION; + + if (listView) + fileList.setSelectionMode(mode); + else + fileTable.setSelectionMode(mode); + } + else if (n.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) + { + File file = filechooser.getSelectedFile(); + + if (file != null + && filechooser.getDialogType() == JFileChooser.SAVE_DIALOG) + { + if (file.isDirectory() && filechooser.isTraversable(file)) + { + directoryLabel = look; + dirLabel.setText(directoryLabel); + filechooser.setApproveButtonText(openButtonText); + filechooser.setApproveButtonToolTipText(openButtonToolTipText); + } + else if (file.isFile()) + { + directoryLabel = save; + dirLabel.setText(directoryLabel); + filechooser.setApproveButtonText(saveButtonText); + filechooser.setApproveButtonToolTipText(saveButtonToolTipText); + } + } + + if (file == null) + setFileName(null); + else if (file.isFile() || filechooser.getFileSelectionMode() + != JFileChooser.FILES_ONLY) + setFileName(file.getName()); + int index = -1; + index = getModel().indexOf(file); + if (index >= 0) + { + if (listView) + { + fileList.setSelectedIndex(index); + fileList.ensureIndexIsVisible(index); + fileList.revalidate(); + fileList.repaint(); + } + else + { + fileTable.getSelectionModel().addSelectionInterval(index, index); + fileTable.scrollRectToVisible(fileTable.getCellRect(index, 0, true)); + fileTable.revalidate(); + fileTable.repaint(); + } + } + } + + else if (n.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) + { + if (listView) + { + fileList.clearSelection(); + fileList.revalidate(); + fileList.repaint(); + } + else + { + fileTable.clearSelection(); + fileTable.revalidate(); + fileTable.repaint(); + } + + setDirectorySelected(false); + File currentDirectory = filechooser.getCurrentDirectory(); + setDirectory(currentDirectory); + boolean hasParent = currentDirectory.getParentFile() != null; + getChangeToParentDirectoryAction().setEnabled(hasParent); + } + + else if (n.equals(JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY)) + { + filterModel.propertyChange(e); + } + else if (n.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) + { + filterModel.propertyChange(e); + } + else if (n.equals(JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY) + || n.equals(JFileChooser.DIALOG_TITLE_CHANGED_PROPERTY)) + { + Window owner = SwingUtilities.windowForComponent(filechooser); + if (owner instanceof JDialog) + ((JDialog) owner).setTitle(getDialogTitle(filechooser)); + approveButton.setText(getApproveButtonText(filechooser)); + approveButton.setToolTipText( + getApproveButtonToolTipText(filechooser)); + approveButton.setMnemonic(getApproveButtonMnemonic(filechooser)); + } + + else if (n.equals(JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY)) + approveButton.setText(getApproveButtonText(filechooser)); + + else if (n.equals( + JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY)) + approveButton.setToolTipText(getApproveButtonToolTipText(filechooser)); + + else if (n.equals(JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY)) + approveButton.setMnemonic(getApproveButtonMnemonic(filechooser)); + + else if (n.equals( + JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY)) + { + if (filechooser.getControlButtonsAreShown()) + { + topPanel.add(controls, BorderLayout.EAST); + } + else + topPanel.remove(controls); + topPanel.revalidate(); + topPanel.repaint(); + topPanel.doLayout(); + } + + else if (n.equals( + JFileChooser.ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY)) + { + if (filechooser.isAcceptAllFileFilterUsed()) + filechooser.addChoosableFileFilter( + getAcceptAllFileFilter(filechooser)); + else + filechooser.removeChoosableFileFilter( + getAcceptAllFileFilter(filechooser)); + } + + else if (n.equals(JFileChooser.ACCESSORY_CHANGED_PROPERTY)) + { + JComponent old = (JComponent) e.getOldValue(); + if (old != null) + getAccessoryPanel().remove(old); + JComponent newval = (JComponent) e.getNewValue(); + if (newval != null) + getAccessoryPanel().add(newval); + } + + if (n.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY) + || n.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY) + || n.equals(JFileChooser.FILE_HIDING_CHANGED_PROPERTY)) + { + // Remove editing component + if (fileTable != null) + fileTable.removeAll(); + if (fileList != null) + fileList.removeAll(); + startEditing = false; + + // Set text on button back to original. + if (filechooser.getDialogType() == JFileChooser.SAVE_DIALOG) + { + directoryLabel = save; + dirLabel.setText(directoryLabel); + filechooser.setApproveButtonText(saveButtonText); + filechooser.setApproveButtonToolTipText(saveButtonToolTipText); + } + + rescanCurrentDirectory(filechooser); + } + + filechooser.revalidate(); + filechooser.repaint(); + } + } + + /** + * A combo box model containing the selected directory and all its parent + * directories. + */ + protected class DirectoryComboBoxModel + extends AbstractListModel + implements ComboBoxModel + { + /** Storage for the items in the model. */ + private List items; + + /** The index of the selected item. */ + private int selectedIndex; + + /** + * Creates a new model. + */ + public DirectoryComboBoxModel() + { + items = new java.util.ArrayList(); + selectedIndex = -1; + } + + /** + * Returns the number of items in the model. + * + * @return The number of items in the model. + */ + public int getSize() + { + return items.size(); + } + + /** + * Returns the item at the specified index. + * + * @param index the item index. + * + * @return The item. + */ + public Object getElementAt(int index) + { + return items.get(index); + } + + /** + * Returns the depth of the item at the given <code>index</code>. + * + * @param index the item index. + * + * @return The depth. + */ + public int getDepth(int index) + { + return Math.max(index, 0); + } + + /** + * Returns the selected item, or <code>null</code> if no item is selected. + * + * @return The selected item, or <code>null</code>. + */ + public Object getSelectedItem() + { + if (selectedIndex >= 0) + return items.get(selectedIndex); + else + return null; + } + + /** + * Sets the selected item. This clears all the directories from the + * existing list, and repopulates it with the new selected directory + * and all its parent directories. + * + * @param selectedDirectory the selected directory. + */ + public void setSelectedItem(Object selectedDirectory) + { + items.clear(); + FileSystemView fsv = getFileChooser().getFileSystemView(); + File parent = (File) selectedDirectory; + while (parent != null) + { + items.add(0, parent); + parent = fsv.getParentDirectory(parent); + } + selectedIndex = items.indexOf(selectedDirectory); + fireContentsChanged(this, 0, items.size() - 1); + } + + } + + /** + * Handles changes to the selection in the directory combo box. + */ + protected class DirectoryComboBoxAction + extends AbstractAction + { + /** + * Creates a new action. + */ + protected DirectoryComboBoxAction() + { + // Nothing to do here. + } + + /** + * Handles the action event. + * + * @param e the event. + */ + public void actionPerformed(ActionEvent e) + { + JFileChooser fc = getFileChooser(); + fc.setCurrentDirectory((File) directoryModel.getSelectedItem()); + } + } + + /** + * A renderer for the items in the directory combo box. + */ + class DirectoryComboBoxRenderer + extends DefaultListCellRenderer + { + /** + * This is the icon that is displayed in the combobox. This wraps + * the standard icon and adds indendation. + */ + private IndentIcon indentIcon; + + /** + * Creates a new renderer. + */ + public DirectoryComboBoxRenderer(JFileChooser fc) + { + indentIcon = new IndentIcon(); + } + + /** + * Returns a component that can be used to paint the given value within + * the list. + * + * @param list the list. + * @param value the value (a {@link File}). + * @param index the item index. + * @param isSelected is the item selected? + * @param cellHasFocus does the list cell have focus? + * + * @return The list cell renderer. + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + super.getListCellRendererComponent(list, value, index, isSelected, + cellHasFocus); + File file = (File) value; + setText(getFileChooser().getName(file)); + + // Install indented icon. + Icon icon = getFileChooser().getIcon(file); + indentIcon.setIcon(icon); + int depth = directoryModel.getDepth(index); + indentIcon.setDepth(depth); + setIcon(indentIcon); + + return this; + } + } + + /** + * An icon that wraps another icon and adds indentation. + */ + class IndentIcon + implements Icon + { + + /** + * The indentation level. + */ + private static final int INDENT = 10; + + /** + * The wrapped icon. + */ + private Icon icon; + + /** + * The current depth. + */ + private int depth; + + /** + * Sets the icon to be wrapped. + * + * @param i the icon + */ + void setIcon(Icon i) + { + icon = i; + } + + /** + * Sets the indentation depth. + * + * @param d the depth to set + */ + void setDepth(int d) + { + depth = d; + } + + public int getIconHeight() + { + return icon.getIconHeight(); + } + + public int getIconWidth() + { + return icon.getIconWidth() + depth * INDENT; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + icon.paintIcon(c, g, x + depth * INDENT, y); + } + + } + + /** + * A renderer for the files and directories in the file chooser. + */ + protected class FileRenderer + extends DefaultListCellRenderer + { + + /** + * Creates a new renderer. + */ + protected FileRenderer() + { + // Nothing to do here. + } + + /** + * Returns a component that can render the specified value. + * + * @param list the list. + * @param value the value (a {@link File}). + * @param index the index. + * @param isSelected is the item selected? + * @param cellHasFocus does the item have the focus? + * + * @return The renderer. + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) + { + FileView v = getFileView(getFileChooser()); + File f = (File) value; + if (f != null) + { + setText(v.getName(f)); + setIcon(v.getIcon(f)); + } + else + { + setText(""); + setIcon(null); + } + setOpaque(true); + if (isSelected) + { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } + else + { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + setEnabled(list.isEnabled()); + setFont(list.getFont()); + + if (cellHasFocus) + setBorder(UIManager.getBorder("List.focusCellHighlightBorder")); + else + setBorder(noFocusBorder); + return this; + } + } + + /** + * A combo box model for the file selection filters. + */ + protected class FilterComboBoxModel + extends AbstractListModel + implements ComboBoxModel, PropertyChangeListener + { + + /** Storage for the filters in the model. */ + protected FileFilter[] filters; + + /** The index of the selected file filter. */ + private Object selected; + + /** + * Creates a new model. + */ + protected FilterComboBoxModel() + { + filters = new FileFilter[1]; + filters[0] = getAcceptAllFileFilter(getFileChooser()); + selected = filters[0]; + } + + /** + * Handles property changes. + * + * @param e the property change event. + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) + { + JFileChooser fc = getFileChooser(); + FileFilter[] choosableFilters = fc.getChoosableFileFilters(); + filters = choosableFilters; + fireContentsChanged(this, 0, filters.length); + selected = e.getNewValue(); + fireContentsChanged(this, -1, -1); + } + else if (e.getPropertyName().equals( + JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY)) + { + // repopulate list + JFileChooser fc = getFileChooser(); + FileFilter[] choosableFilters = fc.getChoosableFileFilters(); + filters = choosableFilters; + fireContentsChanged(this, 0, filters.length); + } + } + + /** + * Sets the selected filter. + * + * @param filter the filter (<code>null</code> ignored). + */ + public void setSelectedItem(Object filter) + { + if (filter != null) + { + selected = filter; + fireContentsChanged(this, -1, -1); + } + } + + /** + * Returns the selected file filter. + * + * @return The selected file filter. + */ + public Object getSelectedItem() + { + return selected; + } + + /** + * Returns the number of items in the model. + * + * @return The number of items in the model. + */ + public int getSize() + { + return filters.length; + } + + /** + * Returns the item at the specified index. + * + * @param index the item index. + * + * @return The item at the specified index. + */ + public Object getElementAt(int index) + { + return filters[index]; + } + + } + + /** + * A renderer for the items in the file filter combo box. + */ + public class FilterComboBoxRenderer + extends DefaultListCellRenderer + { + /** + * Creates a new renderer. + */ + public FilterComboBoxRenderer() + { + // Nothing to do here. + } + + /** + * Returns a component that can be used to paint the given value within + * the list. + * + * @param list the list. + * @param value the value (a {@link FileFilter}). + * @param index the item index. + * @param isSelected is the item selected? + * @param cellHasFocus does the list cell have focus? + * + * @return This component as the renderer. + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) + { + super.getListCellRendererComponent(list, value, index, isSelected, + cellHasFocus); + FileFilter filter = (FileFilter) value; + setText(filter.getDescription()); + return this; + } + } + + /** + * A listener for selection events in the file list. + * + * @see #createListSelectionListener(JFileChooser) + */ + class MetalFileChooserSelectionListener + implements ListSelectionListener + { + /** + * Creates a new <code>SelectionListener</code> object. + */ + protected MetalFileChooserSelectionListener() + { + // Do nothing here. + } + + /** + * Makes changes to different properties when + * a value has changed in the filechooser's selection. + * + * @param e - the list selection event that occured. + */ + public void valueChanged(ListSelectionEvent e) + { + File f = (File) fileList.getSelectedValue(); + if (f == null) + return; + JFileChooser filechooser = getFileChooser(); + if (! filechooser.isTraversable(f)) + filechooser.setSelectedFile(f); + else + filechooser.setSelectedFile(null); + } + } + + /** + * A mouse listener for the {@link JFileChooser}. + * This listener is used for editing filenames. + */ + protected class SingleClickListener + extends MouseAdapter + { + + /** Stores instance of the list */ + JList list; + + /** + * Stores the current file that is being edited. + * It is null if nothing is currently being edited. + */ + File editFile; + + /** The current file chooser. */ + JFileChooser fc; + + /** The last file selected. */ + Object lastSelected; + + /** The textfield used for editing. */ + JTextField editField; + + /** + * Creates a new listener. + * + * @param list the directory/file list. + */ + public SingleClickListener(JList list) + { + this.list = list; + editFile = null; + fc = getFileChooser(); + lastSelected = null; + startEditing = false; + } + + /** + * Receives notification of a mouse click event. + * + * @param e the event. + */ + public void mouseClicked(MouseEvent e) + { + if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) + { + int index = list.locationToIndex(e.getPoint()); + File[] sf = fc.getSelectedFiles(); + if ((!fc.isMultiSelectionEnabled() || (sf != null && sf.length <= 1)) + && index >= 0 && !startEditing && list.isSelectedIndex(index)) + { + Object tmp = list.getModel().getElementAt(index); + if (lastSelected != null && lastSelected.equals(tmp)) + editFile(index); + lastSelected = tmp; + } + else + completeEditing(); + } + else + completeEditing(); + } + + /** + * Sets up the text editor for the current file. + * + * @param index - + * the current index of the item in the list to be edited. + */ + void editFile(int index) + { + Rectangle bounds = list.getCellBounds(index, index); + list.scrollRectToVisible(bounds); + editFile = (File) list.getModel().getElementAt(index); + if (editFile.canWrite()) + { + startEditing = true; + editField = new JTextField(editFile.getName()); + editField.addActionListener(new EditingActionListener()); + + Icon icon = getFileView(fc).getIcon(editFile); + if (icon != null) + { + int padding = icon.getIconWidth() + 4; + bounds.x += padding; + bounds.width -= padding; + } + editField.setBounds(bounds); + + list.add(editField); + + editField.requestFocus(); + editField.selectAll(); + } + else + completeEditing(); + list.repaint(); + } + + /** + * Completes the editing. + */ + void completeEditing() + { + if (editField != null && editFile != null) + { + String text = editField.getText(); + if (text != null && text != "" && !text.equals(fc.getName(editFile))) + { + File f = fc.getFileSystemView(). + createFileObject(fc.getCurrentDirectory(), text); + if ( editFile.renameTo(f) ) + rescanCurrentDirectory(fc); + } + list.remove(editField); + } + startEditing = false; + editFile = null; + lastSelected = null; + editField = null; + list.repaint(); + } + + /** + * ActionListener for the editing text field. + */ + class EditingActionListener implements ActionListener + { + + /** + * This method is invoked when an action occurs. + * + * @param e - + * the <code>ActionEvent</code> that occurred + */ + public void actionPerformed(ActionEvent e) + { + if (editField != null) + completeEditing(); + } + } + } + + /** + * A mouse listener for the {@link JFileChooser}. + * This listener is used for the table + */ + private class TableClickListener extends MouseAdapter + { + + /** Stores instance of the table */ + JTable table; + + /** Stores instance of the file chooser */ + JFileChooser fc; + + /** The last selected file. */ + Object lastSelected; + + /** + * Stores the current file that is being edited. + * It is null if nothing is currently being edited. + */ + File editFile; + + /** The textfield used for editing. */ + JTextField editField; + + /** + * Creates a new listener. + * + * @param table the directory/file table + * @param fc the JFileChooser + */ + public TableClickListener(JTable table, JFileChooser fc) + { + this.table = table; + this.fc = fc; + lastSelected = fileList.getSelectedValue(); + setDirectorySelected(false); + startEditing = false; + editFile = null; + editField = null; + } + + /** + * Receives notification of a mouse click event. + * + * @param e the event. + */ + public void mouseClicked(MouseEvent e) + { + int row = table.getSelectedRow(); + Object selVal = fileList.getModel().getElementAt(row); + if (selVal == null) + return; + FileSystemView fsv = fc.getFileSystemView(); + if (e.getClickCount() == 1 && + selVal.equals(lastSelected) && + e.getButton() == MouseEvent.BUTTON1) + { + File[] sf = fc.getSelectedFiles(); + if ((!fc.isMultiSelectionEnabled() || (sf != null && sf.length <= 1)) + && !startEditing) + { + editFile = (File) selVal; + editFile(row); + } + } + else if (e.getClickCount() >= 2 && + selVal.equals(lastSelected)) + { + if (startEditing) + completeEditing(); + File f = fsv.createFileObject(lastSelected.toString()); + if (fc.isTraversable(f)) + { + fc.setCurrentDirectory(f); + fc.rescanCurrentDirectory(); + } + else + { + fc.setSelectedFile(f); + fc.approveSelection(); + closeDialog(); + } + } + else + { + if (startEditing) + completeEditing(); + String path = selVal.toString(); + File f = fsv.createFileObject(path); + fc.setSelectedFile(f); + if (fc.isTraversable(f)) + { + setDirectorySelected(true); + setDirectory(f); + } + else + { + setDirectorySelected(false); + setDirectory(null); + } + lastSelected = selVal; + if (f.isFile()) + setFileName(path.substring(path.lastIndexOf("/") + 1)); + else if (fc.getFileSelectionMode() != JFileChooser.FILES_ONLY) + setFileName(path); + } + fileTable.repaint(); + } + + /** + * Sets up the text editor for the current file. + * + * @param row - + * the current row of the item in the list to be edited. + */ + void editFile(int row) + { + Rectangle bounds = table.getCellRect(row, 0, true); + table.scrollRectToVisible(bounds); + if (editFile.canWrite()) + { + startEditing = true; + editField = new JTextField(editFile.getName()); + editField.addActionListener(new EditingActionListener()); + + // Need to adjust y pos + bounds.y = row * table.getRowHeight(); + editField.setBounds(bounds); + + table.add(editField); + + editField.requestFocus(); + editField.selectAll(); + } + else + completeEditing(); + table.repaint(); + } + + /** + * Completes the editing. + */ + void completeEditing() + { + if (editField != null && editFile != null) + { + String text = editField.getText(); + if (text != null && text != "" && !text.equals(fc.getName(editFile))) + if (editFile.renameTo(fc.getFileSystemView().createFileObject( + fc.getCurrentDirectory(), text))) + rescanCurrentDirectory(fc); + table.remove(editField); + } + startEditing = false; + editFile = null; + editField = null; + table.repaint(); + } + + /** + * ActionListener for the editing text field. + */ + class EditingActionListener implements ActionListener + { + + /** + * This method is invoked when an action occurs. + * + * @param e - + * the <code>ActionEvent</code> that occurred + */ + public void actionPerformed(ActionEvent e) + { + if (editField != null) + completeEditing(); + } + } + + /** + * Closes the dialog. + */ + public void closeDialog() + { + Window owner = SwingUtilities.windowForComponent(fc); + if (owner instanceof JDialog) + ((JDialog) owner).dispose(); + } + } + + /** The text for a label describing the directory combo box. */ + private String directoryLabel; + + private JComboBox directoryComboBox; + + /** The model for the directory combo box. */ + DirectoryComboBoxModel directoryModel; + + /** The text for a label describing the file text field. */ + private String fileLabel; + + /** The file name text field. */ + private JTextField fileTextField; + + /** The text for a label describing the filter combo box. */ + private String filterLabel; + + /** + * The top panel (contains the directory combo box and the control buttons). + */ + private JPanel topPanel; + + /** A panel containing the control buttons ('up', 'home' etc.). */ + private JPanel controls; + + /** + * The panel that contains the filename field and the filter combobox. + */ + private JPanel bottomPanel; + + /** + * The panel that contains the 'Open' (or 'Save') and 'Cancel' buttons. + */ + private JPanel buttonPanel; + + private JButton approveButton; + + /** The file list. */ + JList fileList; + + /** The file table. */ + JTable fileTable; + + /** The panel containing the file list. */ + JPanel fileListPanel; + + /** The panel containing the file table. */ + JPanel fileTablePanel; + + /** The filter combo box model. */ + private FilterComboBoxModel filterModel; + + /** The action map. */ + private ActionMap actionMap; + + /** True if currently in list view. */ + boolean listView; + + /** True if we can or have started editing a cell. */ + boolean startEditing; + + /** The scrollpane used for the table and list. */ + JScrollPane scrollPane; + + /** The text for the label when saving. */ + String save; + + /** The text for the label when opening a directory. */ + String look; + + /** The label for the file combo box. */ + JLabel dirLabel; + + /** Listeners. */ + ListSelectionListener listSelList; + MouseListener doubleClickList; + SingleClickListener singleClickList; + TableClickListener tableClickList; + + /** + * A factory method that returns a UI delegate for the specified + * component. + * + * @param c the component (which should be a {@link JFileChooser}). + */ + public static ComponentUI createUI(JComponent c) + { + JFileChooser chooser = (JFileChooser) c; + return new MetalFileChooserUI(chooser); + } + + /** + * Creates a new instance of this UI delegate. + * + * @param filechooser the file chooser component. + */ + public MetalFileChooserUI(JFileChooser filechooser) + { + super(filechooser); + bottomPanel = new JPanel(new GridLayout(3, 2)); + buttonPanel = new JPanel(); + } + + public void installUI(JComponent c) + { + super.installUI(c); + actionMap = createActionMap(); + } + + public void uninstallUI(JComponent c) + { + super.uninstallUI(c); + actionMap = null; + } + + /** + * Installs the sub-components of the file chooser. + * + * @param fc the file chooser component. + */ + public void installComponents(JFileChooser fc) + { + fc.setLayout(new BorderLayout()); + topPanel = new JPanel(new BorderLayout()); + dirLabel = new JLabel(directoryLabel); + topPanel.add(dirLabel, BorderLayout.WEST); + this.controls = new JPanel(); + addControlButtons(); + + JPanel dirPanel = new JPanel(new VerticalMidLayout()); + directoryModel = createDirectoryComboBoxModel(fc); + directoryComboBox = new JComboBox(directoryModel); + directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc)); + dirPanel.add(directoryComboBox); + topPanel.add(dirPanel); + topPanel.add(controls, BorderLayout.EAST); + topPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 0, 8)); + fc.add(topPanel, BorderLayout.NORTH); + + JPanel list = createList(fc); + list.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); + fc.add(list, BorderLayout.CENTER); + + JPanel bottomPanel = getBottomPanel(); + filterModel = createFilterComboBoxModel(); + JComboBox fileFilterCombo = new JComboBox(filterModel); + fileFilterCombo.setRenderer(createFilterComboBoxRenderer()); + + fileTextField = new JTextField(); + JPanel fileNamePanel = new JPanel(new VerticalMidLayout()); + fileNamePanel.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 5)); + fileNamePanel.add(fileTextField); + JPanel row1 = new JPanel(new BorderLayout()); + row1.add(new JLabel(this.fileLabel), BorderLayout.WEST); + row1.add(fileNamePanel); + bottomPanel.add(row1); + + JPanel row2 = new JPanel(new BorderLayout()); + row2.add(new JLabel(this.filterLabel), BorderLayout.WEST); + row2.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); + row2.add(fileFilterCombo); + bottomPanel.add(row2); + JPanel buttonPanel = new JPanel(new ButtonLayout()); + + approveButton = new JButton(getApproveSelectionAction()); + approveButton.setText(getApproveButtonText(fc)); + approveButton.setToolTipText(getApproveButtonToolTipText(fc)); + approveButton.setMnemonic(getApproveButtonMnemonic(fc)); + buttonPanel.add(approveButton); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(8, 0, 0, 0)); + + JButton cancelButton = new JButton(getCancelSelectionAction()); + cancelButton.setText(cancelButtonText); + cancelButton.setToolTipText(cancelButtonToolTipText); + cancelButton.setMnemonic(cancelButtonMnemonic); + buttonPanel.add(cancelButton); + bottomPanel.add(buttonPanel, BorderLayout.SOUTH); + bottomPanel.setBorder(BorderFactory.createEmptyBorder(0, 8, 8, 8)); + fc.add(bottomPanel, BorderLayout.SOUTH); + + fc.add(getAccessoryPanel(), BorderLayout.EAST); + } + + /** + * Uninstalls the components added by + * {@link #installComponents(JFileChooser)}. + * + * @param fc the file chooser. + */ + public void uninstallComponents(JFileChooser fc) + { + fc.remove(bottomPanel); + bottomPanel = null; + fc.remove(fileListPanel); + fc.remove(fileTablePanel); + fileTablePanel = null; + fileListPanel = null; + fc.remove(topPanel); + topPanel = null; + + directoryModel = null; + fileTextField = null; + directoryComboBox = null; + } + + /** + * Returns the panel that contains the 'Open' (or 'Save') and 'Cancel' + * buttons. + * + * @return The panel. + */ + protected JPanel getButtonPanel() + { + return buttonPanel; + } + + /** + * Creates and returns a new panel that will be used for the controls at + * the bottom of the file chooser. + * + * @return A new panel. + */ + protected JPanel getBottomPanel() + { + if (bottomPanel == null) + bottomPanel = new JPanel(new GridLayout(3, 2)); + return bottomPanel; + } + + /** + * Fetches localised strings for use by the labels and buttons on the + * file chooser. + * + * @param fc the file chooser. + */ + protected void installStrings(JFileChooser fc) + { + super.installStrings(fc); + look = "Look In: "; + save = "Save In: "; + if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) + directoryLabel = save; + else + directoryLabel = look; + + fileLabel = "File Name: "; + filterLabel = "Files of Type: "; + + this.cancelButtonMnemonic = 0; + this.cancelButtonText = "Cancel"; + this.cancelButtonToolTipText = "Abort file chooser dialog"; + + this.directoryOpenButtonMnemonic = 0; + this.directoryOpenButtonText = "Open"; + this.directoryOpenButtonToolTipText = "Open selected directory"; + + this.helpButtonMnemonic = 0; + this.helpButtonText = "Help"; + this.helpButtonToolTipText = "Filechooser help"; + + this.openButtonMnemonic = 0; + this.openButtonText = "Open"; + this.openButtonToolTipText = "Open selected file"; + + this.saveButtonMnemonic = 0; + this.saveButtonText = "Save"; + this.saveButtonToolTipText = "Save selected file"; + + this.updateButtonMnemonic = 0; + this.updateButtonText = "Update"; + this.updateButtonToolTipText = "Update directory listing"; + } + + /** + * Installs the listeners required. + * + * @param fc the file chooser. + */ + protected void installListeners(JFileChooser fc) + { + directoryComboBox.setAction(new DirectoryComboBoxAction()); + fc.addPropertyChangeListener(filterModel); + listSelList = createListSelectionListener(fc); + doubleClickList = this.createDoubleClickListener(fc, fileList); + singleClickList = new SingleClickListener(fileList); + fileList.addListSelectionListener(listSelList); + fileList.addMouseListener(doubleClickList); + fileList.addMouseListener(singleClickList); + super.installListeners(fc); + } + + protected void uninstallListeners(JFileChooser fc) + { + super.uninstallListeners(fc); + fc.removePropertyChangeListener(filterModel); + directoryComboBox.setAction(null); + fileList.removeListSelectionListener(listSelList); + fileList.removeMouseListener(doubleClickList); + fileList.removeMouseListener(singleClickList); + + if (fileTable != null) + fileTable.removeMouseListener(tableClickList); + } + + protected ActionMap getActionMap() + { + if (actionMap == null) + actionMap = createActionMap(); + return actionMap; + } + + /** + * Creates and returns an action map. + * + * @return The action map. + */ + protected ActionMap createActionMap() + { + ActionMap map = new ActionMap(); + map.put("approveSelection", getApproveSelectionAction()); + map.put("cancelSelection", getCancelSelectionAction()); + map.put("Go Up", getChangeToParentDirectoryAction()); + return map; + } + + /** + * Creates a panel containing a list of files. + * + * @param fc the file chooser. + * + * @return A panel. + */ + protected JPanel createList(JFileChooser fc) + { + if (fileList == null) + { + fileListPanel = new JPanel(new BorderLayout()); + fileList = new JList(getModel()); + scrollPane = new JScrollPane(fileList); + fileList.setLayoutOrientation(JList.VERTICAL_WRAP); + fileList.setCellRenderer(new FileRenderer()); + } + else + { + fileList.setModel(getModel()); + fileListPanel.removeAll(); + scrollPane.getViewport().setView(fileList); + } + fileListPanel.add(scrollPane); + // This size was determined using BeanShell and dumping the JFileChooser + // component hierarchy. Sun has an internal FilePane class in there, but + // that probably doesn't matter atm. + fileListPanel.setPreferredSize(new Dimension(405, 135)); + return fileListPanel; + } + + /** + * Creates a panel containing a table within a scroll pane. + * + * @param fc the file chooser. + * + * @return The details view. + */ + protected JPanel createDetailsView(JFileChooser fc) + { + fileTablePanel = new JPanel(new BorderLayout()); + + Object[] cols = new Object[] {"Name", "Size", "Modified"}; + Object[][] rows = new Object[fileList.getModel().getSize()][3]; + + fileTable = new JTable(new DefaultTableModel(rows, cols)); + + if (fc.isMultiSelectionEnabled()) + fileTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + else + fileTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + fileTable.setShowGrid(false); + fileTable.setColumnSelectionAllowed(false); + fileTable.setDefaultRenderer(Object.class, new TableFileRenderer()); + + tableClickList = new TableClickListener(fileTable, fc); + fileTable.addMouseListener(tableClickList); + + return updateTable(); + } + + /** + * Sets the values in the table, and puts it in the panel. + * + * @return the panel containing the table. + */ + JPanel updateTable() + { + DefaultTableModel mod = (DefaultTableModel) fileTable.getModel(); + ListModel lm = fileList.getModel(); + DateFormat dt = DateFormat.getDateTimeInstance(DateFormat.SHORT, + DateFormat.SHORT); + File curr = null; + int size = lm.getSize(); + int rc = mod.getRowCount(); + + // If there are not enough rows + for (int x = rc; x < size; x++) + mod.addRow(new Object[3]); + + for (int i = 0; i < size; i++) + { + curr = (File) lm.getElementAt(i); + fileTable.setValueAt(curr.getName(), i, 0); + fileTable.setValueAt(formatSize(curr.length()), i, 1); + fileTable.setValueAt(dt.format(new Date(curr.lastModified())), i, 2); + } + + // If there are too many rows + while (rc > size) + mod.removeRow(--rc); + + scrollPane.getViewport().setView(fileTable); + scrollPane.setColumnHeaderView(fileTable.getTableHeader()); + + fileTablePanel.removeAll(); + fileTablePanel.add(scrollPane); + + return fileTablePanel; + } + + /** + * Formats bytes into the appropriate size. + * + * @param bytes the number of bytes to convert + * @return a string representation of the size + */ + private String formatSize(long bytes) + { + NumberFormat nf = NumberFormat.getNumberInstance(); + long mb = (long) Math.pow(2, 20); + long kb = (long) Math.pow(2, 10); + long gb = (long) Math.pow(2, 30); + double size = 0; + String id = ""; + + if ((bytes / gb) >= 1) + { + size = (double) bytes / (double) gb; + id = "GB"; + } + else if ((bytes / mb) >= 1) + { + size = (double) bytes / (double) mb; + id = "MB"; + } + else if ((bytes / kb) >= 1) + { + size = (double) bytes / (double) kb; + id = "KB"; + } + else + { + size = bytes; + id = "Bytes"; + } + + return nf.format(size) + " " + id; + } + /** + * Creates a listener that monitors selections in the directory/file list + * and keeps the {@link JFileChooser} component up to date. + * + * @param fc the file chooser. + * + * @return The listener. + * + * @see #installListeners(JFileChooser) + */ + public ListSelectionListener createListSelectionListener(JFileChooser fc) + { + return new MetalFileChooserSelectionListener(); + } + + /** + * Returns the preferred size for the file chooser component. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + Dimension tp = topPanel.getPreferredSize(); + Dimension bp = bottomPanel.getPreferredSize(); + Dimension fl = fileListPanel.getPreferredSize(); + return new Dimension(fl.width, tp.height + bp.height + fl.height); + } + + /** + * Returns the minimum size for the file chooser component. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + Dimension tp = topPanel.getMinimumSize(); + Dimension bp = bottomPanel.getMinimumSize(); + Dimension fl = fileListPanel.getMinimumSize(); + return new Dimension(fl.width, tp.height + bp.height + fl.height); + } + + /** + * Returns the maximum size for the file chooser component. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + /** + * Creates a property change listener that monitors the {@link JFileChooser} + * for property change events and updates the component display accordingly. + * + * @param fc the file chooser. + * + * @return The property change listener. + * + * @see #installListeners(JFileChooser) + */ + public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) + { + return new MetalFileChooserPropertyChangeListener(); + } + + /** + * Creates and returns a new instance of {@link DirectoryComboBoxModel}. + * + * @return A new instance of {@link DirectoryComboBoxModel}. + */ + protected MetalFileChooserUI.DirectoryComboBoxModel + createDirectoryComboBoxModel(JFileChooser fc) + { + return new DirectoryComboBoxModel(); + } + + /** + * Creates a new instance of the renderer used in the directory + * combo box. + * + * @param fc the file chooser. + * + * @return The renderer. + */ + protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer( + JFileChooser fc) + { + return new DirectoryComboBoxRenderer(fc); + } + + /** + * Creates and returns a new instance of {@link FilterComboBoxModel}. + * + * @return A new instance of {@link FilterComboBoxModel}. + */ + protected FilterComboBoxModel createFilterComboBoxModel() + { + return new FilterComboBoxModel(); + } + + /** + * Creates and returns a new instance of {@link FilterComboBoxRenderer}. + * + * @return A new instance of {@link FilterComboBoxRenderer}. + */ + protected MetalFileChooserUI.FilterComboBoxRenderer + createFilterComboBoxRenderer() + { + return new FilterComboBoxRenderer(); + } + + /** + * Adds the control buttons ('up', 'home' etc.) to the panel. + */ + protected void addControlButtons() + { + JButton upButton = new JButton(getChangeToParentDirectoryAction()); + upButton.setText(null); + upButton.setIcon(this.upFolderIcon); + upButton.setMargin(new Insets(0, 0, 0, 0)); + controls.add(upButton); + + JButton homeButton = new JButton(getGoHomeAction()); + homeButton.setText(null); + homeButton.setIcon(this.homeFolderIcon); + homeButton.setMargin(new Insets(0, 0, 0, 0)); + controls.add(homeButton); + + JButton newFolderButton = new JButton(getNewFolderAction()); + newFolderButton.setText(null); + newFolderButton.setIcon(this.newFolderIcon); + newFolderButton.setMargin(new Insets(0, 0, 0, 0)); + controls.add(newFolderButton); + + JToggleButton listButton = new JToggleButton(this.listViewIcon); + listButton.setMargin(new Insets(0, 0, 0, 0)); + listButton.addActionListener(new ListViewActionListener()); + listButton.setSelected(true); + listView = true; + controls.add(listButton); + + JToggleButton detailButton = new JToggleButton(this.detailsViewIcon); + detailButton.setMargin(new Insets(0, 0, 0, 0)); + detailButton.addActionListener(new DetailViewActionListener()); + detailButton.setSelected(false); + controls.add(detailButton); + + ButtonGroup buttonGroup = new ButtonGroup(); + buttonGroup.add(listButton); + buttonGroup.add(detailButton); + } + + /** + * Removes all the buttons from the control panel. + */ + protected void removeControlButtons() + { + controls.removeAll(); + controls.revalidate(); + controls.repaint(); + } + + /** + * Updates the current directory. + * + * @param fc the file chooser to update. + */ + public void rescanCurrentDirectory(JFileChooser fc) + { + directoryModel.setSelectedItem(fc.getCurrentDirectory()); + getModel().validateFileCache(); + if (!listView) + updateTable(); + else + createList(fc); + } + + /** + * Returns the file name in the text field. + * + * @return The file name. + */ + public String getFileName() + { + String result = null; + if (fileTextField != null) + result = fileTextField.getText(); + return result; + } + + /** + * Sets the file name in the text field. + * + * @param filename the file name. + */ + public void setFileName(String filename) + { + fileTextField.setText(filename); + } + + /** + * DOCUMENT ME!! + * + * @param e - DOCUMENT ME! + */ + public void valueChanged(ListSelectionEvent e) + { + // FIXME: Not sure what we should be doing here, if anything. + } + + /** + * Returns the approve button. + * + * @return The approve button. + */ + protected JButton getApproveButton(JFileChooser fc) + { + return approveButton; + } + + /** + * A layout manager that is used to arrange the subcomponents of the + * {@link JFileChooser}. + */ + class VerticalMidLayout implements LayoutManager + { + /** + * Performs the layout. + * + * @param parent the container. + */ + public void layoutContainer(Container parent) + { + int count = parent.getComponentCount(); + if (count > 0) + { + Insets insets = parent.getInsets(); + Component c = parent.getComponent(0); + Dimension prefSize = c.getPreferredSize(); + int h = parent.getHeight() - insets.top - insets.bottom; + int adj = Math.max(0, (h - prefSize.height) / 2); + c.setBounds(insets.left, insets.top + adj, parent.getWidth() + - insets.left - insets.right, + (int) Math.min(prefSize.getHeight(), h)); + } + } + + /** + * Returns the minimum layout size. + * + * @param parent the container. + * + * @return The minimum layout size. + */ + public Dimension minimumLayoutSize(Container parent) + { + return preferredLayoutSize(parent); + } + + /** + * Returns the preferred layout size. + * + * @param parent the container. + * + * @return The preferred layout size. + */ + public Dimension preferredLayoutSize(Container parent) + { + if (parent.getComponentCount() > 0) + { + return parent.getComponent(0).getPreferredSize(); + } + else return null; + } + + /** + * This layout manager does not need to track components, so this + * method does nothing. + * + * @param name the name the component is associated with. + * @param component the component. + */ + public void addLayoutComponent(String name, Component component) + { + // do nothing + } + + /** + * This layout manager does not need to track components, so this + * method does nothing. + * + * @param component the component. + */ + public void removeLayoutComponent(Component component) + { + // do nothing + } + } + + /** + * A layout manager that is used to arrange buttons for the + * {@link JFileChooser}. + */ + class ButtonLayout implements LayoutManager + { + static final int GAP = 4; + + /** + * Performs the layout. + * + * @param parent the container. + */ + public void layoutContainer(Container parent) + { + int count = parent.getComponentCount(); + if (count > 0) + { + // first find the widest button + int maxW = 0; + for (int i = 0; i < count; i++) + { + Component c = parent.getComponent(i); + Dimension prefSize = c.getPreferredSize(); + maxW = Math.max(prefSize.width, maxW); + } + + // then position the buttons + Insets insets = parent.getInsets(); + int availableH = parent.getHeight() - insets.top - insets.bottom; + int currentX = parent.getWidth() - insets.right; + for (int i = count - 1; i >= 0; i--) + { + Component c = parent.getComponent(i); + Dimension prefSize = c.getPreferredSize(); + int adj = Math.max(0, (availableH - prefSize.height) / 2); + currentX = currentX - prefSize.width; + c.setBounds(currentX, insets.top + adj, prefSize.width, + (int) Math.min(prefSize.getHeight(), availableH)); + currentX = currentX - GAP; + } + } + } + + /** + * Returns the minimum layout size. + * + * @param parent the container. + * + * @return The minimum layout size. + */ + public Dimension minimumLayoutSize(Container parent) + { + return preferredLayoutSize(parent); + } + + /** + * Returns the preferred layout size. + * + * @param parent the container. + * + * @return The preferred layout size. + */ + public Dimension preferredLayoutSize(Container parent) + { + Insets insets = parent.getInsets(); + int maxW = 0; + int maxH = 0; + int count = parent.getComponentCount(); + if (count > 0) + { + for (int i = 0; i < count; i++) + { + Component c = parent.getComponent(i); + Dimension d = c.getPreferredSize(); + maxW = Math.max(d.width, maxW); + maxH = Math.max(d.height, maxH); + } + } + return new Dimension(maxW * count + GAP * (count - 1) + insets.left + + insets.right, maxH + insets.top + insets.bottom); + } + + /** + * This layout manager does not need to track components, so this + * method does nothing. + * + * @param name the name the component is associated with. + * @param component the component. + */ + public void addLayoutComponent(String name, Component component) + { + // do nothing + } + + /** + * This layout manager does not need to track components, so this + * method does nothing. + * + * @param component the component. + */ + public void removeLayoutComponent(Component component) + { + // do nothing + } + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java b/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java new file mode 100644 index 000000000..5382577c3 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java @@ -0,0 +1,2626 @@ +/* MetalIconFactory.java -- + Copyright (C) 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.io.Serializable; + +import javax.swing.AbstractButton; +import javax.swing.Icon; +import javax.swing.JCheckBox; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFileChooser; +import javax.swing.JInternalFrame; +import javax.swing.JRadioButton; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.JSlider; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.plaf.UIResource; + + +/** + * Creates icons for the {@link MetalLookAndFeel}. + */ +public class MetalIconFactory implements Serializable +{ + + /** A constant representing "dark". */ + public static final boolean DARK = false; + + /** A constant representing "light". */ + public static final boolean LIGHT = true; + + /** A shared instance of the MenuArrowIcon. */ + private static Icon menuArrow; + + /** A shared instance of the MenuItemArrowIcon. */ + private static Icon menuItemArrow; + + /** + * An icon displayed for {@link JCheckBoxMenuItem} components. + */ + private static class CheckBoxMenuItemIcon + implements Icon, UIResource, Serializable + { + /** + * Creates a new icon instance. + */ + public CheckBoxMenuItemIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon (10 pixels). + */ + public int getIconWidth() + { + return 10; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon (10 pixels). + */ + public int getIconHeight() + { + return 10; + } + + /** + * Paints the icon. + * + * @param c the component. + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + JCheckBoxMenuItem item = (JCheckBoxMenuItem) c; + + if (item.isArmed()) + g.setColor(MetalLookAndFeel.getBlack()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(x, y, x + 8, y); + g.drawLine(x, y + 1, x, y + 8); + g.drawLine(x + 2, y + 8, x + 8, y + 8); + g.drawLine(x + 8, y + 2, x + 8, y + 7); + + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x + 1, y + 1, x + 7, y + 1); + g.drawLine(x + 1, y + 2, x + 1, y + 7); + g.drawLine(x + 1, y + 9, x + 9, y + 9); + g.drawLine(x + 9, y + 1, x + 9, y + 8); + + // if the item is selected, we should draw a tick + if (item.isSelected()) + { + g.setColor(MetalLookAndFeel.getBlack()); + g.fillRect(x + 2, y + 2, 2, 5); + for (int i = 0; i < 6; i++) + g.drawLine(x + 8 - i, y + i, x + 9 - i, y + i); + } + + } + } + + /** + * An icon used for the "detail view" button on a {@link JFileChooser} under + * the {@link MetalLookAndFeel}. + * + * @see MetalIconFactory#getFileChooserDetailViewIcon() + */ + private static class FileChooserDetailViewIcon + implements Icon, UIResource, Serializable + { + + /** + * Creates a new icon. + */ + public FileChooserDetailViewIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 18; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 18; + } + + /** + * Paints the icon using colors from the {@link MetalLookAndFeel}. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate for the top-left of the icon. + * @param y the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + g.setColor(MetalLookAndFeel.getBlack()); + + // file 1 outline + g.drawLine(x + 2, y + 2, x + 5, y + 2); + g.drawLine(x + 6, y + 3, x + 6, y + 7); + g.drawLine(x + 2, y + 7, x + 6, y + 7); + g.drawLine(x + 2, y + 2, x + 2, y + 7); + + // file 2 outline + g.drawLine(x + 2, y + 10, x + 5, y + 10); + g.drawLine(x + 6, y + 11, x + 6, y + 15); + g.drawLine(x + 2, y + 15, x + 6, y + 15); + g.drawLine(x + 2, y + 10, x + 2, y + 15); + + // detail lines + g.drawLine(x + 8, y + 5, x + 15, y + 5); + g.drawLine(x + 8, y + 13, x + 15, y + 13); + + // fill files + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.fillRect(x + 3, y + 3, 3, 4); + g.fillRect(x + 3, y + 11, 3, 4); + + // highlight files + g.setColor(MetalLookAndFeel.getPrimaryControlHighlight()); + g.drawLine(x + 4, y + 4, x + 4, y + 5); + g.drawLine(x + 4, y + 12, x + 4, y + 13); + + g.setColor(savedColor); + } + } + + /** + * An icon used for the "home folder" button on a {@link JFileChooser} under + * the {@link MetalLookAndFeel}. + * + * @see MetalIconFactory#getFileChooserHomeFolderIcon() + */ + private static class FileChooserHomeFolderIcon + implements Icon, UIResource, Serializable + { + + /** + * Creates a new icon. + */ + public FileChooserHomeFolderIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 18; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 18; + } + + /** + * Paints the icon using colors from the {@link MetalLookAndFeel}. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate for the top-left of the icon. + * @param y the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + g.setColor(MetalLookAndFeel.getBlack()); + + // roof + g.drawLine(x + 1, y + 8, x + 8, y + 1); + g.drawLine(x + 8, y + 1, x + 15, y + 8); + + // base of house + g.drawLine(x + 3, y + 6, x + 3, y + 15); + g.drawLine(x + 3, y + 15, x + 13, y + 15); + g.drawLine(x + 13, y + 6, x + 13, y + 15); + + // door frame + g.drawLine(x + 6, y + 9, x + 6, y + 15); + g.drawLine(x + 6, y + 9, x + 10, y + 9); + g.drawLine(x + 10, y + 9, x + 10, y + 15); + + // chimney + g.drawLine(x + 11, y + 2, x + 11, y + 4); + g.drawLine(x + 12, y + 2, x + 12, y + 5); + + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // roof paint + int xx = x + 8; + for (int i = 0; i < 4; i++) + g.drawLine(xx - i, y + 2 + i, xx + i, y + 2 + i); + g.fillRect(x + 4, y + 6, 9, 2); + + // door knob + g.drawLine(x + 9, y + 12, x + 9, y + 12); + + // house paint + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.drawLine(x + 4, y + 8, x + 12, y + 8); + g.fillRect(x + 4, y + 9, 2, 6); + g.fillRect(x + 11, y + 9, 2, 6); + + g.setColor(savedColor); + } + } + + /** + * An icon used for the "list view" button on a {@link JFileChooser} under + * the {@link MetalLookAndFeel}. + * + * @see MetalIconFactory#getFileChooserListViewIcon() + */ + private static class FileChooserListViewIcon + implements Icon, UIResource, Serializable + { + /** + * Creates a new icon. + */ + public FileChooserListViewIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 18; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 18; + } + + /** + * Paints the icon using colors from the {@link MetalLookAndFeel}. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate for the top-left of the icon. + * @param y the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + g.setColor(MetalLookAndFeel.getBlack()); + + // file 1 outline + g.drawLine(x + 2, y + 2, x + 5, y + 2); + g.drawLine(x + 6, y + 3, x + 6, y + 7); + g.drawLine(x + 2, y + 7, x + 6, y + 7); + g.drawLine(x + 2, y + 2, x + 2, y + 7); + + // file 2 outline + g.drawLine(x + 2, y + 10, x + 5, y + 10); + g.drawLine(x + 6, y + 11, x + 6, y + 15); + g.drawLine(x + 2, y + 15, x + 6, y + 15); + g.drawLine(x + 2, y + 10, x + 2, y + 15); + + // file 3 outline + g.drawLine(x + 10, y + 2, x + 13, y + 2); + g.drawLine(x + 14, y + 3, x + 14, y + 7); + g.drawLine(x + 10, y + 7, x + 14, y + 7); + g.drawLine(x + 10, y + 2, x + 10, y + 7); + + // file 4 outline + g.drawLine(x + 10, y + 10, x + 13, y + 10); + g.drawLine(x + 14, y + 11, x + 14, y + 15); + g.drawLine(x + 10, y + 15, x + 14, y + 15); + g.drawLine(x + 10, y + 10, x + 10, y + 15); + + g.drawLine(x + 8, y + 5, x + 8, y + 5); + g.drawLine(x + 8, y + 13, x + 8, y + 13); + g.drawLine(x + 16, y + 5, x + 16, y + 5); + g.drawLine(x + 16, y + 13, x + 16, y + 13); + + // fill files + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.fillRect(x + 3, y + 3, 3, 4); + g.fillRect(x + 3, y + 11, 3, 4); + g.fillRect(x + 11, y + 3, 3, 4); + g.fillRect(x + 11, y + 11, 3, 4); + + // highlight files + g.setColor(MetalLookAndFeel.getPrimaryControlHighlight()); + g.drawLine(x + 4, y + 4, x + 4, y + 5); + g.drawLine(x + 4, y + 12, x + 4, y + 13); + g.drawLine(x + 12, y + 4, x + 12, y + 5); + g.drawLine(x + 12, y + 12, x + 12, y + 13); + + g.setColor(savedColor); + } + } + + /** + * An icon used for the "new folder" button on a {@link JFileChooser} under + * the {@link MetalLookAndFeel}. + * + * @see MetalIconFactory#getFileChooserNewFolderIcon() + */ + private static class FileChooserNewFolderIcon + implements Icon, UIResource, Serializable + { + /** + * Creates a new icon. + */ + public FileChooserNewFolderIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 18; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 18; + } + + /** + * Paints the icon using colors from the {@link MetalLookAndFeel}. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate for the top-left of the icon. + * @param y the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + g.setColor(MetalLookAndFeel.getBlack()); + + g.drawLine(x + 2, y + 5, x + 9, y + 5); + g.drawLine(x + 10, y + 6, x + 15, y + 6); + g.drawLine(x + 15, y + 5, x + 15, y + 14); + g.drawLine(x + 2, y + 14, x + 15, y + 14); + g.drawLine(x + 1, y + 6, x + 1, y + 14); + + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + g.drawLine(x + 11, y + 3, x + 15, y + 3); + g.drawLine(x + 10, y + 4, x + 15, y + 4); + + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.fillRect(x + 3, y + 7, 7, 7); + g.fillRect(x + 10, y + 8, 5, 6); + g.drawLine(x + 10, y + 5, x + 14, y + 5); + + g.setColor(MetalLookAndFeel.getPrimaryControlHighlight()); + g.drawLine(x + 10, y + 7, x + 14, y + 7); + g.drawLine(x + 2, y + 6, x + 9, y + 6); + g.drawLine(x + 2, y + 6, x + 2, y + 13); + g.setColor(savedColor); + } + } + + /** + * An icon used for the "up folder" button on a {@link JFileChooser} under + * the {@link MetalLookAndFeel}. + * + * @see MetalIconFactory#getFileChooserNewFolderIcon() + */ + private static class FileChooserUpFolderIcon extends FileChooserNewFolderIcon + { + /** + * Creates a new icon. + */ + public FileChooserUpFolderIcon() + { + // Nothing to do here. + } + + /** + * Paints the icon using colors from the {@link MetalLookAndFeel}. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate for the top-left of the icon. + * @param y the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + + // draw the folder + super.paintIcon(c, g, x, y); + + // now draw the up arrow + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 8, y + 9, x + 8, y + 16); + int xx = x + 8; + for (int i = 0; i < 4; i++) + g.drawLine(xx - i, y + 9 + i, xx + i, y + 9 + i); + g.setColor(savedColor); + } + } + + /** + * An icon representing a file (drawn as a piece of paper with the top-right + * corner turned down). + */ + public static class FileIcon16 implements Icon, Serializable + { + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 16; + } + + /** + * Returns the height of the icon, in pixels. The height returned is + * <code>16</code> plus the value returned by + * {@link #getAdditionalHeight()}. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 16 + getAdditionalHeight(); + } + + /** + * Paints the icon at the location (x, y). + * + * @param c the component. + * @param g the graphics context. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + y = y + getShift(); + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x, y, x + 9, y); + g.drawLine(x, y + 1, x, y + 15); + g.drawLine(x, y + 15, x + 12, y + 15); + g.drawLine(x + 12, y + 15, x + 12, y + 6); + g.drawLine(x + 12, y + 6, x + 9, y); + + g.drawLine(x + 7, y + 2, x + 11, y + 6); + g.drawLine(x + 8, y + 1, x + 9, y + 1); + + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.drawLine(x + 1, y + 1, x + 7, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + 14); + g.drawLine(x + 1, y + 14, x + 11, y + 14); + g.drawLine(x + 11, y + 14, x + 11, y + 7); + g.drawLine(x + 8, y + 2, x + 10, y + 4); + } + + /** + * Returns the additional height for the icon. The + * {@link #getIconHeight()} method adds this value to the icon height it + * returns. Subclasses can override this method to adjust the icon height. + * + * @return The additional height (<code>0</code> unless overridden). + */ + public int getAdditionalHeight() + { + return 0; + } + + /** + * Returns the vertical shift, in pixels, applied when painting the icon. + * The default value is zero, but subclasses may override this (for + * example, see {@link TreeLeafIcon}). + * + * @return The shift. + */ + public int getShift() + { + return 0; + } + + } + + /** + * An icon representing a folder. + */ + public static class FolderIcon16 implements Icon, Serializable + { + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 16; + } + + /** + * Returns the height of the icon, in pixels. The height returned is + * <code>16</code> plus the value returned by + * {@link #getAdditionalHeight()}. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 16 + getAdditionalHeight(); + } + + /** + * Paints the icon at the location (x, y). + * + * @param c the component. + * @param g the graphics device. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + y = y + getShift(); + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x, y + 6, x, y + 15); + g.drawLine(x, y + 15, x + 15, y + 15); + g.drawLine(x + 15, y + 15, x + 15, y + 5); + g.drawLine(x + 14, y + 6, x + 9, y + 6); + g.drawLine(x + 8, y + 5, x + 1, y + 5); + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.fillRect(x + 2, y + 7, 7, 8); + g.fillRect(x + 9, y + 8, 6, 7); + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + g.drawLine(x + 9, y + 5, x + 14, y + 5); + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + g.drawLine(x + 9, y + 4, x + 15, y + 4); + g.drawLine(x + 10, y + 3, x + 15, y + 3); + } + + /** + * Returns the additional height for the icon. The + * {@link #getIconHeight()} method adds this value to the icon height it + * returns. Subclasses can override this method to adjust the icon height. + * + * @return The additional height (<code>0</code> unless overridden). + */ + public int getAdditionalHeight() + { + return 0; + } + + /** + * Returns the vertical shift, in pixels, applied when painting the icon. + * The default value is zero, but subclasses may override this (for + * example, see {@link TreeFolderIcon}). + * + * @return The shift. + */ + public int getShift() + { + return 0; + } + + } + + /** + * An icon used by the {@link MetalInternalFrameUI} class when the frame + * is displayed as a palette. + * + * @since 1.3 + */ + public static class PaletteCloseIcon + implements Icon, Serializable, UIResource + { + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 7; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 7; + } + + /** + * Paints the icon using colors from the {@link MetalLookAndFeel}. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate for the top-left of the icon. + * @param y the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + AbstractButton button = (AbstractButton) c; + if (button.getModel().isPressed()) + g.setColor(MetalLookAndFeel.getBlack()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.fillRect(x + 2, y + 2, 3, 3); + g.drawLine(x + 1, y, x + 1, y + 2); + g.drawLine(x, y + 1, x + 2, y + 1); + g.drawLine(x + 5, y, x + 5, y + 2); + g.drawLine(x + 4, y + 1, x + 6, y + 1); + g.drawLine(x + 1, y + 4, x + 1, y + 6); + g.drawLine(x, y + 5, x + 2, y + 5); + g.drawLine(x + 5, y + 4, x + 5, y + 6); + g.drawLine(x + 4, y + 5, x + 6, y + 5); + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(x + 2, y + 6, x + 3, y + 5); + g.drawLine(x + 5, y + 3, x + 6, y + 2); + g.drawLine(x + 6, y + 6, x + 6, y + 6); + g.setColor(savedColor); + } + } + + /** + * An {@link Icon} implementation for {@link JCheckBox}es in the + * Metal Look & Feel. + * + * @author Roman Kennke (roman@kennke.org) + */ + static class RadioButtonIcon implements Icon, UIResource, Serializable + { + + /** + * This is used as a mask when painting the gradient. See + * {@link MetalUtils#paintGradient(java.awt.Graphics, int, int, int, int, + * float, float, java.awt.Color, java.awt.Color, java.awt.Color, int, + * int[][])} for details. + */ + private static int[][] gradientMask = new int[][] {{3, 7}, {1, 9}, {1, 9}, + {0, 10}, {0, 10}, {0, 10}, + {0, 10}, {1, 9}, {1, 9}, + {3, 7}}; + + /** + * Returns the width of the icon in pixels. + * + * @return the width of the icon in pixels + */ + public int getIconWidth() + { + return 13; + } + + /** + * Returns the height of the icon in pixels. + * + * @return the height of the icon in pixels + */ + public int getIconHeight() + { + return 13; + } + + /** + * Paints the icon, taking into account whether or not the component is + * enabled, selected and/or armed. + * + * @param c the Component to draw on (must be an instance of + * {@link JRadioButton}) + * @param g the Graphics context to draw with + * @param x the X position + * @param y the Y position + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + if (UIManager.get("RadioButton.gradient") != null) + MetalUtils.paintGradient(g, x + 2, y + 2, 8, 8, + SwingConstants.VERTICAL, "RadioButton.gradient", + gradientMask); + + Color savedColor = g.getColor(); + JRadioButton b = (JRadioButton) c; + + // draw outer circle + if (b.isEnabled()) + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + else + g.setColor(MetalLookAndFeel.getControlDisabled()); + g.drawLine(x + 2, y + 1, x + 3, y + 1); + g.drawLine(x + 4, y, x + 7, y); + g.drawLine(x + 8, y + 1, x + 9, y + 1); + g.drawLine(x + 10, y + 2, x + 10, y + 3); + g.drawLine(x + 11, y + 4, x + 11, y + 7); + g.drawLine(x + 10, y + 8, x + 10, y + 9); + g.drawLine(x + 8, y + 10, x + 9, y + 10); + g.drawLine(x + 4, y + 11, x + 7, y + 11); + g.drawLine(x + 2, y + 10, x + 3, y + 10); + g.drawLine(x + 1, y + 9, x + 1, y + 8); + g.drawLine(x, y + 7, x, y + 4); + g.drawLine(x + 1, y + 2, x + 1, y + 3); + + if (b.getModel().isArmed()) + { + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x + 4, y + 1, x + 7, y + 1); + g.drawLine(x + 4, y + 10, x + 7, y + 10); + g.drawLine(x + 1, y + 4, x + 1, y + 7); + g.drawLine(x + 10, y + 4, x + 10, y + 7); + g.fillRect(x + 2, y + 2, 8, 8); + } + else + { + // only draw inner highlight if not filled + if (b.isEnabled()) + { + g.setColor(MetalLookAndFeel.getWhite()); + + g.drawLine(x + 2, y + 8, x + 2, y + 9); + g.drawLine(x + 1, y + 4, x + 1, y + 7); + g.drawLine(x + 2, y + 2, x + 2, y + 3); + g.drawLine(x + 3, y + 2, x + 3, y + 2); + g.drawLine(x + 4, y + 1, x + 7, y + 1); + g.drawLine(x + 8, y + 2, x + 9, y + 2); + } + } + + // draw outer highlight + if (b.isEnabled()) + { + g.setColor(MetalLookAndFeel.getWhite()); + + // outer + g.drawLine(x + 10, y + 1, x + 10, y + 1); + g.drawLine(x + 11, y + 2, x + 11, y + 3); + g.drawLine(x + 12, y + 4, x + 12, y + 7); + g.drawLine(x + 11, y + 8, x + 11, y + 9); + g.drawLine(x + 10, y + 10, x + 10, y + 10); + g.drawLine(x + 8, y + 11, x + 9, y + 11); + g.drawLine(x + 4, y + 12, x + 7, y + 12); + g.drawLine(x + 2, y + 11, x + 3, y + 11); + } + + if (b.isSelected()) + { + if (b.isEnabled()) + g.setColor(MetalLookAndFeel.getBlack()); + else + g.setColor(MetalLookAndFeel.getControlDisabled()); + g.drawLine(x + 4, y + 3, x + 7, y + 3); + g.fillRect(x + 3, y + 4, 6, 4); + g.drawLine(x + 4, y + 8, x + 7, y + 8); + } + g.setColor(savedColor); + } + } + + /** + * An icon displayed for {@link JRadioButtonMenuItem} components. + */ + private static class RadioButtonMenuItemIcon + implements Icon, UIResource, Serializable + { + /** + * Creates a new icon instance. + */ + public RadioButtonMenuItemIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 10; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 10; + } + + /** + * Paints the icon. + * + * @param c the component. + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + JRadioButtonMenuItem item = (JRadioButtonMenuItem) c; + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 2, y, x + 6, y); + g.drawLine(x + 7, y + 1, x + 7, y + 1); + g.drawLine(x + 8, y + 2, x + 8, y + 6); + g.drawLine(x + 7, y + 7, x + 7, y + 7); + g.drawLine(x + 2, y + 8, x + 6, y + 8); + g.drawLine(x + 1, y + 7, x + 1, y + 7); + g.drawLine(x, y + 2, x, y + 6); + g.drawLine(x + 1, y + 1, x + 1, y + 1); + + if (item.isSelected()) + { + g.drawLine(x + 3, y + 2, x + 5, y + 2); + g.fillRect(x + 2, y + 3, 5, 3); + g.drawLine(x + 3, y + 6, x + 5, y + 6); + } + + // highlight + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(x + 3, y + 1, x + 6, y + 1); + g.drawLine(x + 8, y + 1, x + 8, y + 1); + g.drawLine(x + 9, y + 2, x + 9, y + 7); + g.drawLine(x + 8, y + 8, x + 8, y + 8); + g.drawLine(x + 2, y + 9, x + 7, y + 9); + g.drawLine(x + 1, y + 8, x + 1, y + 8); + g.drawLine(x + 1, y + 3, x + 1, y + 6); + g.drawLine(x + 2, y + 2, x + 2, y + 2); + g.setColor(savedColor); + } + } + + /** + * The icon used to display the thumb control on a horizontally oriented + * {@link JSlider} component. + */ + private static class HorizontalSliderThumbIcon + implements Icon, UIResource, Serializable + { + + /** + * This mask is used to paint the gradient in the shape of the thumb. + */ + int[][] gradientMask = new int[][] { {0, 12}, {0, 12}, {0, 12}, {0, 12}, + {0, 12}, {0, 12}, {0, 12}, {1, 11}, + {2, 10}, {3, 9}, {4, 8}, {5, 7}, + {6, 6}}; + + /** + * Creates a new instance. + */ + public HorizontalSliderThumbIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 15; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 16; + } + + /** + * Paints the icon, taking into account whether or not the component has + * the focus. + * + * @param c the component. + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + boolean enabled = false; + boolean focus = false; + if (c != null) + { + enabled = c.isEnabled(); + focus = c.hasFocus(); + } + + // draw the outline + if (enabled) + g.setColor(MetalLookAndFeel.getBlack()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(x + 1, y, x + 13, y); + g.drawLine(x + 14, y + 1, x + 14, y + 7); + g.drawLine(x + 14, y + 8, x + 7, y + 15); + g.drawLine(x + 6, y + 14, x, y + 8); + g.drawLine(x, y + 7, x, y + 1); + +// The following is commented out until the masking for the gradient painting +// is working correctly +// // Fill the icon. +// if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme +// && enabled) +// { +// String gradient; +// if (focus) +// gradient = "Slider.focusGradient"; +// else +// gradient = "Slider.gradient"; +// MetalUtils.paintGradient(g, x + 1, y + 2, 12, 13, +// SwingConstants.VERTICAL, gradient, +// gradientMask); +// } +// else + { + if (focus) + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(x + 1, y + 2, 13, 7); + g.drawLine(x + 2, y + 9, x + 12, y + 9); + g.drawLine(x + 3, y + 10, x + 11, y + 10); + g.drawLine(x + 4, y + 11, x + 10, y + 11); + g.drawLine(x + 5, y + 12, x + 9, y + 12); + g.drawLine(x + 6, y + 13, x + 8, y + 13); + g.drawLine(x + 7, y + 14, x + 7, y + 14); + } + + // If the slider is enabled, draw dots and highlights. + if (c.isEnabled() + && !(MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)) + { + if (focus) + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + else + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 3, y + 3, x + 3, y + 3); + g.drawLine(x + 7, y + 3, x + 7, y + 3); + g.drawLine(x + 11, y + 3, x + 11, y + 3); + + g.drawLine(x + 5, y + 5, x + 5, y + 5); + g.drawLine(x + 9, y + 5, x + 9, y + 5); + + g.drawLine(x + 3, y + 7, x + 3, y + 7); + g.drawLine(x + 7, y + 7, x + 7, y + 7); + g.drawLine(x + 11, y + 7, x + 11, y + 7); + + // Draw highlights + if (focus) + g.setColor(MetalLookAndFeel.getPrimaryControl()); + else + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x + 1, y + 1, x + 13, y + 1); + g.drawLine(x + 1, y + 2, x + 1, y + 8); + g.drawLine(x + 2, y + 2, x + 2, y + 2); + g.drawLine(x + 6, y + 2, x + 6, y + 2); + g.drawLine(x + 10, y + 2, x + 10, y + 2); + + g.drawLine(x + 4, y + 4, x + 4, y + 4); + g.drawLine(x + 8, y + 4, x + 8, y + 4); + + g.drawLine(x + 2, y + 6, x + 2, y + 6); + g.drawLine(x + 6, y + 6, x + 6, y + 6); + g.drawLine(x + 10, y + 6, x + 10, y + 6); + } + + } + } + + /** + * An icon used for the 'close' button in the title frame of a + * {@link JInternalFrame}. + */ + private static class InternalFrameCloseIcon + implements Icon, UIResource, Serializable + { + /** The icon size in pixels. */ + private int size; + + /** + * Creates a new icon. + * + * @param size the icon size (width and height) in pixels. + */ + public InternalFrameCloseIcon(int size) + { + this.size = size; + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return size; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return size; + } + + /** + * Paints the icon. + * + * @param c the component (an {@link JInternalFrame} is expected). + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + AbstractButton b = (AbstractButton) c; + + // fill the interior + if (b.getModel().isPressed()) + // FIXME: also need to take into account whether the internal frame is + // selected + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.fillRect(x + 2, y + 2, 10, 10); + + // draw the outline box and the cross + if (b.getModel().isPressed()) + g.setColor(MetalLookAndFeel.getBlack()); + else + { + // FIXME: also need to take into account whether the internal frame is + // selected + boolean selected = true; + if (selected) + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + } + g.drawLine(x + 1, y + 1, x + 13, y + 1); + g.drawLine(x + 1, y + 2, x + 1, y + 12); + g.drawLine(x + 1, y + 13, x + 13, y + 13); + g.drawLine(x + 13, y + 2, x + 13, y + 12); + g.drawLine(x + 2, y + 12, x + 2, y + 12); + g.drawLine(x + 12, y + 2, x + 12, y + 2); + + g.fillRect(x + 4, y + 4, 2, 2); + g.fillRect(x + 5, y + 5, 4, 4); + g.drawLine(x + 9, y + 4, x + 10, y + 4); + g.drawLine(x + 9, y + 4, x + 9, y + 5); + g.drawLine(x + 4, y + 9, x + 4, y + 10); + g.drawLine(x + 4, y + 9, x + 5, y + 9); + g.drawLine(x + 9, y + 8, x + 9, y + 10); + g.drawLine(x + 8, y + 9, x + 10, y + 9); + + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x, y, x + 13, y); + g.drawLine(x, y + 1, x, y + 13); + g.drawLine(x + 3, y + 4, x + 4, y + 3); + g.drawLine(x + 3, y + 9, x + 5, y + 7); + g.drawLine(x + 7, y + 5, x + 9, y + 3); + + g.drawLine(x + 12, y + 3, x + 12, y + 11); + g.drawLine(x + 3, y + 12, x + 12, y + 12); + + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x + 1, y + 14, x + 14, y + 14); + g.drawLine(x + 14, y + 1, x + 14, y + 14); + + if (!b.getModel().isPressed()) + { + g.drawLine(x + 5, y + 10, x + 5, y + 10); + g.drawLine(x + 6, y + 9, x + 7, y + 9); + g.drawLine(x + 10, y + 5, x + 10, y + 5); + g.drawLine(x + 9, y + 6, x + 9, y + 7); + g.drawLine(x + 10, y + 10, x + 11, y + 10); + g.drawLine(x + 10, y + 11, x + 10, y + 11); + } + g.setColor(savedColor); + } + } + + /** + * The icon displayed at the top-left corner of a {@link JInternalFrame}. + */ + private static class InternalFrameDefaultMenuIcon + implements Icon, UIResource, Serializable + { + + /** + * Creates a new instance. + */ + public InternalFrameDefaultMenuIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 16; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 16; + } + + /** + * Paints the icon at the specified location. + * + * @param c the component. + * @param g the graphics device. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + g.fillRect(x + 1, y, 14, 2); + g.fillRect(x, y + 1, 2, 14); + g.fillRect(x + 1, y + 14, 14, 2); + g.fillRect(x + 14, y + 1, 2, 14); + g.drawLine(x + 2, y + 5, x + 14, y + 5); + + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.fillRect(x + 2, y + 2, 12, 3); + + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + g.drawLine(x + 3, y + 3, x + 3, y + 3); + g.drawLine(x + 6, y + 3, x + 6, y + 3); + g.drawLine(x + 9, y + 3, x + 9, y + 3); + g.drawLine(x + 12, y + 3, x + 12, y + 3); + + g.setColor(MetalLookAndFeel.getWhite()); + g.fillRect(x + 2, y + 6, 12, 8); + g.drawLine(x + 2, y + 2, x + 2, y + 2); + g.drawLine(x + 5, y + 2, x + 5, y + 2); + g.drawLine(x + 8, y + 2, x + 8, y + 2); + g.drawLine(x + 11, y + 2, x + 11, y + 2); + } + } + + /** + * An icon used in the title frame of a {@link JInternalFrame}. When you + * maximise an internal frame, this icon will replace the 'maximise' icon to + * provide a 'restore' option. + */ + private static class InternalFrameAltMaximizeIcon + implements Icon, UIResource, Serializable + { + /** The icon size in pixels. */ + private int size; + + /** + * Creates a new icon. + * + * @param size the icon size in pixels. + */ + public InternalFrameAltMaximizeIcon(int size) + { + this.size = size; + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return size; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return size; + } + + /** + * Paints the icon at the specified location. + * + * @param c the component. + * @param g the graphics device. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + + AbstractButton b = (AbstractButton) c; + + // fill the small box interior + if (b.getModel().isPressed()) + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.fillRect(x + 2, y + 6, 7, 7); + + + if (b.getModel().isPressed()) + g.setColor(MetalLookAndFeel.getBlack()); + else + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + + g.drawLine(x + 12, y + 1, x + 13, y + 1); + g.drawLine(x + 11, y + 2, x + 12, y + 2); + g.drawLine(x + 10, y + 3, x + 11, y + 3); + g.drawLine(x + 8, y + 2, x + 8, y + 3); + g.fillRect(x + 8, y + 4, 3, 3); + g.drawLine(x + 11, y + 6, x + 12, y + 6); + + g.drawLine(x + 1, y + 5, x + 5, y + 5); + g.drawLine(x + 1, y + 6, x + 1, y + 12); + g.drawLine(x + 9, y + 9, x + 9, y + 12); + g.drawLine(x + 1, y + 13, x + 9, y + 13); + + g.drawLine(x + 2, y + 12, x + 2, y + 12); + + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 12, y, x + 9, y + 3); + g.drawLine(x + 7, y + 1, x + 8, y + 1); + g.drawLine(x + 7, y + 2, x + 7, y + 6); + g.drawLine(x + 11, y + 5, x + 12, y + 5); + g.drawLine(x, y + 4, x + 5, y + 4); + g.drawLine(x, y + 5, x, y + 13); + g.drawLine(x + 3, y + 12, x + 8, y + 12); + g.drawLine(x + 8, y + 8, x + 8, y + 11); + g.drawLine(x + 9, y + 8, x + 9, y + 8); + + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x + 9, y + 2, x + 9, y + 2); + g.drawLine(x + 11, y + 4, x + 13, y + 2); + g.drawLine(x + 13, y + 6, x + 13, y + 6); + g.drawLine(x + 8, y + 7, x + 13, y + 7); + g.drawLine(x + 6, y + 5, x + 6, y + 5); + g.drawLine(x + 10, y + 8, x + 10, y + 13); + g.drawLine(x + 1, y + 14, x + 10, y + 14); + + if (!b.getModel().isPressed()) + { + g.drawLine(x + 2, y + 6, x + 6, y + 6); + g.drawLine(x + 2, y + 6, x + 2, y + 11); + } + + g.setColor(savedColor); + } + } + + /** + * An icon used for the 'maximize' button in the title frame of a + * {@link JInternalFrame}. + */ + private static class InternalFrameMaximizeIcon + implements Icon, UIResource, Serializable + { + + /** + * Creates a new instance. + */ + public InternalFrameMaximizeIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 16; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 16; + } + + /** + * Paints the icon at the specified location. + * + * @param c the component. + * @param g the graphics device. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + + AbstractButton b = (AbstractButton) c; + + // fill the interior + if (b.getModel().isPressed()) + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.fillRect(x + 2, y + 6, 7, 7); + + if (b.getModel().isPressed()) + g.setColor(MetalLookAndFeel.getBlack()); + else + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + + g.drawLine(x + 9, y + 1, x + 10, y + 1); + g.fillRect(x + 11, y + 1, 3, 3); + g.fillRect(x + 12, y + 4, 2, 2); + g.drawLine(x + 10, y + 3, x + 10, y + 3); + g.drawLine(x + 9, y + 4, x + 10, y + 4); + g.drawLine(x + 1, y + 5, x + 9, y + 5); + g.drawLine(x + 1, y + 6, x + 1, y + 12); + g.drawLine(x + 9, y + 6, x + 9, y + 12); + g.drawLine(x + 1, y + 13, x + 9, y + 13); + + // fill + g.drawLine(x + 7, y + 6, x + 8, y + 6); + g.drawLine(x + 6, y + 7, x + 8, y + 7); + g.drawLine(x + 5, y + 8, x + 6, y + 8); + g.drawLine(x + 4, y + 9, x + 5, y + 9); + g.drawLine(x + 3, y + 10, x + 4, y + 10); + g.drawLine(x + 2, y + 11, x + 3, y + 11); + g.drawLine(x + 2, y + 12, x + 4, y + 12); + g.drawLine(x + 8, y + 8, x + 8, y + 8); + + // draw black + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 8, y, x + 13, y); + g.drawLine(x + 8, y + 1, x + 8, y + 1); + g.drawLine(x + 10, y + 2, x + 9, y + 3); + g.drawLine(x, y + 4, x + 8, y + 4); + g.drawLine(x, y + 5, x, y + 13); + + g.drawLine(x + 2, y + 10, x + 6, y + 6); + g.drawLine(x + 8, y + 9, x + 8, y + 11); + g.drawLine(x + 5, y + 12, x + 8, y + 12); + + // draw white + g.setColor(MetalLookAndFeel.getWhite()); + if (!b.getModel().isPressed()) + { + g.drawLine(x + 2, y + 6, x + 5, y + 6); + g.drawLine(x + 2, y + 7, x + 2, y + 9); + g.drawLine(x + 4, y + 11, x + 7, y + 8); + } + + g.drawLine(x + 1, y + 14, x + 10, y + 14); + g.drawLine(x + 10, y + 5, x + 10, y + 13); + + g.drawLine(x + 9, y + 2, x + 9, y + 2); + g.drawLine(x + 11, y + 4, x + 11, y + 5); + g.drawLine(x + 13, y + 6, x + 14, y + 6); + g.drawLine(x + 14, y + 1, x + 14, y + 5); + g.setColor(savedColor); + } + } + + /** + * An icon used in the title frame of a {@link JInternalFrame}. + */ + private static class InternalFrameMinimizeIcon + implements Icon, UIResource, Serializable + { + + /** + * Creates a new instance. + */ + public InternalFrameMinimizeIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 16; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 16; + } + + /** + * Paints the icon at the specified location. + * + * @param c the component. + * @param g the graphics device. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + + AbstractButton b = (AbstractButton) c; + + if (b.getModel().isPressed()) + g.setColor(MetalLookAndFeel.getBlack()); + else + // FIXME: here the color depends on whether or not the internal frame + // is selected + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + + g.drawLine(x + 12, y + 1, x + 13, y + 1); + g.drawLine(x + 11, y + 2, x + 12, y + 2); + g.drawLine(x + 10, y + 3, x + 11, y + 3); + g.drawLine(x + 8, y + 2, x + 8, y + 3); + g.fillRect(x + 8, y + 4, 3, 3); + g.drawLine(x + 11, y + 6, x + 12, y + 6); + + g.drawLine(x + 1, y + 8, x + 6, y + 8); + g.drawLine(x + 1, y + 9, x + 1, y + 12); + g.drawLine(x + 6, y + 9, x + 6, y + 12); + g.drawLine(x + 1, y + 13, x + 6, y + 13); + + g.drawLine(x + 5, y + 9, x + 5, y + 9); + g.drawLine(x + 2, y + 12, x + 2, y + 12); + + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 12, y, x + 9, y + 3); + g.drawLine(x + 7, y + 1, x + 8, y + 1); + g.drawLine(x + 7, y + 2, x + 7, y + 6); + g.drawLine(x, y + 7, x + 6, y + 7); + g.drawLine(x, y + 8, x, y + 13); + g.drawLine(x + 3, y + 12, x + 5, y + 12); + g.drawLine(x + 5, y + 10, x + 5, y + 11); + g.drawLine(x + 11, y + 5, x + 12, y + 5); + + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x + 9, y + 2, x + 9, y + 2); + g.drawLine(x + 11, y + 4, x + 13, y + 2); + g.drawLine(x + 13, y + 6, x + 13, y + 6); + g.drawLine(x + 8, y + 7, x + 13, y + 7); + g.drawLine(x + 7, y + 9, x + 7, y + 13); + g.drawLine(x + 1, y + 14, x + 7, y + 14); + + if (b.getModel().isPressed()) + { + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + g.fillRect(x + 2, y + 9, 3, 3); + } + else + { + g.drawLine(x + 2, y + 9, x + 4, y + 9); + g.drawLine(x + 2, y + 10, x + 2, y + 11); + } + + g.setColor(savedColor); + } + } + + /** + * The icon used to display the thumb control on a horizontally oriented + * {@link JSlider} component. + */ + private static class VerticalSliderThumbIcon + implements Icon, UIResource, Serializable + { + /** + * This mask is used to paint the gradient in the shape of the thumb. + */ + int[][] gradientMask = new int[][] { {0, 12}, {0, 12}, {0, 12}, {0, 12}, + {0, 12}, {0, 12}, {0, 12}, {1, 11}, + {2, 10}, {3, 9}, {4, 8}, {5, 7}, + {6, 6}}; + + /** + * Creates a new instance. + */ + public VerticalSliderThumbIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 16; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 15; + } + + /** + * Paints the icon taking into account whether the slider control has the + * focus or not. + * + * @param c the slider (must be a non-<code>null</code> instance of + * {@link JSlider}. + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + boolean enabled = false; + boolean focus = false; + if (c != null) + { + enabled = c.isEnabled(); + focus = c.hasFocus(); + } + + // draw the outline + if (enabled) + g.setColor(MetalLookAndFeel.getBlack()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(x + 1, y, x + 7, y); + g.drawLine(x + 8, y, x + 15, y + 7); + g.drawLine(x + 14, y + 8, x + 8, y + 14); + g.drawLine(x + 8, y + 14, x + 1, y + 14); + g.drawLine(x, y + 13, x, y + 1); + +// The following is commented out until the masking for the gradient painting +// is working correctly +// // Fill the icon. +// if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme +// && enabled) +// { +// String gradient; +// if (focus) +// gradient = "Slider.focusGradient"; +// else +// gradient = "Slider.gradient"; +// MetalUtils.paintGradient(g, x + 2, y + 1, 13, 12, +// SwingConstants.HORIZONTAL, gradient, +// gradientMask); +// } +// else + { + if (focus) + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(x + 2, y + 1, 7, 13); + g.drawLine(x + 9, y + 2, x + 9, y + 12); + g.drawLine(x + 10, y + 3, x + 10, y + 11); + g.drawLine(x + 11, y + 4, x + 11, y + 10); + g.drawLine(x + 12, y + 5, x + 12, y + 9); + g.drawLine(x + 13, y + 6, x + 13, y + 8); + g.drawLine(x + 14, y + 7, x + 14, y + 7); + } + + // if the slider is enabled, draw dots and highlights + if (enabled + && ! (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)) + { + if (focus) + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + else + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 3, y + 3, x + 3, y + 3); + g.drawLine(x + 3, y + 7, x + 3, y + 7); + g.drawLine(x + 3, y + 11, x + 3, y + 11); + + g.drawLine(x + 5, y + 5, x + 5, y + 5); + g.drawLine(x + 5, y + 9, x + 5, y + 9); + + g.drawLine(x + 7, y + 3, x + 7, y + 3); + g.drawLine(x + 7, y + 7, x + 7, y + 7); + g.drawLine(x + 7, y + 11, x + 7, y + 11); + + // draw highlights + if (focus) + g.setColor(MetalLookAndFeel.getPrimaryControl()); + else + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x + 1, y + 1, x + 8, y + 1); + g.drawLine(x + 1, y + 2, x + 1, y + 13); + g.drawLine(x + 2, y + 2, x + 2, y + 2); + g.drawLine(x + 2, y + 6, x + 2, y + 6); + g.drawLine(x + 2, y + 10, x + 2, y + 10); + + g.drawLine(x + 4, y + 4, x + 4, y + 4); + g.drawLine(x + 4, y + 8, x + 4, y + 8); + + g.drawLine(x + 6, y + 2, x + 6, y + 2); + g.drawLine(x + 6, y + 6, x + 6, y + 6); + g.drawLine(x + 6, y + 10, x + 6, y + 10); + + } + } + } + + /** + * A tree control icon. This icon can be in one of two states: expanded and + * collapsed. + */ + public static class TreeControlIcon implements Icon, Serializable + { + + /** ???. */ + protected boolean isLight; + + /** A flag that controls whether or not the icon is collapsed. */ + private boolean collapsed; + + /** + * Creates a new icon. + * + * @param isCollapsed a flag that controls whether the icon is in the + * collapsed state or the expanded state. + */ + public TreeControlIcon(boolean isCollapsed) + { + collapsed = isCollapsed; + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 18; + } + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 18; + } + + /** + * Paints the icon at the location (x, y). + * + * @param c the component. + * @param g the graphics device. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + // TODO: pick up appropriate UI colors + Color dark = new Color(99, 130, 191); + Color light = new Color(163, 184, 204); + Color white = Color.white; + + x += 8; + y += 6; + + final int w = 6; + final int wHalf = (w >> 2); + g.setColor(light); + g.drawOval(x, y, w, w); + g.setColor(dark); + g.fillOval(x + 1, y + 1, w - 1, w - 1); + + if (collapsed) + g.fillRect(x + w, y + wHalf + 1, w, 2); + else + g.fillRect(x + wHalf + 1, y + w, 2, w); + + g.setColor(white); + g.fillRect(x + wHalf + 1, y + wHalf + 1, 2, 2); + + } + + /** + * Simply calls {@link #paintIcon(Component, Graphics, int, int)}. + * + * @param c the component. + * @param g the graphics device. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintMe(Component c, Graphics g, int x, int y) + { + paintIcon(c, g, x, y); + } + } + + /** + * A tree folder icon. + */ + public static class TreeFolderIcon extends FolderIcon16 + { + /** + * Creates a new instance. + */ + public TreeFolderIcon() + { + // Nothing to do here. + } + + /** + * Returns the additional height for this icon, in this case <code>2</code> + * pixels. + * + * @return <code>2</code>. + */ + public int getAdditionalHeight() + { + return 2; + } + + /** + * Returns the vertical shift, in pixels, applied when painting the icon. + * This overridden method returns <code>-1</code>. + * + * @return The shift. + */ + public int getShift() + { + return -1; + } + } + + /** + * A tree leaf icon. + */ + public static class TreeLeafIcon extends FileIcon16 + { + /** + * Creates a new instance. + */ + public TreeLeafIcon() + { + // Nothing to do here. + } + + /** + * Returns the additional height for this icon, in this case <code>4</code> + * pixels. + * + * @return <code>4</code>. + */ + public int getAdditionalHeight() + { + return 4; + } + + /** + * Returns the vertical shift, in pixels, applied when painting the icon. + * This overridden method returns <code>2</code>. + * + * @return The shift. + */ + public int getShift() + { + return 2; + } + } + + /** + * An icon representing a hard disk. + * + * @see MetalIconFactory#getTreeHardDriveIcon() + */ + private static class TreeHardDriveIcon + implements Icon, UIResource, Serializable + { + + /** + * Creates a new icon instance. + */ + public TreeHardDriveIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return <code>16</code>. + */ + public int getIconWidth() + { + return 16; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return <code>16</code>. + */ + public int getIconHeight() + { + return 16; + } + + /** + * Paints the icon at the specified location, using colors from the + * current theme. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate for the top-left of the icon. + * @param y the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color saved = g.getColor(); + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 1, y + 4, x + 1, y + 5); + g.drawLine(x + 14, y + 4, x + 14, y + 5); + g.drawLine(x + 1, y + 7, x + 1, y + 8); + g.drawLine(x + 14, y + 7, x + 14, y + 8); + g.drawLine(x + 1, y + 10, x + 1, y + 11); + g.drawLine(x + 14, y + 10, x + 14, y + 11); + + g.drawLine(x + 2, y + 3, x + 3, y + 3); + g.drawLine(x + 12, y + 3, x + 13, y + 3); + g.drawLine(x + 2, y + 6, x + 3, y + 6); + g.drawLine(x + 12, y + 6, x + 13, y + 6); + g.drawLine(x + 2, y + 9, x + 3, y + 9); + g.drawLine(x + 12, y + 9, x + 13, y + 9); + g.drawLine(x + 2, y + 12, x + 3, y + 12); + g.drawLine(x + 12, y + 12, x + 13, y + 12); + + g.drawLine(x + 4, y + 2, x + 11, y + 2); + g.drawLine(x + 4, y + 7, x + 11, y + 7); + g.drawLine(x + 4, y + 10, x + 11, y + 10); + g.drawLine(x + 4, y + 13, x + 11, y + 13); + + g.setColor(MetalLookAndFeel.getWhite()); + g.fillRect(x + 4, y + 3, 2, 2); + g.drawLine(x + 6, y + 4, x + 6, y + 4); + g.drawLine(x + 7, y + 3, x + 9, y + 3); + g.drawLine(x + 8, y + 4, x + 8, y + 4); + g.drawLine(x + 11, y + 3, x + 11, y + 3); + g.fillRect(x + 2, y + 4, 2, 2); + g.fillRect(x + 2, y + 7, 2, 2); + g.fillRect(x + 2, y + 10, 2, 2); + g.drawLine(x + 4, y + 6, x + 4, y + 6); + g.drawLine(x + 4, y + 9, x + 4, y + 9); + g.drawLine(x + 4, y + 12, x + 4, y + 12); + + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x + 13, y + 4, x + 13, y + 4); + g.drawLine(x + 12, y + 5, x + 13, y + 5); + g.drawLine(x + 13, y + 7, x + 13, y + 7); + g.drawLine(x + 12, y + 8, x + 13, y + 8); + g.drawLine(x + 13, y + 10, x + 13, y + 10); + g.drawLine(x + 12, y + 11, x + 13, y + 11); + + g.drawLine(x + 10, y + 5, x + 10, y + 5); + g.drawLine(x + 7, y + 6, x + 7, y + 6); + g.drawLine(x + 9, y + 6, x + 9, y + 6); + g.drawLine(x + 11, y + 6, x + 11, y + 6); + + g.drawLine(x + 10, y + 8, x + 10, y + 8); + g.drawLine(x + 7, y + 9, x + 7, y + 9); + g.drawLine(x + 9, y + 9, x + 9, y + 9); + g.drawLine(x + 11, y + 9, x + 11, y + 9); + + g.drawLine(x + 10, y + 11, x + 10, y + 11); + g.drawLine(x + 7, y + 12, x + 7, y + 12); + g.drawLine(x + 9, y + 12, x + 9, y + 12); + g.drawLine(x + 11, y + 12, x + 11, y + 12); + + g.setColor(saved); + } + } + + /** + * An icon representing a floppy disk. + * + * @see MetalIconFactory#getTreeFloppyDriveIcon() + */ + private static class TreeFloppyDriveIcon + implements Icon, UIResource, Serializable + { + + /** + * Creates a new icon instance. + */ + public TreeFloppyDriveIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return <code>16</code>. + */ + public int getIconWidth() + { + return 16; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return <code>16</code>. + */ + public int getIconHeight() + { + return 16; + } + + /** + * Paints the icon at the specified location, using colors from the + * current theme. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate for the top-left of the icon. + * @param y the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color saved = g.getColor(); + + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 1, y + 1, x + 13, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + 14); + g.drawLine(x + 1, y + 14, x + 14, y + 14); + g.drawLine(x + 14, y + 2, x + 14, y + 14); + + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.fillRect(x + 2, y + 2, 12, 12); + + g.setColor(MetalLookAndFeel.getControlShadow()); + g.fillRect(x + 5, y + 2, 6, 5); + g.drawLine(x + 4, y + 8, x + 11, y + 8); + g.drawLine(x + 3, y + 9, x + 3, y + 13); + g.drawLine(x + 12, y + 9, x + 12, y + 13); + + g.setColor(MetalLookAndFeel.getWhite()); + g.fillRect(x + 8, y + 3, 2, 3); + g.fillRect(x + 4, y + 9, 8, 5); + + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + g.drawLine(x + 5, y + 10, x + 9, y + 10); + g.drawLine(x + 5, y + 12, x + 8, y + 12); + + g.setColor(saved); + } + } + + /** + * An icon representing a computer. + * + * @see MetalIconFactory#getTreeComputerIcon() + */ + private static class TreeComputerIcon + implements Icon, UIResource, Serializable + { + + /** + * Creates a new icon instance. + */ + public TreeComputerIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return <code>16</code>. + */ + public int getIconWidth() + { + return 16; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return <code>16</code>. + */ + public int getIconHeight() + { + return 16; + } + + /** + * Paints the icon at the specified location, using colors from the + * current theme. + * + * @param c the component (ignored). + * @param g the graphics device. + * @param x the x-coordinate for the top-left of the icon. + * @param y the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color saved = g.getColor(); + + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 3, y + 1, x + 12, y + 1); + g.drawLine(x + 2, y + 2, x + 2, y + 8); + g.drawLine(x + 13, y + 2, x + 13, y + 8); + g.drawLine(x + 3, y + 9, x + 3, y + 9); + g.drawLine(x + 12, y + 9, x + 12, y + 9); + g.drawRect(x + 1, y + 10, 13, 4); + g.drawLine(x + 5, y + 3, x + 10, y + 3); + g.drawLine(x + 5, y + 8, x + 10, y + 8); + g.drawLine(x + 4, y + 4, x + 4, y + 7); + g.drawLine(x + 11, y + 4, x + 11, y + 7); + + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.fillRect(x + 5, y + 4, 6, 4); + + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x + 6, y + 12, x + 8, y + 12); + g.drawLine(x + 10, y + 12, x + 12, y + 12); + g.setColor(saved); + } + } + + /** The icon returned by {@link #getCheckBoxIcon()}. */ + private static Icon checkBoxIcon; + + /** The icon returned by {@link #getCheckBoxMenuItemIcon()}. */ + private static Icon checkBoxMenuItemIcon; + + /** The icon returned by {@link #getFileChooserDetailViewIcon()}. */ + private static Icon fileChooserDetailViewIcon; + + /** The icon returned by {@link #getFileChooserHomeFolderIcon()}. */ + private static Icon fileChooserHomeFolderIcon; + + /** The icon returned by {@link #getFileChooserListViewIcon()}. */ + private static Icon fileChooserListViewIcon; + + /** The icon returned by {@link #getFileChooserNewFolderIcon()}. */ + private static Icon fileChooserNewFolderIcon; + + /** The icon returned by {@link #getFileChooserUpFolderIcon()}. */ + private static Icon fileChooserUpFolderIcon; + + /** The cached RadioButtonIcon instance. */ + private static RadioButtonIcon radioButtonIcon; + + /** The icon returned by {@link #getRadioButtonMenuItemIcon()}. */ + private static Icon radioButtonMenuItemIcon; + + /** The icon returned by {@link #getInternalFrameDefaultMenuIcon()}. */ + private static Icon internalFrameDefaultMenuIcon; + + /** The icon returned by {@link #getTreeComputerIcon()}. */ + private static Icon treeComputerIcon; + + /** The icon instance returned by {@link #getTreeFloppyDriveIcon()}. */ + private static Icon treeFloppyDriveIcon; + + /** The icon instance returned by {@link #getTreeHardDriveIcon()}. */ + private static Icon treeHardDriveIcon; + + /** The icon instance returned by {@link #getHorizontalSliderThumbIcon()}. */ + private static Icon horizontalSliderThumbIcon; + + /** The icon instance returned by {@link #getVerticalSliderThumbIcon()}. */ + private static Icon verticalSliderThumbIcon; + + /** + * Creates a new instance. All the methods are static, so creating an + * instance isn't necessary. + */ + public MetalIconFactory() + { + // Nothing to do here. + } + + /** + * Returns an icon for use when rendering the {@link JCheckBox} component. + * + * @return A check box icon. + * + * @since 1.3 + */ + public static Icon getCheckBoxIcon() + { + if (checkBoxIcon == null) + checkBoxIcon = new MetalCheckBoxIcon(); + return checkBoxIcon; + } + + /** + * Returns an icon for use when rendering the {@link JCheckBoxMenuItem} + * component. + * + * @return An icon. + */ + public static Icon getCheckBoxMenuItemIcon() + { + if (checkBoxMenuItemIcon == null) + checkBoxMenuItemIcon = new CheckBoxMenuItemIcon(); + return checkBoxMenuItemIcon; + } + + /** + * Returns an icon for use by the {@link JFileChooser} component. + * + * @return An icon. + */ + public static Icon getFileChooserDetailViewIcon() + { + if (fileChooserDetailViewIcon == null) + fileChooserDetailViewIcon = new FileChooserDetailViewIcon(); + return fileChooserDetailViewIcon; + } + + /** + * Returns an icon for use by the {@link JFileChooser} component. + * + * @return An icon. + */ + public static Icon getFileChooserHomeFolderIcon() + { + if (fileChooserHomeFolderIcon == null) + fileChooserHomeFolderIcon = new FileChooserHomeFolderIcon(); + return fileChooserHomeFolderIcon; + } + + /** + * Returns an icon for use by the {@link JFileChooser} component. + * + * @return An icon. + */ + public static Icon getFileChooserListViewIcon() + { + if (fileChooserListViewIcon == null) + fileChooserListViewIcon = new FileChooserListViewIcon(); + return fileChooserListViewIcon; + } + + /** + * Returns an icon for use by the {@link JFileChooser} component. + * + * @return An icon. + */ + public static Icon getFileChooserNewFolderIcon() + { + if (fileChooserNewFolderIcon == null) + fileChooserNewFolderIcon = new FileChooserNewFolderIcon(); + return fileChooserNewFolderIcon; + } + + /** + * Returns an icon for use by the {@link JFileChooser} component. + * + * @return An icon. + */ + public static Icon getFileChooserUpFolderIcon() + { + if (fileChooserUpFolderIcon == null) + fileChooserUpFolderIcon = new FileChooserUpFolderIcon(); + return fileChooserUpFolderIcon; + } + + /** + * Returns an icon for RadioButtons in the Metal L&F. + * + * @return an icon for RadioButtons in the Metal L&F + */ + public static Icon getRadioButtonIcon() + { + if (radioButtonIcon == null) + radioButtonIcon = new RadioButtonIcon(); + return radioButtonIcon; + } + + /** + * Creates a new instance of the icon used in a {@link JRadioButtonMenuItem}. + * + * @return A new icon instance. + */ + public static Icon getRadioButtonMenuItemIcon() + { + if (radioButtonMenuItemIcon == null) + radioButtonMenuItemIcon = new RadioButtonMenuItemIcon(); + return radioButtonMenuItemIcon; + } + + /** + * Returns the icon used to display the thumb for a horizontally oriented + * {@link JSlider}. + * + * @return The icon. + */ + public static Icon getHorizontalSliderThumbIcon() + { + if (horizontalSliderThumbIcon == null) + horizontalSliderThumbIcon = new HorizontalSliderThumbIcon(); + return horizontalSliderThumbIcon; + } + + /** + * Creates a new icon used to represent the 'close' button in the title + * pane of a {@link JInternalFrame}. + * + * @param size the icon size. + * + * @return A close icon. + */ + public static Icon getInternalFrameCloseIcon(int size) + { + return new InternalFrameCloseIcon(size); + } + + /** + * Creates a new icon for the menu in a {@link JInternalFrame}. This is the + * icon displayed at the top left of the frame. + * + * @return A menu icon. + */ + public static Icon getInternalFrameDefaultMenuIcon() + { + if (internalFrameDefaultMenuIcon == null) + internalFrameDefaultMenuIcon = new InternalFrameDefaultMenuIcon(); + return internalFrameDefaultMenuIcon; + } + + /** + * Creates a new icon for the 'maximize' button in a {@link JInternalFrame}. + * + * @param size the icon size in pixels. + * + * @return The icon. + * + * @see #getInternalFrameAltMaximizeIcon(int) + */ + public static Icon getInternalFrameMaximizeIcon(int size) + { + return new InternalFrameMaximizeIcon(); + } + + /** + * Returns the icon used for the minimize button in the frame title for a + * {@link JInternalFrame}. + * + * @param size the icon size in pixels (ignored by this implementation). + * + * @return The icon. + */ + public static Icon getInternalFrameMinimizeIcon(int size) + { + return new InternalFrameMinimizeIcon(); + } + + /** + * Creates a new icon for the 'restore' button in a {@link JInternalFrame} + * that has been maximised. + * + * @param size the icon size in pixels. + * + * @return The icon. + * + * @see #getInternalFrameMaximizeIcon(int) + */ + public static Icon getInternalFrameAltMaximizeIcon(int size) + { + return new InternalFrameAltMaximizeIcon(size); + } + + /** + * Returns the icon used to display the thumb for a vertically oriented + * {@link JSlider}. + * + * @return The icon. + */ + public static Icon getVerticalSliderThumbIcon() + { + if (verticalSliderThumbIcon == null) + verticalSliderThumbIcon = new VerticalSliderThumbIcon(); + return verticalSliderThumbIcon; + } + + /** + * Creates and returns a new tree folder icon. + * + * @return A new tree folder icon. + */ + public static Icon getTreeFolderIcon() + { + return new TreeFolderIcon(); + } + + /** + * Creates and returns a new tree leaf icon. + * + * @return A new tree leaf icon. + */ + public static Icon getTreeLeafIcon() + { + return new TreeLeafIcon(); + } + + /** + * Creates and returns a tree control icon. + * + * @param isCollapsed a flag that controls whether the icon is in the + * collapsed or expanded state. + * + * @return A tree control icon. + */ + public static Icon getTreeControlIcon(boolean isCollapsed) + { + return new TreeControlIcon(isCollapsed); + } + + /** + * Returns a <code>16x16</code> icon representing a computer. + * + * @return The icon. + */ + public static Icon getTreeComputerIcon() + { + if (treeComputerIcon == null) + treeComputerIcon = new TreeComputerIcon(); + return treeComputerIcon; + } + + /** + * Returns a <code>16x16</code> icon representing a floppy disk. + * + * @return The icon. + */ + public static Icon getTreeFloppyDriveIcon() + { + if (treeFloppyDriveIcon == null) + treeFloppyDriveIcon = new TreeFloppyDriveIcon(); + return treeFloppyDriveIcon; + } + + /** + * Returns a <code>16x16</code> icon representing a hard disk. + * + * @return The icon. + */ + public static Icon getTreeHardDriveIcon() + { + if (treeHardDriveIcon == null) + treeHardDriveIcon = new TreeHardDriveIcon(); + return treeHardDriveIcon; + } + + /** + * Returns a new instance of a 4 x 8 icon showing a small black triangle that + * points to the right. This is displayed in menu items that have a + * sub menu. + * + * @return The icon. + */ + public static Icon getMenuArrowIcon() + { + if (menuArrow == null) + menuArrow = new Icon() + { + public int getIconHeight() + { + return 8; + } + + public int getIconWidth() + { + return 4; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color saved = g.getColor(); + g.setColor(Color.BLACK); + for (int i = 0; i < 4; i++) + g.drawLine(x + i, y + i, x + i, y + 7 - i); + g.setColor(saved); + } + }; + return menuArrow; + } + + /** + * Returns a new instance of a 4 x 8 icon showing a small black triangle that + * points to the right. This is displayed in menu items that have a sub menu. + * + * @return The icon. + */ + public static Icon getMenuItemArrowIcon() + { + if (menuItemArrow == null) + menuItemArrow = new Icon() + { + public int getIconHeight() + { + return 8; + } + + public int getIconWidth() + { + return 4; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color saved = g.getColor(); + g.setColor(Color.BLACK); + for (int i = 0; i < 4; i++) + g.drawLine(x + i, y + i, x + i, y + 7 - i); + g.setColor(saved); + } + }; + return menuItemArrow; + } + + /** + * Returns a new instance of a 13 x 13 icon showing a small black check mark. + * + * @return The icon. + */ + public static Icon getMenuItemCheckIcon() + { + return new Icon() + { + public int getIconHeight() + { + return 13; + } + + public int getIconWidth() + { + return 13; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color saved = g.getColor(); + g.setColor(Color.BLACK); + g.drawLine(3 + x, 5 + y, 3 + x, 9 + y); + g.drawLine(4 + x, 5 + y, 4 + x, 9 + y); + g.drawLine(5 + x, 7 + y, 9 + x, 3 + y); + g.drawLine(5 + x, 8 + y, 9 + x, 4 + y); + g.setColor(saved); + } + }; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java b/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java new file mode 100644 index 000000000..08de77446 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java @@ -0,0 +1,457 @@ +/* MetalInternalFrameTitlePane.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Rectangle; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.Icon; +import javax.swing.JInternalFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.plaf.basic.BasicInternalFrameTitlePane; + + +/** + * The title pane for a {@link JInternalFrame} (see + * {@link MetalInternalFrameUI#createNorthPane(JInternalFrame)}). This can + * be displayed in two styles: one for regular internal frames, and the other + * for "palette" style internal frames. + */ +public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane +{ + + /** + * A property change handler that listens for changes to the + * <code>JInternalFrame.isPalette</code> property and updates the title + * pane as appropriate. + */ + class MetalInternalFrameTitlePanePropertyChangeHandler + extends PropertyChangeHandler + { + /** + * Creates a new handler. + */ + public MetalInternalFrameTitlePanePropertyChangeHandler() + { + super(); + } + + /** + * Handles <code>JInternalFrame.isPalette</code> property changes, with all + * other property changes being passed to the superclass. + * + * @param e the event. + */ + public void propertyChange(PropertyChangeEvent e) + { + String propName = e.getPropertyName(); + if (e.getPropertyName().equals(JInternalFrame.FRAME_ICON_PROPERTY)) + { + title.setIcon(frame.getFrameIcon()); + } + else if (propName.equals("JInternalFrame.isPalette")) + { + if (e.getNewValue().equals(Boolean.TRUE)) + setPalette(true); + else + setPalette(false); + } + else + super.propertyChange(e); + } + } + + /** + * A layout manager for the title pane. + * + * @see #createLayout() + */ + private class MetalTitlePaneLayout implements LayoutManager + { + /** + * Creates a new <code>TitlePaneLayout</code> object. + */ + public MetalTitlePaneLayout() + { + // Do nothing. + } + + /** + * Adds a Component to the Container. + * + * @param name The name to reference the added Component by. + * @param c The Component to add. + */ + public void addLayoutComponent(String name, Component c) + { + // Do nothing. + } + + /** + * This method is called to lay out the children of the Title Pane. + * + * @param c The Container to lay out. + */ + public void layoutContainer(Container c) + { + + Dimension size = c.getSize(); + Insets insets = c.getInsets(); + int width = size.width - insets.left - insets.right; + int height = size.height - insets.top - insets.bottom; + + + int loc = width - insets.right - 1; + int top = insets.top + 2; + int buttonHeight = height - 4; + if (closeButton.isVisible()) + { + int buttonWidth = closeIcon.getIconWidth(); + loc -= buttonWidth + 2; + closeButton.setBounds(loc, top, buttonWidth, buttonHeight); + loc -= 6; + } + + if (maxButton.isVisible()) + { + int buttonWidth = maxIcon.getIconWidth(); + loc -= buttonWidth + 4; + maxButton.setBounds(loc, top, buttonWidth, buttonHeight); + } + + if (iconButton.isVisible()) + { + int buttonWidth = minIcon.getIconWidth(); + loc -= buttonWidth + 4; + iconButton.setBounds(loc, top, buttonWidth, buttonHeight); + loc -= 2; + } + + Dimension titlePreferredSize = title.getPreferredSize(); + title.setBounds(insets.left + 5, insets.top, + Math.min(titlePreferredSize.width, loc - insets.left - 10), + height); + + } + + /** + * This method returns the minimum size of the given Container given the + * children that it has. + * + * @param c The Container to get a minimum size for. + * + * @return The minimum size of the Container. + */ + public Dimension minimumLayoutSize(Container c) + { + return preferredLayoutSize(c); + } + + /** + * Returns the preferred size of the given Container taking + * into account the children that it has. + * + * @param c The Container to lay out. + * + * @return The preferred size of the Container. + */ + public Dimension preferredLayoutSize(Container c) + { + if (isPalette) + return new Dimension(paletteTitleHeight, paletteTitleHeight); + else + return new Dimension(22, 22); + } + + /** + * Removes a Component from the Container. + * + * @param c The Component to remove. + */ + public void removeLayoutComponent(Component c) + { + // Nothing to do here. + } + } + + /** A flag indicating whether the title pane uses the palette style. */ + protected boolean isPalette; + + /** + * The icon used for the close button - this is fetched from the look and + * feel defaults using the key <code>InternalFrame.paletteCloseIcon</code>. + */ + protected Icon paletteCloseIcon; + + /** + * The height of the title pane when <code>isPalette</code> is + * <code>true</code>. This value is fetched from the look and feel defaults + * using the key <code>InternalFrame.paletteTitleHeight</code>. + */ + protected int paletteTitleHeight; + + /** The label used to display the title for the internal frame. */ + JLabel title; + + /** + * Creates a new title pane for the specified frame. + * + * @param f the internal frame. + */ + public MetalInternalFrameTitlePane(JInternalFrame f) + { + super(f); + isPalette = false; + } + + /** + * Fetches the colors used in the title pane. + */ + protected void installDefaults() + { + super.installDefaults(); + selectedTextColor = MetalLookAndFeel.getControlTextColor(); + selectedTitleColor = MetalLookAndFeel.getWindowTitleBackground(); + notSelectedTextColor = MetalLookAndFeel.getInactiveControlTextColor(); + notSelectedTitleColor = MetalLookAndFeel.getWindowTitleInactiveBackground(); + + paletteTitleHeight = UIManager.getInt("InternalFrame.paletteTitleHeight"); + paletteCloseIcon = UIManager.getIcon("InternalFrame.paletteCloseIcon"); + minIcon = MetalIconFactory.getInternalFrameAltMaximizeIcon(16); + + title = new JLabel(frame.getTitle(), + MetalIconFactory.getInternalFrameDefaultMenuIcon(), + SwingConstants.LEFT); + } + + /** + * Clears the colors used for the title pane. + */ + protected void uninstallDefaults() + { + super.uninstallDefaults(); + selectedTextColor = null; + selectedTitleColor = null; + notSelectedTextColor = null; + notSelectedTitleColor = null; + paletteCloseIcon = null; + minIcon = null; + title = null; + } + + /** + * Calls the super class to create the buttons, then calls + * <code>setBorderPainted(false)</code> and + * <code>setContentAreaFilled(false)</code> for each button. + */ + protected void createButtons() + { + super.createButtons(); + closeButton.setBorderPainted(false); + closeButton.setContentAreaFilled(false); + iconButton.setBorderPainted(false); + iconButton.setContentAreaFilled(false); + maxButton.setBorderPainted(false); + maxButton.setContentAreaFilled(false); + } + + /** + * Overridden to do nothing. + */ + protected void addSystemMenuItems(JMenu systemMenu) + { + // do nothing + } + + /** + * Overridden to do nothing. + */ + protected void showSystemMenu() + { + // do nothing + } + + /** + * Adds the sub components of the title pane. + */ + protected void addSubComponents() + { + // FIXME: this method is probably overridden to only add the required + // buttons + add(title); + add(closeButton); + add(iconButton); + add(maxButton); + } + + /** + * Creates a new instance of <code>MetalTitlePaneLayout</code> (not part of + * the public API). + * + * @return A new instance of <code>MetalTitlePaneLayout</code>. + */ + protected LayoutManager createLayout() + { + return new MetalTitlePaneLayout(); + } + + /** + * Draws the title pane in the palette style. + * + * @param g the graphics device. + * + * @see #paintComponent(Graphics) + */ + public void paintPalette(Graphics g) + { + Color savedColor = g.getColor(); + Rectangle b = SwingUtilities.getLocalBounds(this); + + if (UIManager.get("InternalFrame.activeTitleGradient") != null + && frame.isSelected()) + { + MetalUtils.paintGradient(g, b.x, b.y, b.width, b.height, + SwingConstants.VERTICAL, + "InternalFrame.activeTitleGradient"); + } + MetalUtils.fillMetalPattern(this, g, b.x + 4, b.y + 2, b.width + - paletteCloseIcon.getIconWidth() - 13, b.height - 5, + MetalLookAndFeel.getPrimaryControlHighlight(), + MetalLookAndFeel.getBlack()); + + // draw a line separating the title pane from the frame content + Dimension d = getSize(); + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + g.drawLine(0, d.height - 1, d.width - 1, d.height - 1); + + g.setColor(savedColor); + } + + /** + * Paints a representation of the current state of the internal frame. + * + * @param g the graphics device. + */ + public void paintComponent(Graphics g) + { + Color savedColor = g.getColor(); + if (isPalette) + paintPalette(g); + else + { + paintTitleBackground(g); + paintChildren(g); + Dimension d = getSize(); + if (frame.isSelected()) + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // put a dot in each of the top corners + g.drawLine(0, 0, 0, 0); + g.drawLine(d.width - 1, 0, d.width - 1, 0); + + g.drawLine(0, d.height - 1, d.width - 1, d.height - 1); + + // draw the metal pattern + if (UIManager.get("InternalFrame.activeTitleGradient") != null + && frame.isSelected()) + { + MetalUtils.paintGradient(g, 0, 0, getWidth(), getHeight(), + SwingConstants.VERTICAL, + "InternalFrame.activeTitleGradient"); + } + + Rectangle b = title.getBounds(); + int startX = b.x + b.width + 5; + int endX = startX; + if (iconButton.isVisible()) + endX = Math.max(iconButton.getX(), endX); + else if (maxButton.isVisible()) + endX = Math.max(maxButton.getX(), endX); + else if (closeButton.isVisible()) + endX = Math.max(closeButton.getX(), endX); + endX -= 7; + if (endX > startX) + MetalUtils.fillMetalPattern(this, g, startX, 3, endX - startX, + getHeight() - 6, Color.white, Color.gray); + } + g.setColor(savedColor); + } + + /** + * Sets the flag that controls whether the title pane is drawn in the + * palette style or the regular style. + * + * @param b the new value of the flag. + */ + public void setPalette(boolean b) + { + isPalette = b; + title.setVisible(!isPalette); + iconButton.setVisible(!isPalette && frame.isIconifiable()); + maxButton.setVisible(!isPalette && frame.isMaximizable()); + if (isPalette) + closeButton.setIcon(paletteCloseIcon); + else + closeButton.setIcon(closeIcon); + } + + /** + * Creates and returns a property change handler for the title pane. + * + * @return The property change handler. + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new MetalInternalFrameTitlePanePropertyChangeHandler(); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameUI.java new file mode 100644 index 000000000..5eda2ff5e --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameUI.java @@ -0,0 +1,183 @@ +/* MetalInternalFrameUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.ActionMap; +import javax.swing.JComponent; +import javax.swing.JInternalFrame; +import javax.swing.SwingUtilities; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicInternalFrameUI; + +/** + * A UI delegate for the {@link JInternalFrame} component. + */ +public class MetalInternalFrameUI + extends BasicInternalFrameUI +{ + /** + * The key (<code>JInternalFrame.isPalette</code>) for the client property + * that controls whether the internal frame is displayed using the palette + * style. + */ + protected static String IS_PALETTE = "JInternalFrame.isPalette"; + + /** + * Constructs a new instance of <code>MetalInternalFrameUI</code>. + * + * @param frame the frame. + */ + public MetalInternalFrameUI(JInternalFrame frame) + { + super(frame); + } + + /** + * Returns an instance of <code>MetalInternalFrameUI</code>. + * + * @param component the internal frame. + * + * @return an instance of <code>MetalInternalFrameUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalInternalFrameUI((JInternalFrame) component); + } + + /** + * Sets the fields and properties for the component. + * + * @param c the component. + */ + public void installUI(JComponent c) + { + super.installUI(c); + JInternalFrame f = (JInternalFrame) c; + boolean isPalette = false; + Boolean p = (Boolean) f.getClientProperty(IS_PALETTE); + if (p != null) + isPalette = p.booleanValue(); + setPalette(isPalette); + } + + /** + * Creates and returns the component that will be used for the north pane + * of the {@link JInternalFrame}. + * + * @param w the internal frame. + * + * @return A new instance of {@link MetalInternalFrameTitlePane}. + */ + protected JComponent createNorthPane(JInternalFrame w) + { + titlePane = new MetalInternalFrameTitlePane(w); + return titlePane; + } + + /** + * Sets the state of the {@link JInternalFrame} to reflect whether or not + * it is using the palette style. When a frame is displayed as a palette, + * it uses a different border and the title pane is drawn differently. + * + * @param isPalette use the palette style? + */ + public void setPalette(boolean isPalette) + { + MetalInternalFrameTitlePane title = (MetalInternalFrameTitlePane) northPane; + title.setPalette(isPalette); + if (isPalette) + frame.setBorder(new MetalBorders.PaletteBorder()); + else + frame.setBorder(new MetalBorders.InternalFrameBorder()); + } + + /** A listener that is used to handle IS_PALETTE property changes. */ + private PropertyChangeListener paletteListener; + + /** + * Adds the required listeners. + */ + protected void installListeners() + { + super.installListeners(); + paletteListener = new PropertyChangeListener() + { + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals(IS_PALETTE)) + { + if (Boolean.TRUE.equals(e.getNewValue())) + setPalette(true); + else + setPalette(false); + } + } + }; + frame.addPropertyChangeListener(paletteListener); + } + + /** + * Removes the listeners used. + */ + protected void uninstallListeners() + { + super.uninstallListeners(); + frame.removePropertyChangeListener(IS_PALETTE, paletteListener); + paletteListener = null; + } + + /** + * Installs keyboard actions. This is overridden to remove the + * <code>showSystemMenu</code> Action that is installed by the + * <code>BasicInternalFrameUI</code>, since Metal JInternalFrames don't have + * a system menu. + */ + protected void installKeyboardActions() + { + super.installKeyboardActions(); + ActionMap am = SwingUtilities.getUIActionMap(frame); + if (am != null) + { + am.remove("showSystemMenu"); + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalLabelUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalLabelUI.java new file mode 100644 index 000000000..915e5016d --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalLabelUI.java @@ -0,0 +1,108 @@ +/* MetalLabelUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Graphics; + +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicGraphicsUtils; +import javax.swing.plaf.basic.BasicLabelUI; + +/** + * A UI delegate for the {@link JLabel} component. + */ +public class MetalLabelUI + extends BasicLabelUI +{ + + /** The shared instance of the UI delegate. */ + protected static MetalLabelUI metalLabelUI; + + /** + * Constructs a new instance of <code>MetalLabelUI</code>. + */ + public MetalLabelUI() + { + super(); + } + + /** + * Returns a shared instance of <code>MetalLabelUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A shared instance of <code>MetalLabelUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + if (metalLabelUI == null) + metalLabelUI = new MetalLabelUI(); + return metalLabelUI; + } + + /** + * Draws the text for a disabled label, using the color defined in the + * {@link UIManager} defaults with the key + * <code>Label.disabledForeground</code>. + * + * @param l the label. + * @param g the graphics device. + * @param s the label text. + * @param textX the x-coordinate for the label. + * @param textY the y-coordinate for the label. + */ + protected void paintDisabledText(JLabel l, Graphics g, String s, int textX, + int textY) + { + Color savedColor = g.getColor(); + g.setColor(UIManager.getColor("Label.disabledForeground")); + int mnemIndex = l.getDisplayedMnemonicIndex(); + if (mnemIndex != -1) + BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX, + textY); + else + g.drawString(s, textX, textY); + + g.setColor(savedColor); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java new file mode 100644 index 000000000..acc3fedde --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -0,0 +1,1372 @@ +/* MetalLookAndFeel.java + Copyright (C) 2002, 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import gnu.classpath.SystemProperties; + +import java.awt.Color; +import java.awt.Font; + +import javax.swing.LookAndFeel; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.InsetsUIResource; +import javax.swing.plaf.BorderUIResource.LineBorderUIResource; +import javax.swing.plaf.basic.BasicLookAndFeel; + + +/** + * A custom look and feel that is designed to look similar across different + * operating systems. To install this look and feel, add the following code + * (or something similar) near the start of your application:</p> + * <pre> + * try + * { + * UIManager.setLookAndFeel(new MetalLookAndFeel()); + * } + * catch (UnsupportedLookAndFeelException e) + * { + * e.printStackTrace(); + * }</pre> + */ +public class MetalLookAndFeel extends BasicLookAndFeel +{ + private static final long serialVersionUID = 6680646159193457980L; + + /** The current theme. */ + private static MetalTheme theme; + + /** + * Creates a new instance of the Metal look and feel. + */ + public MetalLookAndFeel() + { + // Nothing to do here. + } + + /** + * Sets the current theme to a new instance of {@link DefaultMetalTheme}. + */ + protected void createDefaultTheme() + { + getCurrentTheme(); + } + + /** + * Returns <code>false</code> to indicate that this look and feel does not + * attempt to emulate the look and feel of native applications on the host + * platform. + * + * @return <code>false</code>. + */ + public boolean isNativeLookAndFeel() + { + return false; + } + + /** + * Returns <code>true</code> to indicate that this look and feel is supported + * on all platforms. + * + * @return <code>true</code>. + */ + public boolean isSupportedLookAndFeel() + { + return true; + } + + /** + * Returns a string describing the look and feel. In this case, the method + * returns "Metal look and feel". + * + * @return A string describing the look and feel. + */ + public String getDescription() + { + return "The Java(tm) Look and Feel"; + } + + /** + * Returns the look and feel identifier. + * + * @return "MetalLookAndFeel". + */ + public String getID() + { + return "Metal"; + } + + /** + * Returns the look and feel name. + * + * @return "MetalLookAndFeel". + */ + public String getName() + { + return "Metal"; + } + + public UIDefaults getDefaults() + { + createDefaultTheme(); + UIDefaults def = super.getDefaults(); + + theme.addCustomEntriesToTable(def); + return def; + } + + /** + * Returns the accelerator foreground color from the installed theme. + * + * @return The accelerator foreground color. + */ + public static ColorUIResource getAcceleratorForeground() + { + if (theme != null) + return theme.getAcceleratorForeground(); + return null; + } + + /** + * Returns the accelerator selected foreground color from the installed + * theme. + * + * @return The accelerator selected foreground color. + */ + public static ColorUIResource getAcceleratorSelectedForeground() + { + if (theme != null) + return theme.getAcceleratorSelectedForeground(); + return null; + } + + /** + * Returns the color black from the installed theme. + * + * @return The color black. + */ + public static ColorUIResource getBlack() + { + if (theme != null) + return theme.getBlack(); + return null; + } + + /** + * Returns the control color from the installed theme. + * + * @return The control color. + */ + public static ColorUIResource getControl() + { + if (theme != null) + return theme.getControl(); + return null; + } + + /** + * Returns the color used for dark shadows on controls, from the installed + * theme. + * + * @return The color used for dark shadows on controls. + */ + public static ColorUIResource getControlDarkShadow() + { + if (theme != null) + return theme.getControlDarkShadow(); + return null; + } + + /** + * Returns the color used for disabled controls, from the installed theme. + * + * @return The color used for disabled controls. + */ + public static ColorUIResource getControlDisabled() + { + if (theme != null) + return theme.getControlDisabled(); + return null; + } + + /** + * Returns the color used to draw highlights for controls, from the installed + * theme. + * + * @return The color used to draw highlights for controls. + */ + public static ColorUIResource getControlHighlight() + { + if (theme != null) + return theme.getControlHighlight(); + return null; + } + + /** + * Returns the color used to display control info, from the installed + * theme. + * + * @return The color used to display control info. + */ + public static ColorUIResource getControlInfo() + { + if (theme != null) + return theme.getControlInfo(); + return null; + } + + /** + * Returns the color used to draw shadows for controls, from the installed + * theme. + * + * @return The color used to draw shadows for controls. + */ + public static ColorUIResource getControlShadow() + { + if (theme != null) + return theme.getControlShadow(); + return null; + } + + /** + * Returns the color used for text on controls, from the installed theme. + * + * @return The color used for text on controls. + */ + public static ColorUIResource getControlTextColor() + { + if (theme != null) + return theme.getControlTextColor(); + return null; + } + + /** + * Returns the font used for text on controls, from the installed theme. + * + * @return The font used for text on controls. + */ + public static FontUIResource getControlTextFont() + { + if (theme != null) + return theme.getControlTextFont(); + return null; + } + + /** + * Returns the color used for the desktop background, from the installed + * theme. + * + * @return The color used for the desktop background. + */ + public static ColorUIResource getDesktopColor() + { + if (theme != null) + return theme.getDesktopColor(); + return null; + } + + /** + * Returns the color used to draw focus highlights, from the installed + * theme. + * + * @return The color used to draw focus highlights. + */ + public static ColorUIResource getFocusColor() + { + if (theme != null) + return theme.getFocusColor(); + return null; + } + + /** + * Returns the color used to draw highlighted text, from the installed + * theme. + * + * @return The color used to draw highlighted text. + */ + public static ColorUIResource getHighlightedTextColor() + { + if (theme != null) + return theme.getHighlightedTextColor(); + return null; + } + + /** + * Returns the color used to draw text on inactive controls, from the + * installed theme. + * + * @return The color used to draw text on inactive controls. + */ + public static ColorUIResource getInactiveControlTextColor() + { + if (theme != null) + return theme.getInactiveControlTextColor(); + return null; + } + + /** + * Returns the color used to draw inactive system text, from the installed + * theme. + * + * @return The color used to draw inactive system text. + */ + public static ColorUIResource getInactiveSystemTextColor() + { + if (theme != null) + return theme.getInactiveSystemTextColor(); + return null; + } + + /** + * Returns the background color for menu items, from the installed theme. + * + * @return The background color for menu items. + * + * @see #getMenuSelectedBackground() + */ + public static ColorUIResource getMenuBackground() + { + if (theme != null) + return theme.getMenuBackground(); + return null; + } + + /** + * Returns the foreground color for disabled menu items, from the installed + * theme. + * + * @return The foreground color for disabled menu items. + * + * @see #getMenuForeground() + */ + public static ColorUIResource getMenuDisabledForeground() + { + if (theme != null) + return theme.getMenuDisabledForeground(); + return null; + } + + /** + * Returns the foreground color for menu items, from the installed theme. + * + * @return The foreground color for menu items. + * + * @see #getMenuDisabledForeground() + * @see #getMenuSelectedForeground() + */ + public static ColorUIResource getMenuForeground() + { + if (theme != null) + return theme.getMenuForeground(); + return null; + } + + /** + * Returns the background color for selected menu items, from the installed + * theme. + * + * @return The background color for selected menu items. + * + * @see #getMenuBackground() + */ + public static ColorUIResource getMenuSelectedBackground() + { + if (theme != null) + return theme.getMenuSelectedBackground(); + return null; + } + + /** + * Returns the foreground color for selected menu items, from the installed + * theme. + * + * @return The foreground color for selected menu items. + * + * @see #getMenuForeground() + */ + public static ColorUIResource getMenuSelectedForeground() + { + if (theme != null) + return theme.getMenuSelectedForeground(); + return null; + } + + /** + * Returns the font used for text in menus, from the installed theme. + * + * @return The font used for text in menus. + */ + public static FontUIResource getMenuTextFont() + { + if (theme != null) + return theme.getMenuTextFont(); + return null; + } + + /** + * Returns the primary color for controls, from the installed theme. + * + * @return The primary color for controls. + */ + public static ColorUIResource getPrimaryControl() + { + if (theme != null) + return theme.getPrimaryControl(); + return null; + } + + /** + * Returns the primary color for the dark shadow on controls, from the + * installed theme. + * + * @return The primary color for the dark shadow on controls. + */ + public static ColorUIResource getPrimaryControlDarkShadow() + { + if (theme != null) + return theme.getPrimaryControlDarkShadow(); + return null; + } + + /** + * Returns the primary color for the highlight on controls, from the + * installed theme. + * + * @return The primary color for the highlight on controls. + */ + public static ColorUIResource getPrimaryControlHighlight() + { + if (theme != null) + return theme.getPrimaryControlHighlight(); + return null; + } + + /** + * Returns the primary color for the information on controls, from the + * installed theme. + * + * @return The primary color for the information on controls. + */ + public static ColorUIResource getPrimaryControlInfo() + { + if (theme != null) + return theme.getPrimaryControlInfo(); + return null; + } + + /** + * Returns the primary color for the shadow on controls, from the installed + * theme. + * + * @return The primary color for the shadow on controls. + */ + public static ColorUIResource getPrimaryControlShadow() + { + if (theme != null) + return theme.getPrimaryControlShadow(); + return null; + } + + /** + * Returns the background color for separators, from the installed theme. + * + * @return The background color for separators. + */ + public static ColorUIResource getSeparatorBackground() + { + if (theme != null) + return theme.getSeparatorBackground(); + return null; + } + + /** + * Returns the foreground color for separators, from the installed theme. + * + * @return The foreground color for separators. + */ + public static ColorUIResource getSeparatorForeground() + { + if (theme != null) + return theme.getSeparatorForeground(); + return null; + } + + /** + * Returns the font used for sub text, from the installed theme. + * + * @return The font used for sub text. + */ + public static FontUIResource getSubTextFont() + { + if (theme != null) + return theme.getSubTextFont(); + return null; + } + + /** + * Returns the color used for system text, from the installed theme. + * + * @return The color used for system text. + */ + public static ColorUIResource getSystemTextColor() + { + if (theme != null) + return theme.getSystemTextColor(); + return null; + } + + /** + * Returns the font used for system text, from the installed theme. + * + * @return The font used for system text. + */ + public static FontUIResource getSystemTextFont() + { + if (theme != null) + return theme.getSystemTextFont(); + return null; + } + + /** + * Returns the color used to highlight text, from the installed theme. + * + * @return The color used to highlight text. + */ + public static ColorUIResource getTextHighlightColor() + { + if (theme != null) + return theme.getTextHighlightColor(); + return null; + } + + /** + * Returns the color used to display user text, from the installed theme. + * + * @return The color used to display user text. + */ + public static ColorUIResource getUserTextColor() + { + if (theme != null) + return theme.getUserTextColor(); + return null; + } + + /** + * Returns the font used for user text, obtained from the current theme. + * + * @return The font used for user text. + */ + public static FontUIResource getUserTextFont() + { + if (theme != null) + return theme.getUserTextFont(); + return null; + } + + /** + * Returns the color used for white, from the installed theme. + * + * @return The color used for white. + */ + public static ColorUIResource getWhite() + { + if (theme != null) + return theme.getWhite(); + return null; + } + + /** + * Returns the window background color, from the installed theme. + * + * @return The window background color. + */ + public static ColorUIResource getWindowBackground() + { + if (theme != null) + return theme.getWindowBackground(); + return null; + } + + /** + * Returns the window title background color, from the installed theme. + * + * @return The window title background color. + */ + public static ColorUIResource getWindowTitleBackground() + { + if (theme != null) + return theme.getWindowTitleBackground(); + return null; + } + + /** + * Returns the window title font from the current theme. + * + * @return The window title font. + * + * @see MetalTheme + */ + public static FontUIResource getWindowTitleFont() + { + if (theme != null) + return theme.getWindowTitleFont(); + return null; + } + + /** + * Returns the window title foreground color, from the installed theme. + * + * @return The window title foreground color. + */ + public static ColorUIResource getWindowTitleForeground() + { + if (theme != null) + return theme.getWindowTitleForeground(); + return null; + } + + /** + * Returns the background color for an inactive window title, from the + * installed theme. + * + * @return The background color for an inactive window title. + */ + public static ColorUIResource getWindowTitleInactiveBackground() + { + if (theme != null) + return theme.getWindowTitleInactiveBackground(); + return null; + } + + /** + * Returns the foreground color for an inactive window title, from the + * installed theme. + * + * @return The foreground color for an inactive window title. + */ + public static ColorUIResource getWindowTitleInactiveForeground() + { + if (theme != null) + return theme.getWindowTitleInactiveForeground(); + return null; + } + + /** + * Sets the current theme for the look and feel. Note that the theme must be + * set <em>before</em> the look and feel is installed. To change the theme + * for an already running application that is using the + * {@link MetalLookAndFeel}, first set the theme with this method, then + * create a new instance of {@link MetalLookAndFeel} and install it in the + * usual way (see {@link UIManager#setLookAndFeel(LookAndFeel)}). + * + * @param theme the theme (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>theme</code> is <code>null</code>. + * + * @see #getCurrentTheme() + */ + public static void setCurrentTheme(MetalTheme theme) + { + if (theme == null) + throw new NullPointerException("Null 'theme' not permitted."); + MetalLookAndFeel.theme = theme; + } + + /** + * Sets the ComponentUI classes for all Swing components to the Metal + * implementations. + * + * In particular this sets the following keys: + * + * <table> + * <tr> + * <th>Key</th><th>Value</th> + * </tr><tr> + * <td>ButtonUI</td><td>{@link MetalButtonUI}</td> + * </tr><tr> + * <td>CheckBoxUI</td><td>{@link MetalCheckBoxUI}</td> + * </tr><tr> + * <td>ComboBoxUI</td><td>{@link MetalComboBoxUI}</td> + * </tr><tr> + * <td>DesktopIconUI</td><td>{@link MetalDesktopIconUI}</td> + * </tr><tr> + * <td>InternalFrameUI</td><td>{@link MetalInternalFrameUI}</td> + * </tr><tr> + * <td>LabelUI</td><td>{@link MetalLabelUI}</td> + * </tr><tr> + * <td>PopupMenuSeparatorUI</td><td>{@link MetalPopupMenuSeparatorUI}</td> + * </tr><tr> + * <td>ProgressBarUI</td><td>{@link MetalProgressBarUI}</td> + * </tr><tr> + * <td>RadioButtonUI</td><td>{@link MetalRadioButtonUI}</td> + * </tr><tr> + * <td>RootPaneUI</td><td>{@link MetalRootPaneUI}</td> + * </tr><tr> + * <td>ScrollBarUI</td><td>{@link MetalScrollBarUI}</td> + * </tr><tr> + * <td>ScrollPaneUI</td><td>{@link MetalScrollPaneUI}</td> + * </tr><tr> + * <td>SeparatorUI</td><td>{@link MetalSeparatorUI}</td> + * </tr><tr> + * <td>SliderUI</td><td>{@link MetalSliderUI}</td> + * </tr><tr> + * <td>SplitPaneUI</td><td>{@link MetalSplitPaneUI}</td> + * </tr><tr> + * <td>TabbedPaneUI</td><td>{@link MetalTabbedPaneUI}</td> + * </tr><tr> + * <td>TextFieldUI</td><td>{@link MetalTextFieldUI}</td> + * </tr><tr> + * <td>ToggleButtonUI</td><td>{@link MetalToggleButtonUI}</td> + * </tr><tr> + * <td>ToolBarUI</td><td>{@link MetalToolBarUI}</td> + * </tr><tr> + * <td>ToolTipUI</td><td>{@link MetalToolTipUI}</td> + * </tr><tr> + * <td>TreeUI</td><td>{@link MetalTreeUI}</td> + * </tr><tr> + * </table> + * + * @param defaults the UIDefaults where the class defaults are added + */ + protected void initClassDefaults(UIDefaults defaults) + { + super.initClassDefaults(defaults); + + // Variables + Object[] uiDefaults; + // Initialize Class Defaults + uiDefaults = new Object[] { + "ButtonUI", "javax.swing.plaf.metal.MetalButtonUI", + "CheckBoxUI", "javax.swing.plaf.metal.MetalCheckBoxUI", + "ComboBoxUI", "javax.swing.plaf.metal.MetalComboBoxUI", + "DesktopIconUI", "javax.swing.plaf.metal.MetalDesktopIconUI", + "FileChooserUI", "javax.swing.plaf.metal.MetalFileChooserUI", + "InternalFrameUI", "javax.swing.plaf.metal.MetalInternalFrameUI", + "LabelUI", "javax.swing.plaf.metal.MetalLabelUI", + "MenuBarUI", "javax.swing.plaf.metal.MetalMenuBarUI", + "PopupMenuSeparatorUI", + "javax.swing.plaf.metal.MetalPopupMenuSeparatorUI", + "ProgressBarUI", "javax.swing.plaf.metal.MetalProgressBarUI", + "RadioButtonUI", "javax.swing.plaf.metal.MetalRadioButtonUI", + "RootPaneUI", "javax.swing.plaf.metal.MetalRootPaneUI", + "ScrollBarUI", "javax.swing.plaf.metal.MetalScrollBarUI", + "ScrollPaneUI", "javax.swing.plaf.metal.MetalScrollPaneUI", + "SeparatorUI", "javax.swing.plaf.metal.MetalSeparatorUI", + "SliderUI", "javax.swing.plaf.metal.MetalSliderUI", + "SplitPaneUI", "javax.swing.plaf.metal.MetalSplitPaneUI", + "TabbedPaneUI", "javax.swing.plaf.metal.MetalTabbedPaneUI", + "TextFieldUI", "javax.swing.plaf.metal.MetalTextFieldUI", + "ToggleButtonUI", "javax.swing.plaf.metal.MetalToggleButtonUI", + "ToolBarUI", "javax.swing.plaf.metal.MetalToolBarUI", + "ToolTipUI", "javax.swing.plaf.metal.MetalToolTipUI", + "TreeUI", "javax.swing.plaf.metal.MetalTreeUI", + }; + // Add Class Defaults to UI Defaults table + defaults.putDefaults(uiDefaults); + } + + /** + * Initializes the component defaults for the Metal Look & Feel. + * + * In particular this sets the following keys (the colors are given + * as RGB hex values): + * + * <table> + * <tr> + * <th>Key</th><th>Value</th> + * </tr><tr> + * <td>Button.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>Button.border</td><td>{@link MetalBorders#getButtonBorder()}</td> + * </tr><tr> + * <td>Button.font</td><td>{@link #getControlTextFont}</td> + * </tr><tr> + * <td>Button.margin</td><td><code>new java.awt.Insets(2, 14, 2, 14)</code> + * </td> + * </tr><tr> + * <td>CheckBox.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>CheckBoxMenuItem.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>ToolBar.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>Panel.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>Slider.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>OptionPane.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>ProgressBar.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>TabbedPane.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>Label.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>Label.font</td><td>{@link #getControlTextFont}</td> + * </tr><tr> + * <td>Menu.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>MenuBar.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>MenuItem.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>ScrollBar.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>PopupMenu.border</td> + * <td><code>new javax.swing.plaf.metal.MetalBorders.PopupMenuBorder()</td> + * </tr><tr> + * </table> + * + * @param defaults the UIDefaults instance to which the values are added + */ + protected void initComponentDefaults(UIDefaults defaults) + { + super.initComponentDefaults(defaults); + Object[] myDefaults = new Object[] { + "Button.background", getControl(), + "Button.border", MetalBorders.getButtonBorder(), + "Button.darkShadow", getControlDarkShadow(), + "Button.disabledText", getInactiveControlTextColor(), + "Button.focus", getFocusColor(), + "Button.font", getControlTextFont(), + "Button.foreground", getControlTextColor(), + "Button.highlight", getControlHighlight(), + "Button.light", getControlHighlight(), + "Button.margin", new InsetsUIResource(2, 14, 2, 14), + "Button.select", getControlShadow(), + "Button.shadow", getControlShadow(), + + "CheckBox.background", getControl(), + "CheckBox.border", MetalBorders.getButtonBorder(), + "CheckBox.disabledText", getInactiveControlTextColor(), + "CheckBox.focus", getFocusColor(), + "CheckBox.font", getControlTextFont(), + "CheckBox.foreground", getControlTextColor(), + "CheckBox.icon", + new UIDefaults.ProxyLazyValue("javax.swing.plaf.metal.MetalCheckBoxIcon"), + "CheckBox.checkIcon", + new UIDefaults.ProxyLazyValue("javax.swing.plaf.metal.MetalCheckBoxIcon"), + "Checkbox.select", getControlShadow(), + + "CheckBoxMenuItem.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 10), + "CheckBoxMenuItem.acceleratorForeground", getAcceleratorForeground(), + "CheckBoxMenuItem.acceleratorSelectionForeground", getAcceleratorSelectedForeground(), + "CheckBoxMenuItem.background", getMenuBackground(), + "CheckBoxMenuItem.borderPainted", Boolean.TRUE, + "CheckBoxMenuItem.commandSound", "sounds/MenuItemCommand.wav", + "CheckBoxMenuItem.checkIcon", MetalIconFactory.getCheckBoxMenuItemIcon(), + "CheckBoxMenuItem.disabledForeground", getMenuDisabledForeground(), + "CheckBoxMenuItem.font", getMenuTextFont(), + "CheckBoxMenuItem.foreground", getMenuForeground(), + "CheckBoxMenuItem.selectionBackground", getMenuSelectedBackground(), + "CheckBoxMenuItem.selectionForeground", getMenuSelectedForeground(), + + "ColorChooser.background", getControl(), + "ColorChooser.foreground", getControlTextColor(), + "ColorChooser.rgbBlueMnemonic", new Integer(0), + "ColorChooser.rgbGreenMnemonic", new Integer(0), + "ColorChooser.rgbRedMnemonic", new Integer(0), + "ColorChooser.swatchesDefaultRecentColor", getControl(), + + "ComboBox.background", getControl(), + "ComboBox.buttonBackground", getControl(), + "ComboBox.buttonDarkShadow", getControlDarkShadow(), + "ComboBox.buttonHighlight", getControlHighlight(), + "ComboBox.buttonShadow", getControlShadow(), + "ComboBox.disabledBackground", getControl(), + "ComboBox.disabledForeground", getInactiveSystemTextColor(), + "ComboBox.font", getControlTextFont(), + "ComboBox.foreground", getControlTextColor(), + "ComboBox.selectionBackground", getPrimaryControlShadow(), + "ComboBox.selectionForeground", getControlTextColor(), + + "Desktop.background", getDesktopColor(), + + "DesktopIcon.background", getControl(), + "DesktopIcon.foreground", getControlTextColor(), + "DesktopIcon.width", new Integer(160), + "DesktopIcon.border", MetalBorders.getDesktopIconBorder(), + "DesktopIcon.font", getControlTextFont(), + + "EditorPane.background", getWindowBackground(), + "EditorPane.caretForeground", getUserTextColor(), + "EditorPane.font", getControlTextFont(), + "EditorPane.foreground", getUserTextColor(), + "EditorPane.inactiveForeground", getInactiveSystemTextColor(), + "EditorPane.selectionBackground", getTextHighlightColor(), + "EditorPane.selectionForeground", getHighlightedTextColor(), + + "FormattedTextField.background", getWindowBackground(), + "FormattedTextField.border", + new BorderUIResource(MetalBorders.getTextFieldBorder()), + "FormattedTextField.caretForeground", getUserTextColor(), + "FormattedTextField.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "FormattedTextField.foreground", getUserTextColor(), + "FormattedTextField.inactiveBackground", getControl(), + "FormattedTextField.inactiveForeground", getInactiveSystemTextColor(), + "FormattedTextField.selectionBackground", getTextHighlightColor(), + "FormattedTextField.selectionForeground", getHighlightedTextColor(), + + "FileChooser.upFolderIcon", + MetalIconFactory.getFileChooserUpFolderIcon(), + "FileChooser.listViewIcon", + MetalIconFactory.getFileChooserListViewIcon(), + "FileChooser.newFolderIcon", + MetalIconFactory.getFileChooserNewFolderIcon(), + "FileChooser.homeFolderIcon", + MetalIconFactory.getFileChooserHomeFolderIcon(), + "FileChooser.detailsViewIcon", + MetalIconFactory.getFileChooserDetailViewIcon(), + "FileChooser.fileNameLabelMnemonic", new Integer(78), + "FileChooser.filesOfTypeLabelMnemonic", new Integer(84), + "FileChooser.lookInLabelMnemonic", new Integer(73), + "FileView.computerIcon", MetalIconFactory.getTreeComputerIcon(), + "FileView.directoryIcon", MetalIconFactory.getTreeFolderIcon(), + "FileView.fileIcon", MetalIconFactory.getTreeLeafIcon(), + "FileView.floppyDriveIcon", MetalIconFactory.getTreeFloppyDriveIcon(), + "FileView.hardDriveIcon", MetalIconFactory.getTreeHardDriveIcon(), + + "InternalFrame.activeTitleBackground", getWindowTitleBackground(), + "InternalFrame.activeTitleForeground", getWindowTitleForeground(), + "InternalFrame.border", new MetalBorders.InternalFrameBorder(), + "InternalFrame.borderColor", getControl(), + "InternalFrame.borderDarkShadow", getControlDarkShadow(), + "InternalFrame.borderHighlight", getControlHighlight(), + "InternalFrame.borderLight", getControlHighlight(), + "InternalFrame.borderShadow", getControlShadow(), + "InternalFrame.icon", MetalIconFactory.getInternalFrameDefaultMenuIcon(), + "InternalFrame.closeIcon", + MetalIconFactory.getInternalFrameCloseIcon(16), + "InternalFrame.closeSound", "sounds/FrameClose.wav", + "InternalFrame.inactiveTitleBackground", getWindowTitleInactiveBackground(), + "InternalFrame.inactiveTitleForeground", getWindowTitleInactiveForeground(), + "InternalFrame.maximizeIcon", + MetalIconFactory.getInternalFrameMaximizeIcon(16), + "InternalFrame.maximizeSound", "sounds/FrameMaximize.wav", + "InternalFrame.iconifyIcon", + MetalIconFactory.getInternalFrameMinimizeIcon(16), + "InternalFrame.minimizeSound", "sounds/FrameMinimize.wav", + "InternalFrame.paletteBorder", new MetalBorders.PaletteBorder(), + "InternalFrame.paletteCloseIcon", new MetalIconFactory.PaletteCloseIcon(), + "InternalFrame.paletteTitleHeight", new Integer(11), + "InternalFrame.restoreDownSound", "sounds/FrameRestoreDown.wav", + "InternalFrame.restoreUpSound", "sounds/FrameRestoreUp.wav", + + "Label.background", getControl(), + "Label.disabledForeground", getInactiveSystemTextColor(), + "Label.disabledShadow", getControlShadow(), + "Label.font", getControlTextFont(), + "Label.foreground", getSystemTextColor(), + + "List.font", getControlTextFont(), + "List.background", getWindowBackground(), + "List.foreground", getUserTextColor(), + "List.selectionBackground", getTextHighlightColor(), + "List.selectionForeground", getHighlightedTextColor(), + "List.focusCellHighlightBorder", + new LineBorderUIResource(MetalLookAndFeel.getFocusColor()), + + "Menu.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 10), + "Menu.acceleratorForeground", getAcceleratorForeground(), + "Menu.acceleratorSelectionForeground", getAcceleratorSelectedForeground(), + "Menu.arrowIcon", MetalIconFactory.getMenuArrowIcon(), + "Menu.background", getMenuBackground(), + "Menu.border", new MetalBorders.MenuItemBorder(), + "Menu.borderPainted", Boolean.TRUE, + "MenuItem.commandSound", "sounds/MenuItemCommand.wav", + "Menu.disabledForeground", getMenuDisabledForeground(), + "Menu.font", getMenuTextFont(), + "Menu.foreground", getMenuForeground(), + "Menu.selectionBackground", getMenuSelectedBackground(), + "Menu.selectionForeground", getMenuSelectedForeground(), + "Menu.submenuPopupOffsetX", new Integer(-4), + "Menu.submenuPopupOffsetY", new Integer(-3), + + "MenuBar.background", getMenuBackground(), + "MenuBar.border", new MetalBorders.MenuBarBorder(), + "MenuBar.font", getMenuTextFont(), + "MenuBar.foreground", getMenuForeground(), + "MenuBar.highlight", getControlHighlight(), + "MenuBar.shadow", getControlShadow(), + + "MenuItem.acceleratorDelimiter", "-", + "MenuItem.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 10), + "MenuItem.acceleratorForeground", getAcceleratorForeground(), + "MenuItem.acceleratorSelectionForeground", getAcceleratorSelectedForeground(), + "MenuItem.arrowIcon", MetalIconFactory.getMenuItemArrowIcon(), + "MenuItem.background", getMenuBackground(), + "MenuItem.border", new MetalBorders.MenuItemBorder(), + "MenuItem.borderPainted", Boolean.TRUE, + "MenuItem.disabledForeground", getMenuDisabledForeground(), + "MenuItem.font", getMenuTextFont(), + "MenuItem.foreground", getMenuForeground(), + "MenuItem.selectionBackground", getMenuSelectedBackground(), + "MenuItem.selectionForeground", getMenuSelectedForeground(), + + "OptionPane.background", getControl(), + "OptionPane.errorSound", "sounds/OptionPaneError.wav", + "OptionPane.informationSound", "sounds/OptionPaneInformation.wav", + "OptionPane.questionSound", "sounds/OptionPaneQuestion.wav", + "OptionPane.warningSound", "sounds/OptionPaneWarning.wav", + "OptionPane.errorDialog.border.background", new ColorUIResource(153, 51, 51), + "OptionPane.errorDialog.titlePane.background", new ColorUIResource(255, 153, 153), + "OptionPane.errorDialog.titlePane.foreground", new ColorUIResource(51, 0, 0), + "OptionPane.errorDialog.titlePane.shadow", new ColorUIResource(204, 102, 102), + "OptionPane.foreground", getControlTextColor(), + "OptionPane.messageForeground", getControlTextColor(), + "OptionPane.questionDialog.border.background", new ColorUIResource(51, 102, 51), + "OptionPane.questionDialog.titlePane.background", new ColorUIResource(153, 204, 153), + "OptionPane.questionDialog.titlePane.foreground", new ColorUIResource(0, 51, 0), + "OptionPane.questionDialog.titlePane.shadow", new ColorUIResource(102, 153, 102), + "OptionPane.warningDialog.border.background", new ColorUIResource(153, 102, 51), + "OptionPane.warningDialog.titlePane.background", new ColorUIResource(255, 204, 153), + "OptionPane.warningDialog.titlePane.foreground", new ColorUIResource(102, 51, 0), + "OptionPane.warningDialog.titlePane.shadow", new ColorUIResource(204, 153, 102), + + "Panel.background", getControl(), + "Panel.foreground", getUserTextColor(), + + "PasswordField.background", getWindowBackground(), + "PasswordField.border", + new BorderUIResource(MetalBorders.getTextFieldBorder()), + "PasswordField.caretForeground", getUserTextColor(), + "PasswordField.foreground", getUserTextColor(), + "PasswordField.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "PasswordField.inactiveBackground", getControl(), + "PasswordField.inactiveForeground", getInactiveSystemTextColor(), + "PasswordField.selectionBackground", getTextHighlightColor(), + "PasswordField.selectionForeground", getHighlightedTextColor(), + + "PopupMenu.background", getMenuBackground(), + "PopupMenu.border", new MetalBorders.PopupMenuBorder(), + "PopupMenu.font", getMenuTextFont(), + "PopupMenu.foreground", getMenuForeground(), + "PopupMenu.popupSound", "sounds/PopupMenuPopup.wav", + + "ProgressBar.background", getControl(), + "ProgressBar.border", new BorderUIResource.LineBorderUIResource(getControlDarkShadow(), 1), + "ProgressBar.font", getControlTextFont(), + "ProgressBar.foreground", getPrimaryControlShadow(), + "ProgressBar.selectionBackground", getPrimaryControlDarkShadow(), + "ProgressBar.selectionForeground", getControl(), + + "RadioButton.background", getControl(), + "RadioButton.darkShadow", getControlDarkShadow(), + "RadioButton.disabledText", getInactiveControlTextColor(), + "RadioButton.icon", + new UIDefaults.LazyValue() + { + public Object createValue(UIDefaults def) + { + return MetalIconFactory.getRadioButtonIcon(); + } + }, + "RadioButton.focus", MetalLookAndFeel.getFocusColor(), + "RadioButton.font", MetalLookAndFeel.getControlTextFont(), + "RadioButton.foreground", getControlTextColor(), + "RadioButton.highlight", getControlHighlight(), + "RadioButton.light", getControlHighlight(), + "RadioButton.select", getControlShadow(), + "RadioButton.shadow", getControlShadow(), + + "RadioButtonMenuItem.acceleratorFont", new Font("Dialog", Font.PLAIN, 10), + "RadioButtonMenuItem.acceleratorForeground", getAcceleratorForeground(), + "RadioButtonMenuItem.acceleratorSelectionForeground", getAcceleratorSelectedForeground(), + "RadioButtonMenuItem.background", getMenuBackground(), + "RadioButtonMenuItem.border", new MetalBorders.MenuItemBorder(), + "RadioButtonMenuItem.borderPainted", Boolean.TRUE, + "RadioButtonMenuItem.checkIcon", + MetalIconFactory.getRadioButtonMenuItemIcon(), + "RadioButtonMenuItem.commandSound", "sounds/MenuItemCommand.wav", + "RadioButtonMenuItem.disabledForeground", getMenuDisabledForeground(), + "RadioButtonMenuItem.font", getMenuTextFont(), + "RadioButtonMenuItem.foreground", getMenuForeground(), + "RadioButtonMenuItem.margin", new InsetsUIResource(2, 2, 2, 2), + "RadioButtonMenuItem.selectionBackground", + MetalLookAndFeel.getMenuSelectedBackground(), + "RadioButtonMenuItem.selectionForeground", + MetalLookAndFeel.getMenuSelectedForeground(), + + "ScrollBar.allowsAbsolutePositioning", Boolean.TRUE, + "ScrollBar.background", getControl(), + "ScrollBar.darkShadow", getControlDarkShadow(), + "ScrollBar.foreground", getControl(), + "ScrollBar.highlight", getControlHighlight(), + "ScrollBar.shadow", getControlShadow(), + "ScrollBar.thumb", getPrimaryControlShadow(), + "ScrollBar.thumbDarkShadow", getControlDarkShadow(), + "ScrollBar.thumbHighlight", getPrimaryControl(), + "ScrollBar.thumbShadow", getPrimaryControlDarkShadow(), + "ScrollBar.track", getControl(), + "ScrollBar.trackHighlight", getControlDarkShadow(), + "ScrollBar.width", new Integer(17), + + "ScrollPane.background", getControl(), + "ScrollPane.border", new MetalBorders.ScrollPaneBorder(), + "ScrollPane.foreground", getControlTextColor(), + + "Separator.background", getSeparatorBackground(), + "Separator.foreground", getSeparatorForeground(), + "Separator.highlight", getControlHighlight(), + "Separator.shadow", getControlShadow(), + + "Slider.background", getControl(), + "Slider.focus", getFocusColor(), + "Slider.focusInsets", new InsetsUIResource(0, 0, 0, 0), + "Slider.foreground", getPrimaryControlShadow(), + "Slider.highlight", getControlHighlight(), + "Slider.horizontalThumbIcon", + MetalIconFactory.getHorizontalSliderThumbIcon(), + "Slider.majorTickLength", new Integer(6), + "Slider.shadow", getControlShadow(), + "Slider.trackWidth", new Integer(7), + "Slider.verticalThumbIcon", + MetalIconFactory.getVerticalSliderThumbIcon(), + + "Spinner.arrowButtonInsets", new InsetsUIResource(0, 0, 0, 0), + "Spinner.background", getControl(), + "Spinner.border", MetalBorders.getTextFieldBorder(), + "Spinner.font", getControlTextFont(), + "Spinner.foreground", getControl(), + + "SplitPane.background", getControl(), + "SplitPane.darkShadow", getControlDarkShadow(), + "SplitPane.dividerFocusColor", getPrimaryControl(), + "SplitPane.dividerSize", new Integer(10), + "SplitPane.highlight", getControlHighlight(), + "SplitPane.shadow", getControlShadow(), + + "SplitPaneDivider.draggingColor", Color.DARK_GRAY, + + "TabbedPane.background", getControlShadow(), + "TabbedPane.contentBorderInsets", new InsetsUIResource(2, 2, 3, 3), + "TabbedPane.contentOpaque", Boolean.TRUE, + "TabbedPane.darkShadow", getControlDarkShadow(), + "TabbedPane.focus", getPrimaryControlDarkShadow(), + "TabbedPane.font", getControlTextFont(), + "TabbedPane.foreground", getControlTextColor(), + "TabbedPane.highlight", getControlHighlight(), + "TabbedPane.light", getControl(), + "TabbedPane.selected", getControl(), // overridden in OceanTheme + "TabbedPane.selectHighlight", getControlHighlight(), + "TabbedPane.selectedTabPadInsets", new InsetsUIResource(2, 2, 2, 1), + "TabbedPane.shadow", getControlShadow(), + "TabbedPane.tabAreaBackground", getControl(), // overridden in OceanTheme + "TabbedPane.tabAreaInsets", new InsetsUIResource(4, 2, 0, 6), // dito + "TabbedPane.tabInsets", new InsetsUIResource(0, 9, 1, 9), + + // new properties in OceanTheme: + // TabbedPane.contentAreaColor + // TabbedPane.unselectedBackground + + "Table.background", getWindowBackground(), + "Table.focusCellBackground", getWindowBackground(), + "Table.focusCellForeground", getControlTextColor(), + "Table.foreground", getControlTextColor(), + "Table.focusCellHighlightBorder", + new BorderUIResource.LineBorderUIResource(getFocusColor()), + "Table.focusCellBackground", getWindowBackground(), + "Table.gridColor", getControlDarkShadow(), + "Table.selectionBackground", new ColorUIResource(204, 204, 255), + "Table.selectionForeground", new ColorUIResource(0, 0, 0), + + "TableHeader.background", getControl(), + "TableHeader.cellBorder", new MetalBorders.TableHeaderBorder(), + "TableHeader.foreground", getControlTextColor(), + + "TextArea.background", getWindowBackground(), + "TextArea.caretForeground", getUserTextColor(), + "TextArea.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "TextArea.foreground", getUserTextColor(), + "TextArea.inactiveForeground", getInactiveSystemTextColor(), + "TextArea.selectionBackground", getTextHighlightColor(), + "TextArea.selectionForeground", getHighlightedTextColor(), + + "TextField.background", getWindowBackground(), + "TextField.border", + new BorderUIResource(MetalBorders.getTextFieldBorder()), + "TextField.caretForeground", getUserTextColor(), + "TextField.darkShadow", getControlDarkShadow(), + "TextField.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "TextField.foreground", getUserTextColor(), + "TextField.highlight", getControlHighlight(), + "TextField.inactiveBackground", getControl(), + "TextField.inactiveForeground", getInactiveSystemTextColor(), + "TextField.light", getControlHighlight(), + "TextField.selectionBackground", getTextHighlightColor(), + "TextField.selectionForeground", getHighlightedTextColor(), + "TextField.shadow", getControlShadow(), + + "TextPane.background", getWindowBackground(), + "TextPane.caretForeground", getUserTextColor(), + "TextPane.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "TextPane.foreground", getUserTextColor(), + "TextPane.inactiveForeground", getInactiveSystemTextColor(), + "TextPane.selectionBackground", getTextHighlightColor(), + "TextPane.selectionForeground", getHighlightedTextColor(), + + "TitledBorder.border", new LineBorderUIResource(getPrimaryControl(), 1), + "TitledBorder.font", getControlTextFont(), + "TitledBorder.titleColor", getSystemTextColor(), + + "ToggleButton.background", getControl(), + "ToggleButton.border", MetalBorders.getToggleButtonBorder(), + "ToggleButton.darkShadow", getControlDarkShadow(), + "ToggleButton.disabledText", getInactiveControlTextColor(), + "ToggleButton.focus", getFocusColor(), + "ToggleButton.font", getControlTextFont(), + "ToggleButton.foreground", getControlTextColor(), + "ToggleButton.highlight", getControlHighlight(), + "ToggleButton.light", getControlHighlight(), + "ToggleButton.margin", new InsetsUIResource(2, 14, 2, 14), + "ToggleButton.select", getControlShadow(), + "ToggleButton.shadow", getControlShadow(), + + "ToolBar.background", getMenuBackground(), + "ToolBar.darkShadow", getControlDarkShadow(), + "ToolBar.dockingBackground", getMenuBackground(), + "ToolBar.dockingForeground", getPrimaryControlDarkShadow(), + "ToolBar.floatingBackground", getMenuBackground(), + "ToolBar.floatingForeground", getPrimaryControl(), + "ToolBar.font", getMenuTextFont(), + "ToolBar.foreground", getMenuForeground(), + "ToolBar.highlight", getControlHighlight(), + "ToolBar.light", getControlHighlight(), + "ToolBar.shadow", getControlShadow(), + "ToolBar.border", new MetalBorders.ToolBarBorder(), + "ToolBar.rolloverBorder", MetalBorders.getToolbarButtonBorder(), + "ToolBar.nonrolloverBorder", MetalBorders.getToolbarButtonBorder(), + + "ToolTip.background", getPrimaryControl(), + "ToolTip.backgroundInactive", getControl(), + "ToolTip.border", new BorderUIResource.LineBorderUIResource(getPrimaryControlDarkShadow(), 1), + "ToolTip.borderInactive", new BorderUIResource.LineBorderUIResource(getControlDarkShadow(), 1), + "ToolTip.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "ToolTip.foreground", getPrimaryControlInfo(), + "ToolTip.foregroundInactive", getControlDarkShadow(), + "ToolTip.hideAccelerator", Boolean.FALSE, + + "Tree.background", getWindowBackground(), + "Tree.closedIcon", MetalIconFactory.getTreeFolderIcon(), + "Tree.collapsedIcon", MetalIconFactory.getTreeControlIcon(true), + "Tree.expandedIcon", MetalIconFactory.getTreeControlIcon(false), + "Tree.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "Tree.foreground", getUserTextColor(), + "Tree.hash", getPrimaryControl(), + "Tree.leafIcon", MetalIconFactory.getTreeLeafIcon(), + "Tree.leftChildIndent", new Integer(7), + "Tree.line", getPrimaryControl(), + "Tree.openIcon", MetalIconFactory.getTreeFolderIcon(), + "Tree.rightChildIndent", new Integer(13), + "Tree.rowHeight", new Integer(0), + "Tree.scrollsOnExpand", Boolean.TRUE, + "Tree.selectionBackground", getTextHighlightColor(), + "Tree.selectionBorder", new BorderUIResource.LineBorderUIResource(new Color(102, 102, 153)), + "Tree.selectionBorderColor", getFocusColor(), + "Tree.selectionForeground", getHighlightedTextColor(), + "Tree.textBackground", getWindowBackground(), + "Tree.textForeground", getUserTextColor(), + + "Viewport.background", getControl(), + "Viewport.foreground", getUserTextColor() + }; + defaults.putDefaults(myDefaults); + } + + /** + * Initializes the system color defaults. + * + * In particular this sets the following keys: + * + * <table> + * <tr> + * <th>Key</th><th>Value</th><th>Description</th> + * </tr><tr> + * <td>control</td><td>0xcccccc</td><td>The default color for components</td> + * </tr> + * </table> + */ + protected void initSystemColorDefaults(UIDefaults defaults) + { + super.initSystemColorDefaults(defaults); + Object[] uiDefaults; + uiDefaults = new Object[] { + "control", new ColorUIResource(getControl()), + "desktop", new ColorUIResource(getDesktopColor()) + }; + defaults.putDefaults(uiDefaults); + } + + /** + * Returns the current theme for the Metal look and feel. The default is + * an instance of {@link OceanTheme}. + * + * @return The current theme (never <code>null</code>). + * + * @see #setCurrentTheme(MetalTheme) + */ + public static MetalTheme getCurrentTheme() + { + if (theme == null) + { + // swing.metalTheme property documented here: + // http://java.sun.com/j2se/1.5.0/docs/guide/swing/1.5/index.html + if ("steel".equals(SystemProperties.getProperty("swing.metalTheme"))) + theme = new DefaultMetalTheme(); + else + theme = new OceanTheme(); + } + return theme; + } + + /** + * Returns <code>true</code> because the Metal look + * and feel supports window decorations for toplevel + * containers. + * + * @return <code>true</code> + */ + public boolean getSupportsWindowDecorations() + { + return true; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalMenuBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalMenuBarUI.java new file mode 100644 index 000000000..35f2b05c0 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalMenuBarUI.java @@ -0,0 +1,94 @@ +/* MetalMenuBarUI.java -- MenuBar UI for the Metal L&F + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Graphics; + +import javax.swing.JComponent; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicMenuBarUI; + +/** + * A UI implementation for MenuBar in the Metal Look & Feel. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public class MetalMenuBarUI extends BasicMenuBarUI +{ + /** + * Creates and returns a new instance of this UI for the specified component. + * + * @param c the component to create a UI for + * + * @return the UI for the component + */ + public static ComponentUI createUI(JComponent c) + { + return new MetalMenuBarUI(); + } + + + /** + * If the property <code>MenuBar.gradient</code> is set, then a gradient + * is painted as background, otherwise the normal superclass behaviour is + * called. + */ + public void update(Graphics g, JComponent c) + { + int height = c.getHeight(); + if (c.isOpaque() + && UIManager.get("MenuBar.gradient") != null + && c.getBackground() instanceof UIResource + && height > 2) + { + MetalUtils.paintGradient(g, 0, 0, c.getWidth(), height, + SwingConstants.VERTICAL, "MenuBar.gradient"); + + paint(g, c); + } + else + super.update(g, c); + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java new file mode 100644 index 000000000..7c580f90f --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java @@ -0,0 +1,77 @@ +/* MetalPopupMenuSeparatorUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.JPopupMenu; +import javax.swing.plaf.ComponentUI; + +/** + * A UI delegate for the {@link JPopupMenu.Separator} component. + */ +public class MetalPopupMenuSeparatorUI + extends MetalSeparatorUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for MetalPopupMenuSeparatorUIs */ + private static MetalPopupMenuSeparatorUI instance; + + /** + * Constructs a new instance of <code>MetalPopupMenuSeparatorUI</code>. + */ + public MetalPopupMenuSeparatorUI() + { + super(); + } + + /** + * Returns a shared instance of <code>MetalPopupMenuSeparatorUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A shared instance of <code>MetalPopupMenuSeparatorUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalPopupMenuSeparatorUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalProgressBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalProgressBarUI.java new file mode 100644 index 000000000..005c5f0d8 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalProgressBarUI.java @@ -0,0 +1,147 @@ +/* MetalProgressBarUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.JComponent; +import javax.swing.JProgressBar; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicProgressBarUI; + +/** + * A UI delegate for the {@link JProgressBar} component. + */ +public class MetalProgressBarUI extends BasicProgressBarUI +{ + /** + * Constructs a new instance of <code>MetalProgressBarUI</code>. + */ + public MetalProgressBarUI() + { + super(); + } + + /** + * Returns a new instance of <code>MetalProgressBarUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A new instance of <code>MetalProgressBarUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalProgressBarUI(); + } + + /** + * Performs the painting for determinate progress bars. This calls the + * superclass behaviour and then adds some highlighting to the upper and left + * edge of the progress bar. + * + * @param g the graphics context + * @param c not used here + */ + public void paintDeterminate(Graphics g, JComponent c) + { + super.paintDeterminate(g, c); + Color saved = g.getColor(); + Insets i = progressBar.getInsets(); + int w = progressBar.getWidth(); + int h = progressBar.getHeight(); + int orientation = progressBar.getOrientation(); + + Color shadow = MetalLookAndFeel.getControlShadow(); + g.setColor(shadow); + + g.drawLine(i.left, i.top, w - i.right, i.top); + g.drawLine(i.left, i.top, i.left, h - i.bottom); + int full = getAmountFull(i, w, h); + if (full > 0) + { + Color darkShadow = MetalLookAndFeel.getPrimaryControlDarkShadow(); + g.setColor(darkShadow); + if (orientation == JProgressBar.HORIZONTAL) + { + g.drawLine(i.left, i.top, i.left, h - i.bottom); + g.drawLine(i.left, i.top, i.left + full - 1, i.top); + } + else + { + if (full >= (h - i.top - i.bottom)) + g.drawLine(i.left, i.top, w - i.right, i.top); + g.drawLine(i.left, h - i.bottom, i.left, h - i.bottom - full); + } + } + g.setColor(saved); + } + + /** + * Performs the painting for indeterminate progress bars. This calls the + * superclass behaviour and then adds some highlighting to the upper and left + * edge of the progress bar. + * + * @param g the graphics context + * @param c not used here + */ + public void paintIndeterminate(Graphics g, JComponent c) + { + super.paintIndeterminate(g, c); + Color saved = g.getColor(); + Insets i = progressBar.getInsets(); + int w = progressBar.getWidth(); + int h = progressBar.getHeight(); + Color shadow = MetalLookAndFeel.getControlShadow(); + g.setColor(shadow); + g.drawLine(i.left, i.top, w - i.right, i.top); + g.drawLine(i.left, i.top, i.left, h - i.bottom); + + boxRect = getBox(boxRect); + Color darkShadow = MetalLookAndFeel.getPrimaryControlDarkShadow(); + g.setColor(darkShadow); + int orientation = progressBar.getOrientation(); + if (orientation == JProgressBar.HORIZONTAL) + g.drawLine(boxRect.x, i.top, boxRect.x + boxRect.width - 1, i.top); + else + g.drawLine(i.left, boxRect.y, i.left, boxRect.y + boxRect.height - 1); + g.setColor(saved); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalRadioButtonUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalRadioButtonUI.java new file mode 100644 index 000000000..0f7f3b101 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalRadioButtonUI.java @@ -0,0 +1,183 @@ +/* MetalRadioButtonUI.java + Copyright (C) 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.JRadioButton; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicRadioButtonUI; + + +/** + * A UI delegate for the {@link JRadioButton} component. + */ +public class MetalRadioButtonUI + extends BasicRadioButtonUI +{ + + /** Used to draw the focus rectangle. */ + protected Color focusColor; + + /** Used to fill the icon when the button is pressed. */ + protected Color selectColor; + + /** Used to draw disabled text. */ + protected Color disabledTextColor; + + /** + * Constructs a new instance of <code>MetalRadioButtonUI</code>. + */ + public MetalRadioButtonUI() + { + super(); + } + + /** + * Returns a new instance of <code>MetalRadioButtonUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A new instance of <code>MetalRadioButtonUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalRadioButtonUI(); + } + + /** + * Sets the default values for the specified button. + * + * @param b the button. + */ + public void installDefaults(AbstractButton b) + { + super.installDefaults(b); + String prefix = getPropertyPrefix(); + disabledTextColor = UIManager.getColor(prefix + "disabledText"); + focusColor = UIManager.getColor(prefix + "focus"); + selectColor = UIManager.getColor(prefix + "select"); + } + + /** + * Clears any defaults set in the installDefaults() method. + * + * @param b the {@link JRadioButton}. + */ + protected void uninstallDefaults(AbstractButton b) + { + super.uninstallDefaults(b); + disabledTextColor = null; + focusColor = null; + selectColor = null; + } + + /** + * Returns the color used to fill the {@link JRadioButton}'s icon when the + * button is pressed. The default color is obtained from the + * {@link UIManager} defaults via an entry with the key + * <code>RadioButton.select</code>. + * + * @return The select color. + */ + protected Color getSelectColor() + { + return selectColor; + } + + /** + * Returns the color for the {@link JRadioButton}'s text when the button is + * disabled. The default color is obtained from the {@link UIManager} + * defaults via an entry with the key <code>RadioButton.disabledText</code>. + * + * @return The disabled text color. + */ + protected Color getDisabledTextColor() + { + return disabledTextColor; + } + + /** + * Returns the color used to draw the focus rectangle when the + * {@link JRadioButton} has the focus. The default color is obtained from + * the {@link UIManager} defaults via an entry with the key + * <code>RadioButton.focus</code>. + * + * @return The color used to draw the focus rectangle. + * + * @see #paintFocus(Graphics, Rectangle, Dimension) + */ + protected Color getFocusColor() + { + return focusColor; + } + + /** + * Paints the {@link JRadioButton}. + * + * @param g the graphics device. + * @param c the component (an instance of {@link JRadioButton}). + */ + public void paint(Graphics g, JComponent c) + { + super.paint(g, c); + // FIXME: disabled text isn't being drawn correctly, it's possible that + // it could be done here... + } + + /** + * Paints the focus rectangle for the {@link JRadioButton}. + * + * @param g the graphics device. + * @param t the bounding rectangle for the text. + * @param d ??? + */ + protected void paintFocus(Graphics g, Rectangle t, Dimension d) + { + g.setColor(focusColor); + g.drawRect(t.x - 1, t.y - 1, t.width + 1, t.height + 1); + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java new file mode 100644 index 000000000..84f1303f6 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java @@ -0,0 +1,1075 @@ +/* MetalRootPaneUI.java + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.LayoutManager2; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JRootPane; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; +import javax.swing.event.MouseInputAdapter; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicRootPaneUI; + +/** + * A UI delegate for the {@link JRootPane} component. This implementation + * supports the JRootPane <code>windowDecorationStyle</code> property. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.4 + */ +public class MetalRootPaneUI + extends BasicRootPaneUI +{ + + /** + * The border that is used on JRootPane when the windowDecorationStyle + * property of the JRootPane is set to a different value than NONE. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private static class MetalFrameBorder + extends AbstractBorder + { + /** + * Returns the border insets. + * + * @param c the component + * @param newInsets the insets to be filled with the return value, may be + * <code>null</code> in which case a new object is created + * + * @return the border insets + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + if (newInsets == null) + newInsets = new Insets(5, 5, 5, 5); + else + { + newInsets.top = 5; + newInsets.left = 5; + newInsets.bottom = 5; + newInsets.right = 5; + } + return newInsets; + } + + /** + * Returns the border insets. + * + * @param c the component + * + * @return the border insets + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + /** + * Paints the border for the specified component. + * + * @param c the component + * @param g the graphics device + * @param x the x-coordinate + * @param y the y-coordinate + * @param w the width + * @param h the height + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + JRootPane f = (JRootPane) c; + Window frame = SwingUtilities.getWindowAncestor(f); + if (frame.isActive()) + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // Fill the border background. + g.fillRect(x, y, w, 5); + g.fillRect(x, y, 5, h); + g.fillRect(x + w - 5, y, 5, h); + g.fillRect(x, y + h - 5, w, 5); + + // Draw a dot in each corner. + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(x, y, 1, 1); + g.fillRect(x + w - 1, y, 1, 1); + g.fillRect(x + w - 1, y + h - 1, 1, 1); + g.fillRect(x, y + h - 1, 1, 1); + + // Draw the lines. + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 14, y + 2, x + w - 15, y + 2); + g.drawLine(x + 14, y + h - 3, x + w - 15, y + h - 3); + g.drawLine(x + 2, y + 14, x + 2, y + h - 15); + g.drawLine(x + w - 3, y + 14, x + w - 3, y + h - 15); + + // Draw the line highlights. + if (frame.isActive()) + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x + 15, y + 3, x + w - 14, y + 3); + g.drawLine(x + 15, y + h - 2, x + w - 14, y + h - 2); + g.drawLine(x + 3, y + 15, x + 3, y + h - 14); + g.drawLine(x + w - 2, y + 15, x + w - 2, y + h - 14); + } + } + + /** + * The component that renders the title bar for frames. This duplicates + * most of {@link MetalInternalFrameTitlePane}. It is not reasonably possible + * to reuse that class because that is bound to the JInternalFrame and we + * need to handle JFrames/JRootPanes here. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private static class MetalTitlePane extends JComponent + { + + /** + * Handles dragging of the title pane and moves the window accordingly. + */ + private class MouseHandler + extends MouseInputAdapter + { + /** + * The point where the dragging started. + */ + Point lastDragLocation; + + /** + * Receives notification when the mouse gets pressed on the title pane. + * This updates the lastDragLocation. + * + * @param ev the mouse event + */ + public void mousePressed(MouseEvent ev) + { + lastDragLocation = ev.getPoint(); + } + + /** + * Receives notification when the mouse is dragged on the title pane. + * This will move the nearest window accordingly. + * + * @param ev the mouse event + */ + public void mouseDragged(MouseEvent ev) + { + Point dragLocation = ev.getPoint(); + int deltaX = dragLocation.x - lastDragLocation.x; + int deltaY = dragLocation.y - lastDragLocation.y; + Window window = SwingUtilities.getWindowAncestor(rootPane); + Point loc = window.getLocation(); + window.setLocation(loc.x + deltaX, loc.y + deltaY); + // Note that we do not update the lastDragLocation. This is because + // we move the underlying window while dragging the component, which + // results in having the same lastDragLocation under the mouse while + // dragging. + } + } + + /** + * The Action responsible for closing the JInternalFrame. + */ + private class CloseAction extends AbstractAction + { + /** + * Creates a new action. + */ + public CloseAction() + { + super("Close"); + } + + /** + * This method is called when something closes the frame. + * + * @param e the ActionEvent + */ + public void actionPerformed(ActionEvent e) + { + Window frame = SwingUtilities.getWindowAncestor(rootPane); + if (frame instanceof JFrame) + { + JFrame jframe = (JFrame) frame; + switch (jframe.getDefaultCloseOperation()) + { + case JFrame.EXIT_ON_CLOSE: + jframe.setVisible(false); + jframe.dispose(); + System.exit(0); + break; + case JFrame.DISPOSE_ON_CLOSE: + jframe.setVisible(false); + jframe.dispose(); + break; + case JFrame.HIDE_ON_CLOSE: + jframe.setVisible(false); + break; + case JFrame.DO_NOTHING_ON_CLOSE: + default: + break; + } + } + else if (frame instanceof JDialog) + { + JDialog jdialog = (JDialog) frame; + switch (jdialog.getDefaultCloseOperation()) + { + case JFrame.DISPOSE_ON_CLOSE: + jdialog.setVisible(false); + jdialog.dispose(); + break; + case JFrame.HIDE_ON_CLOSE: + jdialog.setVisible(false); + break; + case JFrame.DO_NOTHING_ON_CLOSE: + default: + break; + } + } + } + } + + /** + * This action is performed when the iconify button is pressed. + */ + private class IconifyAction + extends AbstractAction + { + + public void actionPerformed(ActionEvent event) + { + Window w = SwingUtilities.getWindowAncestor(rootPane); + if (w instanceof Frame) + { + Frame f = (Frame) w; + int state = f.getExtendedState(); + f.setExtendedState(Frame.ICONIFIED); + } + } + + } + + /** + * This action is performed when the maximize button is pressed. + */ + private class MaximizeAction + extends AbstractAction + { + + public void actionPerformed(ActionEvent event) + { + Window w = SwingUtilities.getWindowAncestor(rootPane); + if (w instanceof Frame) + { + Frame f = (Frame) w; + int state = f.getExtendedState(); + f.setExtendedState(Frame.MAXIMIZED_BOTH); + } + } + } + + /** + * This helper class is used to create the minimize, maximize and close + * buttons in the top right corner of the Title Pane. These buttons are + * special since they cannot be given focus and have no border. + */ + private class PaneButton extends JButton + { + /** + * Creates a new PaneButton object with the given Action. + * + * @param a The Action that the button uses. + */ + public PaneButton(Action a) + { + super(a); + setMargin(new Insets(0, 0, 0, 0)); + } + + /** + * This method returns true if the Component can be focused. + * + * @return false. + */ + public boolean isFocusable() + { + // These buttons cannot be given focus. + return false; + } + + } + + /** + * The layout for the JRootPane when the <code>windowDecorationStyle</code> + * property is set. In addition to the usual JRootPane.RootLayout behaviour + * this lays out the titlePane. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class MetalTitlePaneLayout implements LayoutManager + { + /** + * Creates a new <code>TitlePaneLayout</code> object. + */ + public MetalTitlePaneLayout() + { + // Do nothing. + } + + /** + * Adds a Component to the Container. + * + * @param name The name to reference the added Component by. + * @param c The Component to add. + */ + public void addLayoutComponent(String name, Component c) + { + // Do nothing. + } + + /** + * This method is called to lay out the children of the Title Pane. + * + * @param c The Container to lay out. + */ + public void layoutContainer(Container c) + { + + Dimension size = c.getSize(); + Insets insets = c.getInsets(); + int width = size.width - insets.left - insets.right; + int height = size.height - insets.top - insets.bottom; + + int loc = width - insets.right - 1; + int top = insets.top + 2; + int buttonHeight = height - 4; + if (closeButton.isVisible()) + { + int buttonWidth = closeIcon.getIconWidth(); + loc -= buttonWidth + 2; + closeButton.setBounds(loc, top, buttonWidth, buttonHeight); + loc -= 6; + } + + if (maxButton.isVisible()) + { + int buttonWidth = maxIcon.getIconWidth(); + loc -= buttonWidth + 4; + maxButton.setBounds(loc, top, buttonWidth, buttonHeight); + } + + if (iconButton.isVisible()) + { + int buttonWidth = minIcon.getIconWidth(); + loc -= buttonWidth + 4; + iconButton.setBounds(loc, top, buttonWidth, buttonHeight); + loc -= 2; + } + + Dimension titlePreferredSize = title.getPreferredSize(); + title.setBounds(insets.left + 5, insets.top, + Math.min(titlePreferredSize.width, loc - insets.left - 10), + height); + + } + + /** + * This method returns the minimum size of the given Container given the + * children that it has. + * + * @param c The Container to get a minimum size for. + * + * @return The minimum size of the Container. + */ + public Dimension minimumLayoutSize(Container c) + { + return preferredLayoutSize(c); + } + + /** + * Returns the preferred size of the given Container taking + * into account the children that it has. + * + * @param c The Container to lay out. + * + * @return The preferred size of the Container. + */ + public Dimension preferredLayoutSize(Container c) + { + return new Dimension(22, 22); + } + + /** + * Removes a Component from the Container. + * + * @param c The Component to remove. + */ + public void removeLayoutComponent(Component c) + { + // Nothing to do here. + } + } + + JRootPane rootPane; + + /** The button that closes the JInternalFrame. */ + JButton closeButton; + + /** The button that iconifies the JInternalFrame. */ + JButton iconButton; + + /** The button that maximizes the JInternalFrame. */ + JButton maxButton; + + Icon minIcon; + + /** The icon displayed in the maximize button. */ + Icon maxIcon; + + /** The icon displayed in the iconify button. */ + private Icon iconIcon; + + /** The icon displayed in the close button. */ + Icon closeIcon; + + /** + * The background color of the TitlePane when the JInternalFrame is not + * selected. + */ + private Color notSelectedTitleColor; + + /** + * The background color of the TitlePane when the JInternalFrame is + * selected. + */ + private Color selectedTitleColor; + + /** + * The label used to display the title. This label is not added to the + * TitlePane. + */ + JLabel title; + + /** The action associated with closing the JInternalFrame. */ + private Action closeAction; + + /** The action associated with iconifying the JInternalFrame. */ + private Action iconifyAction; + + /** The action associated with maximizing the JInternalFrame. */ + private Action maximizeAction; + + /** The JMenuBar that is located at the top left of the Title Pane. */ + private JMenuBar menuBar; + + /** The JMenu inside the menuBar. */ + protected JMenu windowMenu; + + MetalTitlePane(JRootPane rp) + { + rootPane = rp; + setLayout(createLayout()); + title = new JLabel(); + title.setHorizontalAlignment(SwingConstants.LEFT); + title.setHorizontalTextPosition(SwingConstants.LEFT); + title.setOpaque(false); + installTitlePane(); + } + + protected LayoutManager createLayout() + { + return new MetalTitlePaneLayout(); + } + + /** + * This method installs the TitlePane onto the JInternalFrameTitlePane. It + * also creates any children components that need to be created and adds + * listeners to the appropriate components. + */ + protected void installTitlePane() + { + installDefaults(); + installListeners(); + createActions(); + assembleSystemMenu(); + createButtons(); + setButtonIcons(); + addSubComponents(); + enableActions(); + } + + private void enableActions() + { + // TODO: Implement this. + } + + private void addSubComponents() + { + add(menuBar); + add(closeButton); + add(iconButton); + add(maxButton); + } + + private void installListeners() + { + MouseInputAdapter mouseHandler = new MouseHandler(); + addMouseListener(mouseHandler); + addMouseMotionListener(mouseHandler); + } + + private void createActions() + { + closeAction = new CloseAction(); + iconifyAction = new IconifyAction(); + maximizeAction = new MaximizeAction(); + } + + private void assembleSystemMenu() + { + menuBar = createSystemMenuBar(); + windowMenu = createSystemMenu(); + menuBar.add(windowMenu); + addSystemMenuItems(windowMenu); + enableActions(); + } + + protected JMenuBar createSystemMenuBar() + { + if (menuBar == null) + menuBar = new JMenuBar(); + menuBar.removeAll(); + return menuBar; + } + + protected JMenu createSystemMenu() + { + if (windowMenu == null) + windowMenu = new JMenu(); + windowMenu.removeAll(); + return windowMenu; + } + + private void addSystemMenuItems(JMenu menu) + { + // TODO: Implement this. + } + + protected void createButtons() + { + closeButton = new PaneButton(closeAction); + closeButton.setText(null); + iconButton = new PaneButton(iconifyAction); + iconButton.setText(null); + maxButton = new PaneButton(maximizeAction); + maxButton.setText(null); + closeButton.setBorderPainted(false); + closeButton.setContentAreaFilled(false); + iconButton.setBorderPainted(false); + iconButton.setContentAreaFilled(false); + maxButton.setBorderPainted(false); + maxButton.setContentAreaFilled(false); + } + + protected void setButtonIcons() + { + if (closeIcon != null && closeButton != null) + closeButton.setIcon(closeIcon); + if (iconIcon != null && iconButton != null) + iconButton.setIcon(iconIcon); + if (maxIcon != null && maxButton != null) + maxButton.setIcon(maxIcon); + } + + /** + * Paints a representation of the current state of the internal frame. + * + * @param g the graphics device. + */ + public void paintComponent(Graphics g) + { + Window frame = SwingUtilities.getWindowAncestor(rootPane); + Color savedColor = g.getColor(); + paintTitleBackground(g); + paintChildren(g); + Dimension d = getSize(); + if (frame.isActive()) + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // put a dot in each of the top corners + g.drawLine(0, 0, 0, 0); + g.drawLine(d.width - 1, 0, d.width - 1, 0); + + g.drawLine(0, d.height - 1, d.width - 1, d.height - 1); + + // draw the metal pattern + if (UIManager.get("InternalFrame.activeTitleGradient") != null + && frame.isActive()) + { + MetalUtils.paintGradient(g, 0, 0, getWidth(), getHeight(), + SwingConstants.VERTICAL, + "InternalFrame.activeTitleGradient"); + } + + Rectangle b = title.getBounds(); + int startX = b.x + b.width + 5; + int endX = startX; + if (iconButton.isVisible()) + endX = Math.max(iconButton.getX(), endX); + else if (maxButton.isVisible()) + endX = Math.max(maxButton.getX(), endX); + else if (closeButton.isVisible()) + endX = Math.max(closeButton.getX(), endX); + endX -= 7; + if (endX > startX) + MetalUtils.fillMetalPattern(this, g, startX, 3, endX - startX, getHeight() - 6, Color.white, Color.gray); + g.setColor(savedColor); + } + + /** + * This method paints the TitlePane's background. + * + * @param g The Graphics object to paint with. + */ + protected void paintTitleBackground(Graphics g) + { + Window frame = SwingUtilities.getWindowAncestor(rootPane); + + if (!isOpaque()) + return; + + Color saved = g.getColor(); + Dimension dims = getSize(); + + Color bg = getBackground(); + if (frame.isActive()) + bg = selectedTitleColor; + else + bg = notSelectedTitleColor; + g.setColor(bg); + g.fillRect(0, 0, dims.width, dims.height); + g.setColor(saved); + } + + /** + * This method installs the defaults determined by the look and feel. + */ + private void installDefaults() + { + title.setFont(UIManager.getFont("InternalFrame.titleFont")); + selectedTitleColor = UIManager.getColor("InternalFrame.activeTitleBackground"); + notSelectedTitleColor = UIManager.getColor("InternalFrame.inactiveTitleBackground"); + closeIcon = UIManager.getIcon("InternalFrame.closeIcon"); + iconIcon = UIManager.getIcon("InternalFrame.iconifyIcon"); + maxIcon = UIManager.getIcon("InternalFrame.maximizeIcon"); + minIcon = MetalIconFactory.getInternalFrameAltMaximizeIcon(16); + Frame frame = (Frame) SwingUtilities.getWindowAncestor(rootPane); + title = new JLabel(frame.getTitle(), + MetalIconFactory.getInternalFrameDefaultMenuIcon(), + SwingConstants.LEFT); + } + } + + private static class MetalRootLayout + implements LayoutManager2 + { + + /** + * The cached layout info for the glass pane. + */ + private Rectangle glassPaneBounds; + + /** + * The cached layout info for the layered pane. + */ + private Rectangle layeredPaneBounds; + + /** + * The cached layout info for the content pane. + */ + private Rectangle contentPaneBounds; + + /** + * The cached layout info for the menu bar. + */ + private Rectangle menuBarBounds; + + /** + * The cached layout info for the title pane. + */ + private Rectangle titlePaneBounds; + + /** + * The cached preferred size. + */ + private Dimension prefSize; + + /** + * The title pane for l&f decorated frames. + */ + private MetalTitlePane titlePane; + + /** + * Creates a new MetalRootLayout. + * + * @param tp the title pane + */ + MetalRootLayout(MetalTitlePane tp) + { + titlePane = tp; + } + + public void addLayoutComponent(Component component, Object constraints) + { + // Nothing to do here. + } + + public Dimension maximumLayoutSize(Container target) + { + return preferredLayoutSize(target); + } + + public float getLayoutAlignmentX(Container target) + { + return 0.0F; + } + + public float getLayoutAlignmentY(Container target) + { + return 0.0F; + } + + public void invalidateLayout(Container target) + { + synchronized (this) + { + glassPaneBounds = null; + layeredPaneBounds = null; + contentPaneBounds = null; + menuBarBounds = null; + titlePaneBounds = null; + prefSize = null; + } + } + + public void addLayoutComponent(String name, Component component) + { + // Nothing to do here. + } + + public void removeLayoutComponent(Component component) + { + // TODO Auto-generated method stub + + } + + public Dimension preferredLayoutSize(Container parent) + { + JRootPane rp = (JRootPane) parent; + JLayeredPane layeredPane = rp.getLayeredPane(); + Component contentPane = rp.getContentPane(); + Component menuBar = rp.getJMenuBar(); + + // We must synchronize here, otherwise we cannot guarantee that the + // prefSize is still non-null when returning. + synchronized (this) + { + if (prefSize == null) + { + Insets i = parent.getInsets(); + prefSize = new Dimension(i.left + i.right, i.top + i.bottom); + Dimension contentPrefSize = contentPane.getPreferredSize(); + prefSize.width += contentPrefSize.width; + prefSize.height += contentPrefSize.height + + titlePane.getPreferredSize().height; + if (menuBar != null) + { + Dimension menuBarSize = menuBar.getPreferredSize(); + if (menuBarSize.width > contentPrefSize.width) + prefSize.width += menuBarSize.width - contentPrefSize.width; + prefSize.height += menuBarSize.height; + } + } + // Return a copy here so the cached value won't get trashed by some + // other component. + return new Dimension(prefSize); + } + } + + public Dimension minimumLayoutSize(Container parent) + { + return preferredLayoutSize(parent); + } + + public void layoutContainer(Container parent) + { + JRootPane rp = (JRootPane) parent; + JLayeredPane layeredPane = rp.getLayeredPane(); + Component contentPane = rp.getContentPane(); + Component menuBar = rp.getJMenuBar(); + Component glassPane = rp.getGlassPane(); + + if (glassPaneBounds == null || layeredPaneBounds == null + || contentPaneBounds == null || menuBarBounds == null) + { + Insets i = rp.getInsets(); + int containerWidth = parent.getBounds().width - i.left - i.right; + int containerHeight = parent.getBounds().height - i.top - i.bottom; + + // 1. The glassPane fills entire viewable region (bounds - insets). + // 2. The layeredPane filles entire viewable region. + // 3. The titlePane is placed at the upper edge of the layeredPane. + // 4. The menuBar is positioned at the upper edge of layeredPane. + // 5. The contentPane fills viewable region minus menuBar minus + // titlePane, if present. + + // +-------------------------------+ + // | JLayeredPane | + // | +--------------------------+ | + // | | titlePane + | + // | +--------------------------+ | + // | +--------------------------+ | + // | | menuBar | | + // | +--------------------------+ | + // | +--------------------------+ | + // | |contentPane | | + // | | | | + // | | | | + // | | | | + // | +--------------------------+ | + // +-------------------------------+ + + // Setup titlePaneBounds. + if (titlePaneBounds == null) + titlePaneBounds = new Rectangle(); + titlePaneBounds.width = containerWidth; + titlePaneBounds.height = titlePane.getPreferredSize().height; + + // Setup menuBarBounds. + if (menuBarBounds == null) + menuBarBounds = new Rectangle(); + menuBarBounds.setBounds(0, + titlePaneBounds.y + titlePaneBounds.height, + containerWidth, 0); + if (menuBar != null) + { + Dimension menuBarSize = menuBar.getPreferredSize(); + if (menuBarSize.height > containerHeight) + menuBarBounds.height = containerHeight; + else + menuBarBounds.height = menuBarSize.height; + } + + // Setup contentPaneBounds. + if (contentPaneBounds == null) + contentPaneBounds = new Rectangle(); + contentPaneBounds.setBounds(0, + menuBarBounds.y + menuBarBounds.height, + containerWidth, + containerHeight - menuBarBounds.y + - menuBarBounds.height); + glassPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight); + layeredPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight); + } + + // Layout components. + glassPane.setBounds(glassPaneBounds); + layeredPane.setBounds(layeredPaneBounds); + if (menuBar != null) + menuBar.setBounds(menuBarBounds); + contentPane.setBounds(contentPaneBounds); + titlePane.setBounds(titlePaneBounds); + } + + } + + /** + * The shared UI instance for MetalRootPaneUIs. + */ + private static MetalRootPaneUI instance; + + /** + * Constructs a shared instance of <code>MetalRootPaneUI</code>. + */ + public MetalRootPaneUI() + { + super(); + } + + /** + * Returns a shared instance of <code>MetalRootPaneUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A shared instance of <code>MetalRootPaneUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalRootPaneUI(); + return instance; + } + + /** + * Installs this UI to the root pane. If the + * <code>windowDecorationsStyle</code> property is set on the root pane, + * the Metal window decorations are installed on the root pane. + * + * @param c + */ + public void installUI(JComponent c) + { + super.installUI(c); + JRootPane rp = (JRootPane) c; + if (rp.getWindowDecorationStyle() != JRootPane.NONE) + installWindowDecorations(rp); + } + + /** + * Uninstalls the UI from the root pane. This performs the superclass + * behaviour and uninstalls the window decorations that have possibly been + * installed by {@link #installUI}. + * + * @param c the root pane + */ + public void uninstallUI(JComponent c) + { + JRootPane rp = (JRootPane) c; + if (rp.getWindowDecorationStyle() != JRootPane.NONE) + uninstallWindowDecorations(rp); + super.uninstallUI(c); + } + + /** + * Receives notification if any of the JRootPane's property changes. In + * particular this catches changes to the <code>windowDecorationStyle</code> + * property and installs the window decorations accordingly. + * + * @param ev the property change event + */ + public void propertyChange(PropertyChangeEvent ev) + { + super.propertyChange(ev); + String propertyName = ev.getPropertyName(); + if (propertyName.equals("windowDecorationStyle")) + { + JRootPane rp = (JRootPane) ev.getSource(); + if (rp.getWindowDecorationStyle() != JRootPane.NONE) + installWindowDecorations(rp); + else + uninstallWindowDecorations(rp); + } + } + + /** + * Installs the window decorations to the root pane. This sets up a border, + * a title pane and a layout manager that can layout the root pane with that + * title pane. + * + * @param rp the root pane. + */ + private void installWindowDecorations(JRootPane rp) + { + rp.setBorder(new MetalFrameBorder()); + MetalTitlePane titlePane = new MetalTitlePane(rp); + rp.setLayout(new MetalRootLayout(titlePane)); + // We should have a contentPane already. + assert rp.getLayeredPane().getComponentCount() > 0 + : "We should have a contentPane already"; + + rp.getLayeredPane().add(titlePane, + JLayeredPane.FRAME_CONTENT_LAYER, 1); + } + + /** + * Uninstalls the window decorations from the root pane. This should rarely + * be necessary, but we do it anyway. + * + * @param rp the root pane + */ + private void uninstallWindowDecorations(JRootPane rp) + { + rp.setBorder(null); + JLayeredPane lp = rp.getLayeredPane(); + for (int i = lp.getComponentCount() - 1; i >= 0; --i) + { + if (lp.getComponent(i) instanceof MetalTitlePane) + { + lp.remove(i); + break; + } + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java new file mode 100644 index 000000000..5f0cbe4be --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java @@ -0,0 +1,584 @@ +/* MetalScrollBarUI.java + Copyright (C) 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JScrollBar; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicScrollBarUI; + +/** + * A UI delegate for the {@link JScrollBar} component. + */ +public class MetalScrollBarUI extends BasicScrollBarUI +{ + + /** + * A property change handler for the UI delegate that monitors for + * changes to the "JScrollBar.isFreeStanding" property, and updates + * the buttons and track rendering as appropriate. + */ + class MetalScrollBarPropertyChangeHandler + extends BasicScrollBarUI.PropertyChangeHandler + { + /** + * Creates a new handler. + * + * @see #createPropertyChangeListener() + */ + public MetalScrollBarPropertyChangeHandler() + { + // Nothing to do here. + } + + /** + * Handles a property change event. If the event name is + * <code>JSlider.isFreeStanding</code>, this method updates the + * delegate, otherwise the event is passed up to the super class. + * + * @param e the property change event. + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals(FREE_STANDING_PROP)) + { + Boolean prop = (Boolean) e.getNewValue(); + isFreeStanding = prop == null ? true : prop.booleanValue(); + if (increaseButton != null) + increaseButton.setFreeStanding(isFreeStanding); + if (decreaseButton != null) + decreaseButton.setFreeStanding(isFreeStanding); + } + else + super.propertyChange(e); + } + } + + /** The name for the 'free standing' property. */ + public static final String FREE_STANDING_PROP = "JScrollBar.isFreeStanding"; + + /** The minimum thumb size for a scroll bar that is not free standing. */ + private static final Dimension MIN_THUMB_SIZE = new Dimension(15, 15); + + /** The minimum thumb size for a scroll bar that is free standing. */ + private static final Dimension MIN_THUMB_SIZE_FREE_STANDING + = new Dimension(17, 17); + + /** The button that increases the value in the scroll bar. */ + protected MetalScrollButton increaseButton; + + /** The button that decreases the value in the scroll bar. */ + protected MetalScrollButton decreaseButton; + + /** + * The scroll bar width. + */ + protected int scrollBarWidth; + + /** + * A flag that indicates whether the scroll bar is "free standing", which + * means it has complete borders and can be used anywhere in the UI. A + * scroll bar which is not free standing has borders missing from one + * side, and relies on being part of another container with its own borders + * to look right visually. */ + protected boolean isFreeStanding = true; + + /** + * The color for the scroll bar shadow (this is read from the UIDefaults in + * the installDefaults() method). + */ + Color scrollBarShadowColor; + + /** + * Constructs a new instance of <code>MetalScrollBarUI</code>, with no + * specific initialisation. + */ + public MetalScrollBarUI() + { + super(); + } + + /** + * Returns a new instance of <code>MetalScrollBarUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return An instance of MetalScrollBarUI + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalScrollBarUI(); + } + + /** + * Installs the defaults. + */ + protected void installDefaults() + { + // need to initialise isFreeStanding before calling the super class, + // so that the value is set when createIncreaseButton() and + // createDecreaseButton() are called (unless there is somewhere earlier + // that we can do this). + Boolean prop = (Boolean) scrollbar.getClientProperty(FREE_STANDING_PROP); + isFreeStanding = prop == null ? true : prop.booleanValue(); + scrollBarShadowColor = UIManager.getColor("ScrollBar.shadow"); + scrollBarWidth = UIManager.getInt("ScrollBar.width"); + super.installDefaults(); + } + + /** + * Creates a property change listener for the delegate to use. This + * overrides the method to provide a custom listener for the + * {@link MetalLookAndFeel} that can handle the + * <code>JScrollBar.isFreeStanding</code> property. + * + * @return A property change listener. + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new MetalScrollBarPropertyChangeHandler(); + } + + /** + * Creates a new button to use as the control at the lower end of the + * {@link JScrollBar}. This method assigns the new button (an instance of + * {@link MetalScrollButton} to the {@link #decreaseButton} field, and also + * returns the button. The button width is determined by the + * <code>ScrollBar.width</code> setting in the UI defaults. + * + * @param orientation the orientation of the button ({@link #NORTH}, + * {@link #SOUTH}, {@link #EAST} or {@link #WEST}). + * + * @return The button. + */ + protected JButton createDecreaseButton(int orientation) + { + decreaseButton = new MetalScrollButton(orientation, scrollBarWidth, + isFreeStanding); + return decreaseButton; + } + + /** + * Creates a new button to use as the control at the upper end of the + * {@link JScrollBar}. This method assigns the new button (an instance of + * {@link MetalScrollButton} to the {@link #increaseButton} field, and also + * returns the button. The button width is determined by the + * <code>ScrollBar.width</code> setting in the UI defaults. + * + * @param orientation the orientation of the button ({@link #NORTH}, + * {@link #SOUTH}, {@link #EAST} or {@link #WEST}). + * + * @return The button. + */ + protected JButton createIncreaseButton(int orientation) + { + increaseButton = new MetalScrollButton(orientation, scrollBarWidth, + isFreeStanding); + return increaseButton; + } + + /** + * Paints the track for the scrollbar. + * + * @param g the graphics device. + * @param c the component. + * @param trackBounds the track bounds. + */ + protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) + { + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(trackBounds.x, trackBounds.y, trackBounds.width, + trackBounds.height); + if (scrollbar.getOrientation() == HORIZONTAL) + paintTrackHorizontal(g, c, trackBounds.x, trackBounds.y, + trackBounds.width, trackBounds.height); + else + paintTrackVertical(g, c, trackBounds.x, trackBounds.y, + trackBounds.width, trackBounds.height); + + } + + /** + * Paints the track for a horizontal scrollbar. + * + * @param g the graphics device. + * @param c the component. + * @param x the x-coordinate for the track bounds. + * @param y the y-coordinate for the track bounds. + * @param w the width for the track bounds. + * @param h the height for the track bounds. + */ + private void paintTrackHorizontal(Graphics g, JComponent c, + int x, int y, int w, int h) + { + if (c.isEnabled()) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(x, y, x, y + h - 1); + g.drawLine(x, y, x + w - 1, y); + g.drawLine(x + w - 1, y, x + w - 1, y + h - 1); + + g.setColor(scrollBarShadowColor); + g.drawLine(x + 1, y + 1, x + 1, y + h - 1); + g.drawLine(x + 1, y + 1, x + w - 2, y + 1); + + if (isFreeStanding) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(x, y + h - 2, x + w - 1, y + h - 2); + g.setColor(scrollBarShadowColor); + g.drawLine(x, y + h - 1, x + w - 1, y + h - 1); + } + } + else + { + g.setColor(MetalLookAndFeel.getControlDisabled()); + if (isFreeStanding) + g.drawRect(x, y, w - 1, h - 1); + else + { + g.drawLine(x, y, x + w - 1, y); + g.drawLine(x, y, x, y + h - 1); + g.drawLine(x + w - 1, y, x + w - 1, y + h - 1); + } + } + } + + /** + * Paints the track for a vertical scrollbar. + * + * @param g the graphics device. + * @param c the component. + * @param x the x-coordinate for the track bounds. + * @param y the y-coordinate for the track bounds. + * @param w the width for the track bounds. + * @param h the height for the track bounds. + */ + private void paintTrackVertical(Graphics g, JComponent c, + int x, int y, int w, int h) + { + if (c.isEnabled()) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(x, y, x, y + h - 1); + g.drawLine(x, y, x + w - 1, y); + g.drawLine(x, y + h - 1, x + w - 1, y + h - 1); + + g.setColor(scrollBarShadowColor); + g.drawLine(x + 1, y + 1, x + w - 1, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + h - 2); + + if (isFreeStanding) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(x + w - 2, y, x + w - 2, y + h - 1); + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(x + w - 1, y, x + w - 1, y + h - 1); + } + } + else + { + g.setColor(MetalLookAndFeel.getControlDisabled()); + if (isFreeStanding) + g.drawRect(x, y, w - 1, h - 1); + else + { + g.drawLine(x, y, x + w - 1, y); + g.drawLine(x, y, x, y + h - 1); + g.drawLine(x, y + h - 1, x + w - 1, y + h - 1); + } + } + } + + /** + * Paints the slider button of the ScrollBar. + * + * @param g the Graphics context to use + * @param c the JComponent on which we paint + * @param thumbBounds the rectangle that is the slider button + */ + protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) + { + // a disabled scrollbar has no thumb in the metal look and feel + if (!c.isEnabled()) + return; + if (scrollbar.getOrientation() == HORIZONTAL) + paintThumbHorizontal(g, c, thumbBounds); + else + paintThumbVertical(g, c, thumbBounds); + + // Draw the pattern when the theme is not Ocean. + if (! (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)) + { + MetalUtils.fillMetalPattern(c, g, thumbBounds.x + 3, thumbBounds.y + 3, + thumbBounds.width - 6, + thumbBounds.height - 6, + thumbHighlightColor, + thumbLightShadowColor); + } + } + + /** + * Paints the thumb for a horizontal scroll bar. + * + * @param g the graphics device. + * @param c the scroll bar component. + * @param thumbBounds the thumb bounds. + */ + private void paintThumbHorizontal(Graphics g, JComponent c, + Rectangle thumbBounds) + { + int x = thumbBounds.x; + int y = thumbBounds.y; + int w = thumbBounds.width; + int h = thumbBounds.height; + + // First we fill the background. + MetalTheme theme = MetalLookAndFeel.getCurrentTheme(); + if (theme instanceof OceanTheme + && UIManager.get("ScrollBar.gradient") != null) + { + MetalUtils.paintGradient(g, x + 2, y + 2, w - 4, h - 2, + SwingConstants.VERTICAL, + "ScrollBar.gradient"); + } + else + { + g.setColor(thumbColor); + if (isFreeStanding) + g.fillRect(x, y, w, h - 1); + else + g.fillRect(x, y, w, h); + } + + // then draw the dark box + g.setColor(thumbLightShadowColor); + if (isFreeStanding) + g.drawRect(x, y, w - 1, h - 2); + else + { + g.drawLine(x, y, x + w - 1, y); + g.drawLine(x, y, x, y + h - 1); + g.drawLine(x + w - 1, y, x + w - 1, y + h - 1); + } + + // then the highlight + g.setColor(thumbHighlightColor); + if (isFreeStanding) + { + g.drawLine(x + 1, y + 1, x + w - 3, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + h - 3); + } + else + { + g.drawLine(x + 1, y + 1, x + w - 3, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + h - 1); + } + + // draw the shadow line + g.setColor(UIManager.getColor("ScrollBar.shadow")); + g.drawLine(x + w, y + 1, x + w, y + h - 1); + + // For the OceanTheme, draw the 3 lines in the middle. + if (theme instanceof OceanTheme) + { + g.setColor(thumbLightShadowColor); + int middle = x + w / 2; + g.drawLine(middle - 2, y + 4, middle - 2, y + h - 5); + g.drawLine(middle, y + 4, middle, y + h - 5); + g.drawLine(middle + 2, y + 4, middle + 2, y + h - 5); + g.setColor(UIManager.getColor("ScrollBar.highlight")); + g.drawLine(middle - 1, y + 5, middle - 1, y + h - 4); + g.drawLine(middle + 1, y + 5, middle + 1, y + h - 4); + g.drawLine(middle + 3, y + 5, middle + 3, y + h - 4); + } + } + + /** + * Paints the thumb for a vertical scroll bar. + * + * @param g the graphics device. + * @param c the scroll bar component. + * @param thumbBounds the thumb bounds. + */ + private void paintThumbVertical(Graphics g, JComponent c, + Rectangle thumbBounds) + { + int x = thumbBounds.x; + int y = thumbBounds.y; + int w = thumbBounds.width; + int h = thumbBounds.height; + + // First we fill the background. + MetalTheme theme = MetalLookAndFeel.getCurrentTheme(); + if (theme instanceof OceanTheme + && UIManager.get("ScrollBar.gradient") != null) + { + MetalUtils.paintGradient(g, x + 2, y + 2, w - 2, h - 4, + SwingConstants.HORIZONTAL, + "ScrollBar.gradient"); + } + else + { + g.setColor(thumbColor); + if (isFreeStanding) + g.fillRect(x, y, w - 1, h); + else + g.fillRect(x, y, w, h); + } + + // then draw the dark box + g.setColor(thumbLightShadowColor); + if (isFreeStanding) + g.drawRect(x, y, w - 2, h - 1); + else + { + g.drawLine(x, y, x + w - 1, y); + g.drawLine(x, y, x, y + h - 1); + g.drawLine(x, y + h - 1, x + w - 1, y + h - 1); + } + + // then the highlight + g.setColor(thumbHighlightColor); + if (isFreeStanding) + { + g.drawLine(x + 1, y + 1, x + w - 3, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + h - 3); + } + else + { + g.drawLine(x + 1, y + 1, x + w - 1, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + h - 3); + } + + // draw the shadow line + g.setColor(UIManager.getColor("ScrollBar.shadow")); + g.drawLine(x + 1, y + h, x + w - 2, y + h); + + // For the OceanTheme, draw the 3 lines in the middle. + if (theme instanceof OceanTheme) + { + g.setColor(thumbLightShadowColor); + int middle = y + h / 2; + g.drawLine(x + 4, middle - 2, x + w - 5, middle - 2); + g.drawLine(x + 4, middle, x + w - 5, middle); + g.drawLine(x + 4, middle + 2, x + w - 5, middle + 2); + g.setColor(UIManager.getColor("ScrollBar.highlight")); + g.drawLine(x + 5, middle - 1, x + w - 4, middle - 1); + g.drawLine(x + 5, middle + 1, x + w - 4, middle + 1); + g.drawLine(x + 5, middle + 3, x + w - 4, middle + 3); + } + } + + /** + * Returns the minimum thumb size. For a free standing scroll bar the + * minimum size is <code>17 x 17</code> pixels, whereas for a non free + * standing scroll bar the minimum size is <code>15 x 15</code> pixels. + * + * @return The minimum thumb size. + */ + protected Dimension getMinimumThumbSize() + { + Dimension retVal; + if (scrollbar != null) + { + if (isFreeStanding) + retVal = MIN_THUMB_SIZE_FREE_STANDING; + else + retVal = MIN_THUMB_SIZE; + } + else + retVal = new Dimension(0, 0); + return retVal; + } + + /** + * Returns the <code>preferredSize</code> for the specified scroll bar. + * For a vertical scrollbar the height is the sum of the preferred heights + * of the buttons plus <code>30</code>. The width is fetched from the + * <code>UIManager</code> property <code>ScrollBar.width</code>. + * + * For horizontal scrollbars the width is the sum of the preferred widths + * of the buttons plus <code>30</code>. The height is fetched from the + * <code>UIManager</code> property <code>ScrollBar.height</code>. + * + * @param c the scrollbar for which to calculate the preferred size + * + * @return the <code>preferredSize</code> for the specified scroll bar + */ + public Dimension getPreferredSize(JComponent c) + { + int height; + int width; + height = width = 0; + + if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) + { + width += incrButton.getPreferredSize().getWidth(); + width += decrButton.getPreferredSize().getWidth(); + width += 30; + height = UIManager.getInt("ScrollBar.width"); + } + else + { + height += incrButton.getPreferredSize().getHeight(); + height += decrButton.getPreferredSize().getHeight(); + height += 30; + width = UIManager.getInt("ScrollBar.width"); + } + + Insets insets = scrollbar.getInsets(); + + height += insets.top + insets.bottom; + width += insets.left + insets.right; + + return new Dimension(width, height); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalScrollButton.java b/libjava/classpath/javax/swing/plaf/metal/MetalScrollButton.java new file mode 100644 index 000000000..3273908b3 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalScrollButton.java @@ -0,0 +1,483 @@ +/* MetalScrollButton.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.SwingUtilities; +import javax.swing.plaf.basic.BasicArrowButton; + +/** + * A button used by the {@link MetalScrollBarUI}. The button appearance + * varies according to the button direction, whether or not it is part of a + * "free standing" scroll bar, and the current state of the button. + */ +public class MetalScrollButton extends BasicArrowButton +{ + + /** + * The maximum size for buttons. + * @see #getMaximumSize() + */ + private static Dimension maximumSize; + + /** The width of the button. */ + private int buttonWidth; + + /** + * A flag that indicates whether the button is part of a free standing + * scroll bar. This affects how the border is drawn. + */ + private boolean freeStanding; + + /** + * Creates a new button. + * + * @param direction the direction (this should be one of {@link #NORTH}, + * {@link #SOUTH}, {@link #EAST} and {@link #WEST}, but + * this is not enforced). + * @param width the button width. + * @param freeStanding a flag indicating whether the scroll button is free + * standing or not. + */ + public MetalScrollButton(int direction, int width, boolean freeStanding) + { + super(direction); + buttonWidth = width; + this.freeStanding = freeStanding; + setFocusable(false); + } + + /** + * Returns the button width. + * + * @return The button width. + */ + public int getButtonWidth() + { + return buttonWidth; + } + + /** + * Sets the free standing flag. This controls how the button border is + * drawn. + * + * @param freeStanding the new value of the flag. + */ + public void setFreeStanding(boolean freeStanding) + { + this.freeStanding = freeStanding; + } + + /** + * Paints the button. + * + * @param g the graphics device. + */ + public void paint(Graphics g) + { + Rectangle bounds = SwingUtilities.getLocalBounds(this); + + // fill the background + if (getModel().isPressed()) + g.setColor(MetalLookAndFeel.getControlShadow()); + else + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(0, 0, bounds.width, bounds.height); + + paintArrow(g, bounds.width, bounds.height); + + // paint a border manually - I tried using a real (custom) Border + // but couldn't get it to stay set for the button, something was + // overwriting it... + if (freeStanding) + { + if (direction == WEST) + paintWestBorderFreeStanding(g, bounds.width, bounds.height); + else if (direction == EAST) + paintEastBorderFreeStanding(g, bounds.width, bounds.height); + else if (direction == SOUTH) + paintSouthBorderFreeStanding(g, bounds.width, bounds.height); + else // asume NORTH + paintNorthBorderFreeStanding(g, bounds.width, bounds.height); + } + else + { + if (direction == WEST) + paintWestBorder(g, bounds.width, bounds.height); + else if (direction == EAST) + paintEastBorder(g, bounds.width, bounds.height); + else if (direction == SOUTH) + paintSouthBorder(g, bounds.width, bounds.height); + else // asume NORTH + paintNorthBorder(g, bounds.width, bounds.height); + } + } + + private void paintArrow(Graphics g, int w, int h) + { + if (isEnabled()) + g.setColor(MetalLookAndFeel.getBlack()); + else + g.setColor(MetalLookAndFeel.getControlDisabled()); + + if (direction == SOUTH) + { + int x = w / 2; + int y = h / 2 + 2; + for (int i = 1; i < 5; i++) + g.drawLine(x - i, y - i, x + i - 1, y - i); + } + else if (direction == EAST) + { + int x = w / 2 + 2; + int y = h / 2; + for (int i = 1; i < 5; i++) + g.drawLine(x - i, y - i, x - i, y + i - 1); + } + else if (direction == WEST) + { + int x = w / 2 - 3; + int y = h / 2; + for (int i = 1; i < 5; i++) + g.drawLine(x + i, y - i, x + i, y + i - 1); + } + else // assume NORTH + { + int x = w / 2; + int y = h / 2 - 3; + for (int i = 1; i < 5; i++) + g.drawLine(x - i, y + i, x + i - 1, y + i); + } + } + /** + * Paints the border for a button with a {@link #NORTH} direction that + * belongs to a free standing scroll bar. + * + * @param g the graphics device. + * @param w the button width. + * @param h the button height. + */ + private void paintNorthBorderFreeStanding(Graphics g, int w, int h) + { + if (isEnabled()) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(0, 0, w - 2, 0); + g.drawLine(0, 0, 0, h - 1); + g.drawLine(2, h - 1, w - 2, h - 1); + g.drawLine(w - 2, 2, w - 2, h - 1); + + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(1, 1, 1, h - 2); + g.drawLine(1, 1, w - 3, 1); + g.drawLine(w - 1, 1, w - 1, h - 1); + + g.setColor(MetalLookAndFeel.getControl()); + g.drawLine(1, h - 1, 1, h - 1); + g.drawLine(w - 2, 1, w - 2, 1); + } + else + { + g.setColor(MetalLookAndFeel.getControlDisabled()); + g.drawLine(0, 0, w - 1, 0); + g.drawLine(w - 1, 0, w - 1, h - 1); + g.drawLine(0, 0, 0, h - 1); + } + } + + /** + * Paints the border for a button with a {@link #SOUTH} direction that + * belongs to a free standing scroll bar. + * + * @param g the graphics device. + * @param w the button width. + * @param h the button height. + */ + private void paintSouthBorderFreeStanding(Graphics g, int w, int h) + { + if (isEnabled()) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(0, 0, w - 2, 0); + g.drawLine(0, 0, 0, h - 1); + g.drawLine(2, h - 1, w - 2, h - 1); + g.drawLine(w - 2, 2, w - 2, h - 1); + + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(1, 1, 1, h - 1); + g.drawLine(1, 1, w - 1, 1); + g.drawLine(w - 1, 1, w - 1, h - 1); + + g.setColor(MetalLookAndFeel.getControl()); + g.drawLine(1, h - 1, 1, h - 1); + g.drawLine(w - 1, 1, w - 1, 1); + } + else + { + g.setColor(MetalLookAndFeel.getControlDisabled()); + g.drawLine(0, h - 1, w - 1, h - 1); + g.drawLine(w - 1, 0, w - 1, h - 1); + g.drawLine(0, 0, 0, h - 1); + } + } + + /** + * Paints the border for a button with an {@link #EAST} direction that + * belongs to a free standing scroll bar. + * + * @param g the graphics device. + * @param w the button width. + * @param h the button height. + */ + private void paintEastBorderFreeStanding(Graphics g, int w, int h) + { + if (isEnabled()) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(0, 0, w - 2, 0); + g.drawLine(w - 2, 0, w - 2, h - 2); + g.drawLine(0, h - 2, w - 2, h - 2); + + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(0, 1, w - 1, 1); + g.drawLine(w - 1, 1, w - 1, h - 1); + g.drawLine(0, h - 1, w - 1, h - 1); + + g.setColor(MetalLookAndFeel.getControl()); + g.drawLine(w - 2, 1, w - 2, 1); + } + else + { + g.setColor(MetalLookAndFeel.getControlDisabled()); + g.drawLine(0, 0, w - 1, 0); + g.drawLine(w - 1, 0, w - 1, h - 1); + g.drawLine(0, h - 1, w - 1, h - 1); + } + } + + /** + * Paints the border for a button with a {@link #WEST} direction that + * belongs to a free standing scroll bar. + * + * @param g the graphics device. + * @param w the button width. + * @param h the button height. + */ + private void paintWestBorderFreeStanding(Graphics g, int w, int h) + { + if (isEnabled()) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(0, 0, w - 1, 0); + g.drawLine(0, 0, 0, h - 2); + g.drawLine(0, h - 2, w - 1, h - 2); + + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(1, 1, w - 1, 1); + g.drawLine(1, 1, 1, h - 1); + g.drawLine(1, h - 1, w - 1, h - 1); + + g.setColor(MetalLookAndFeel.getControl()); + g.drawLine(1, h - 2, 1, h - 2); + } + else + { + g.setColor(MetalLookAndFeel.getControlDisabled()); + g.drawLine(0, 0, w - 1, 0); + g.drawLine(0, 0, 0, h - 1); + g.drawLine(0, h - 1, w - 1, h - 1); + } + } + + /** + * Paints the border for a button with a {@link #NORTH} direction that + * belongs to a scroll bar that is not free standing. + * + * @param g the graphics device. + * @param w the button width. + * @param h the button height. + */ + private void paintNorthBorder(Graphics g, int w, int h) + { + if (isEnabled()) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(0, 0, 0, h - 1); + + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(1, 0, 1, h - 1); + g.drawLine(1, 0, w - 1, 0); + } + else + { + g.setColor(MetalLookAndFeel.getControlDisabled()); + g.drawLine(0, 0, 0, h - 1); + } + } + + /** + * Paints the border for a button with a {@link #SOUTH} direction that + * belongs to a scroll bar that is not free standing. + * + * @param g the graphics device. + * @param w the button width. + * @param h the button height. + */ + private void paintSouthBorder(Graphics g, int w, int h) + { + if (isEnabled()) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(0, 0, 0, h - 1); + g.drawLine(0, h - 1, w - 1, h - 1); + + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(1, 0, 1, h - 1); + g.drawLine(1, 0, w - 1, 0); + + g.setColor(MetalLookAndFeel.getControl()); + g.drawLine(1, h - 1, 1, h - 1); + } + else + { + g.setColor(MetalLookAndFeel.getControlDisabled()); + g.drawLine(0, 0, 0, h - 1); + } + } + + /** + * Paints the border for a button with an {@link #EAST} direction that + * belongs to a scroll bar that is not free standing. + * + * @param g the graphics device. + * @param w the button width. + * @param h the button height. + */ + private void paintEastBorder(Graphics g, int w, int h) + { + if (isEnabled()) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(0, 0, w - 1, 0); + g.drawLine(w - 1, 2, w - 1, h - 1); + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(0, 1, w - 2, 1); + g.drawLine(0, 1, 0, h - 1); + } + else + { + g.setColor(MetalLookAndFeel.getControlDisabled()); + g.drawLine(0, 0, w - 1, 0); + } + } + + /** + * Paints the border for a button with a {@link #WEST} direction that + * belongs to a scroll bar that is not free standing. + * + * @param g the graphics device. + * @param w the button width. + * @param h the button height. + */ + private void paintWestBorder(Graphics g, int w, int h) + { + Rectangle bounds = SwingUtilities.getLocalBounds(this); + if (isEnabled()) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(0, 0, bounds.width - 1, 0); + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(0, 1, bounds.width - 1, 1); + g.drawLine(0, 1, 0, bounds.height - 1); + } + else + { + g.setColor(MetalLookAndFeel.getControlDisabled()); + g.drawLine(0, 0, bounds.width - 1, 0); + } + } + + /** + * Returns the preferred size for the button, which varies depending on + * the direction of the button and whether or not it is free standing. + * + * @return The preferred size. + */ + public Dimension getPreferredSize() + { + int adj = 1; + if (!freeStanding) + adj = 2; + + if (direction == EAST) + return new Dimension(buttonWidth - adj, buttonWidth); + else if (direction == WEST) + return new Dimension(buttonWidth - 2, buttonWidth); + else if (direction == SOUTH) + return new Dimension(buttonWidth, buttonWidth - adj); + else // assume NORTH + return new Dimension(buttonWidth, buttonWidth - 2); + } + + /** + * Returns the minimum size for the button. + * + * @return The minimum size for the button. + */ + public Dimension getMinimumSize() + { + return getPreferredSize(); + } + + /** + * Returns the maximum size for the button. + * + * @return <code>Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE)</code>. + */ + public Dimension getMaximumSize() + { + if (maximumSize == null) + maximumSize = new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); + return maximumSize; + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalScrollPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalScrollPaneUI.java new file mode 100644 index 000000000..09a47c300 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalScrollPaneUI.java @@ -0,0 +1,159 @@ +/* MetalScrollPaneUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.beans.PropertyChangeListener; + +import javax.swing.JComponent; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicScrollPaneUI; + +/** + * A UI delegate for the {@link JScrollPane} component. + */ +public class MetalScrollPaneUI + extends BasicScrollPaneUI +{ + /** + * Constructs a new instance of <code>MetalScrollPaneUI</code>. + */ + public MetalScrollPaneUI() + { + super(); + } + + /** + * Returns a shared instance of <code>MetalScrollPaneUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A shared instance of <code>MetalScrollPaneUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalScrollPaneUI(); + } + + /** + * Configures the specified component appropriate for the look and feel. + * This method is invoked when the ComponentUI instance is being installed + * as the UI delegate on the specified component. This method should + * completely configure the component for the look and feel, + * including the following: + * 1. Install any default property values for color, fonts, borders, + * icons, opacity, etc. on the component. Whenever possible, property + * values initialized by the client program should not be overridden. + * 2. Install a LayoutManager on the component if necessary. + * 3. Create/add any required sub-components to the component. + * 4. Create/install event listeners on the component. + * 5. Create/install a PropertyChangeListener on the component in order + * to detect and respond to component property changes appropriately. + * 6. Install keyboard UI (mnemonics, traversal, etc.) on the component. + * 7. Initialize any appropriate instance data. + * + * @param c - the component to install the ui on + */ + public void installUI(JComponent c) + { + super.installUI(c); + JScrollBar hsb = scrollpane.getHorizontalScrollBar(); + hsb.putClientProperty(MetalScrollBarUI.FREE_STANDING_PROP, Boolean.FALSE); + JScrollBar vsb = scrollpane.getVerticalScrollBar(); + vsb.putClientProperty(MetalScrollBarUI.FREE_STANDING_PROP, Boolean.FALSE); + } + + /** + * Reverses configuration which was done on the specified component + * during installUI. This method is invoked when this UIComponent + * instance is being removed as the UI delegate for the specified + * component. This method should undo the configuration performed in + * installUI, being careful to leave the JComponent instance in a + * clean state (no extraneous listeners, look-and-feel-specific property + * objects, etc.). This should include the following: + * 1. Remove any UI-set borders from the component. + * 2. Remove any UI-set layout managers on the component. + * 3. Remove any UI-added sub-components from the component. + * 4. Remove any UI-added event/property listeners from the component. + * 5. Remove any UI-installed keyboard UI from the component. + * 6. Nullify any allocated instance data objects to allow for GC. + * + * @param c - the component to uninstall the ui on + */ + public void uninstallUI(JComponent c) + { + JScrollBar hsb = scrollpane.getHorizontalScrollBar(); + hsb.putClientProperty(MetalScrollBarUI.FREE_STANDING_PROP, null); + JScrollBar vsb = scrollpane.getVerticalScrollBar(); + vsb.putClientProperty(MetalScrollBarUI.FREE_STANDING_PROP, null); + super.uninstallUI(c); + } + + /** + * Installs listeners on scrollPane + * + * @param scrollPane - the component to install the listeners on + */ + public void installListeners(JScrollPane scrollPane) + { + super.installListeners(scrollPane); + } + + /** + * Uninstalls listeners on scrollPane + * + * @param scrollPane - the component to uninstall the listeners on + */ + public void uninstallListeners(JScrollPane scrollPane) + { + super.uninstallListeners(scrollPane); + } + + /** + * TODO + * + * @return TODO + */ + protected PropertyChangeListener createScrollBarSwapListener() + { + // FIXME: Anything else to do here? + return super.createPropertyChangeListener(); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalSeparatorUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalSeparatorUI.java new file mode 100644 index 000000000..8afa98c97 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalSeparatorUI.java @@ -0,0 +1,131 @@ +/* MetalSeparatorUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.JComponent; +import javax.swing.JSeparator; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicSeparatorUI; + +/** + * A UI delegate for the {@link JSeparator} component. + */ +public class MetalSeparatorUI + extends BasicSeparatorUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for MetalSeparatorUIs */ + private static MetalSeparatorUI instance; + + /** + * Constructs a new instance of <code>MetalSeparatorUI</code>. + */ + public MetalSeparatorUI() + { + super(); + } + + /** + * Returns a shared instance of <code>MetalSeparatorUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A shared instance of <code>MetalSeparatorUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalSeparatorUI(); + return instance; + } + + /** + * The separator is made of two lines. The top line will be + * the Metal theme color separatorForeground (or left line if it's vertical). + * The bottom or right line will be the Metal theme color + * separatorBackground. + * The two lines will + * be centered inside the bounds box. If the separator is horizontal, + * then it will be vertically centered, or if it's vertical, it will + * be horizontally centered. + * + * @param g The Graphics object to paint with + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + Rectangle r = new Rectangle(); + SwingUtilities.calculateInnerArea(c, r); + Color saved = g.getColor(); + Color c1 = UIManager.getColor("Separator.foreground"); + Color c2 = UIManager.getColor("Separator.background"); + JSeparator s; + if (c instanceof JSeparator) + s = (JSeparator) c; + else + return; + + if (s.getOrientation() == JSeparator.HORIZONTAL) + { + int midAB = r.height / 2; + g.setColor(c1); + g.drawLine(r.x, r.y + midAB - 1, r.x + r.width, r.y + midAB - 1); + + g.setColor(c2); + g.fillRect(r.x, r.y + midAB, r.x + r.width, r.y + midAB); + } + else + { + int midAD = r.height / 2 + r.y; + g.setColor(c1); + g.drawLine(r.x, r.y, r.x, r.y + r.height); + + g.setColor(c2); + g.fillRect(r.x + midAD, r.y + r.height, r.x + midAD, r.y + r.height); + } + g.setColor(saved); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java new file mode 100644 index 000000000..e85c32462 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java @@ -0,0 +1,475 @@ +/* MetalSliderUI.java + Copyright (C) 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JSlider; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicGraphicsUtils; +import javax.swing.plaf.basic.BasicSliderUI; + +/** + * A UI delegate for the {@link JSlider} component. + */ +public class MetalSliderUI extends BasicSliderUI +{ + /** + * A property change handler that updates the rendered component in response + * to specific property change events. This custom handler is used to + * intercept the "JSlider.isFilled" property, which is only recognised by + * the {@link MetalLookAndFeel}. + */ + protected class MetalPropertyListener + extends BasicSliderUI.PropertyChangeHandler + { + /** + * Creates a new listener. + */ + protected MetalPropertyListener() + { + // Nothing to do here. + } + + /** + * Handles property change events. Events with the name "JSlider.isFilled" + * are handled here, and other events are passed to the superclass. + * + * @param e the property change event. + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals(SLIDER_FILL)) + { + Boolean b = (Boolean) e.getNewValue(); + if (b == null) + filledSlider = false; + else + filledSlider = b.booleanValue(); + } + else + super.propertyChange(e); + } + } + + /** The thumb color (unused, because an icon is used to draw the thumb). */ + protected static Color thumbColor; + + /** + * The highlight color used for drawing the track rect when the slider is + * enabled. + */ + protected static Color highlightColor; + + /** + * The shadow color used for drawing the track rect when the slider is + * enabled. + */ + protected static Color darkShadowColor; + + /** The track width. */ + protected static int trackWidth = UIManager.getInt("Slider.trackWidth"); + + /** The length of the major tick marks. */ + protected static int tickLength = UIManager.getInt("Slider.majorTickLength"); + + /** The icon used for the thumb control of horizontally oriented sliders. */ + protected static Icon horizThumbIcon = UIManager.getIcon( + "Slider.horizontalThumbIcon"); + + /** The icon used for the thumb control of vertically oriented sliders. */ + protected static Icon vertThumbIcon = UIManager.getIcon( + "Slider.verticalThumbIcon"); + + /** The gap between the track and the tick marks. */ + protected final int TICK_BUFFER = 4; + + /** A key to look up the filledSlider setting in the {@link UIManager}. */ + protected final String SLIDER_FILL = "JSlider.isFilled"; + + /** + * A flag that controls whether or not the track is filled up to the value + * of the slider. + */ + protected boolean filledSlider; + + /** + * Constructs a new instance. + */ + public MetalSliderUI() + { + super(null); + filledSlider = UIManager.getBoolean(SLIDER_FILL); + darkShadowColor = MetalLookAndFeel.getControlDarkShadow(); + highlightColor = MetalLookAndFeel.getControlHighlight(); + } + + /** + * Returns a new instance of <code>MetalSliderUI</code>. + * + * @param component the component (ignored). + * + * @return A new instance of <code>MetalSliderUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalSliderUI(); + } + + /** + * Installs the default for this UI delegate in the supplied component. + * + * @param c the component. + */ + public void installUI(JComponent c) + { + super.installUI(c); + Boolean b = (Boolean) c.getClientProperty(SLIDER_FILL); + if (b != null) + filledSlider = b.booleanValue(); + } + + /** + * Creates a property change listener for the slider. + * + * @param slider the slider. + * + * @return A new instance of {@link MetalPropertyListener}. + */ + protected PropertyChangeListener createPropertyChangeListener(JSlider slider) + { + return new MetalPropertyListener(); + } + + /** + * Paints the thumb icon for the slider. + * + * @param g the graphics device. + */ + public void paintThumb(Graphics g) + { + Color save = g.getColor(); + g.setColor(thumbColor); + if (slider.getOrientation() == JSlider.HORIZONTAL) + horizThumbIcon.paintIcon(slider, g, thumbRect.x, thumbRect.y); + else + vertThumbIcon.paintIcon(slider, g, thumbRect.x, thumbRect.y); + g.setColor(save); + } + + /** + * Paints the track along which the thumb control moves. + * + * @param g the graphics device. + */ + public void paintTrack(Graphics g) + { + Color shadowColor = MetalLookAndFeel.getControlShadow(); + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + int trackX = trackRect.x; + int trackY = trackRect.y + (trackRect.height - getTrackWidth()) / 2; + int trackW = trackRect.width; + int trackH = getTrackWidth(); + + // draw border + if (slider.isEnabled()) + BasicGraphicsUtils.drawEtchedRect(g, trackX, trackY, trackW, trackH, + darkShadowColor, shadowColor, darkShadowColor, highlightColor); + else + { + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawRect(trackX, trackY, trackW - 2, trackH - 2); + } + + // fill track (if required) + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme) + { + if (slider.isEnabled()) + { + int xPos = xPositionForValue(slider.getValue()); + int x = slider.getInverted() ? xPos : trackRect.x; + int w = slider.getInverted() ? trackX + trackW - xPos + : xPos - trackRect.x; + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x + 1, trackY + 1, x + w - 3, trackY + 1); + g.setColor(UIManager.getColor("Slider.altTrackColor")); + g.drawLine(x + 1, trackY + 2, x + w - 3, trackY + 2); + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x + 1, trackY + 3, x + w - 3, trackY + 3); + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + g.drawLine(x + 1, trackY + 4, x + w - 3, trackY + 4); + } + } + else if (filledSlider) + { + int xPos = xPositionForValue(slider.getValue()); + int x = slider.getInverted() ? xPos : trackRect.x; + int w = slider.getInverted() ? trackX + trackW - xPos + : xPos - trackRect.x; + g.setColor(MetalLookAndFeel.getControlShadow()); + g.fillRect(x + 1, trackY + 1, w - 3, getTrackWidth() - 3); + if (slider.isEnabled()) + { + g.setColor(MetalLookAndFeel.getControl()); + g.drawLine(x + 1, trackY + 1, x + w - 3, trackY + 1); + g.drawLine(x + 1, trackY + 1, x + 1, + trackY + getTrackWidth() - 3); + } + } + } + else + { + int trackX = trackRect.x + (trackRect.width - getTrackWidth()) / 2; + int trackY = trackRect.y; + int trackW = getTrackWidth(); + int trackH = trackRect.height; + if (slider.isEnabled()) + BasicGraphicsUtils.drawEtchedRect(g, trackX, trackY, trackW, trackH, + darkShadowColor, shadowColor, darkShadowColor, highlightColor); + else + { + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawRect(trackX, trackY, trackW - 2, trackH - 2); + } + + // Fill track if necessary. + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme) + { + if (slider.isEnabled()) + { + int yPos = yPositionForValue(slider.getValue()); + int y = slider.getInverted() ? trackY : yPos; + int h = slider.getInverted() ? yPos - trackY + : trackY + trackH - yPos; + + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(trackX + 1, y + 1, trackX + 1, y + h - 3); + g.setColor(UIManager.getColor("Slider.altTrackColor")); + g.drawLine(trackX + 2, y + 1, trackX + 2, y + h - 3); + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(trackX + 3, y + 1, trackX + 3, y + h - 3); + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + g.drawLine(trackX + 4, y + 1, trackX + 4, y + h - 3); + } + } + else if (filledSlider) + { + int yPos = yPositionForValue(slider.getValue()); + int y = slider.getInverted() ? trackY : yPos; + int h = slider.getInverted() ? yPos - trackY + : trackY + trackH - yPos; + g.setColor(MetalLookAndFeel.getControlShadow()); + g.fillRect(trackX + 1, y + 1, getTrackWidth() - 3, h - 3); + if (slider.isEnabled()) + { + g.setColor(MetalLookAndFeel.getControl()); + g.drawLine(trackX + 1, y + 1, trackX + trackW - 3, y + 1); + g.drawLine(trackX + 1, y + 1, trackX + 1, y + h - 3); + } + } + } + } + + /** + * Draws the focus rectangle for the slider. The Metal look and feel + * indicates that the {@link JSlider} has the focus by changing the color of + * the thumb control - this is handled elsewhere and so this method is empty + * (it overrides the method in the {@link BasicSliderUI} class to prevent + * a default focus highlight from being drawn). + * + * @param g the graphics device. + */ + public void paintFocus(Graphics g) + { + thumbColor = getFocusColor(); + paintThumb(g); + } + + /** + * Returns the size of the thumb icon. + * + * @return The size of the thumb icon. + */ + protected Dimension getThumbSize() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + return new Dimension(horizThumbIcon.getIconWidth(), + horizThumbIcon.getIconHeight()); + else + return new Dimension(vertThumbIcon.getIconWidth(), + vertThumbIcon.getIconHeight()); + } + + /** + * Returns the length of the major tick marks. + * + * @return The length of the major tick marks. + */ + public int getTickLength() + { + int len = tickLength + TICK_BUFFER + 1; + if (slider.getOrientation() == JSlider.VERTICAL) + len += 2; + return len; + } + + /** + * Returns the track width. + * + * @return The track width. + */ + protected int getTrackWidth() + { + return trackWidth; + } + + /** + * Returns the track length. + * + * @return The track length. + */ + protected int getTrackLength() + { + return slider.getOrientation() == JSlider.HORIZONTAL + ? tickRect.width : tickRect.height; + } + + /** + * Returns the thumb overhang. + * + * @return The thumb overhang. + */ + protected int getThumbOverhang() + { + // FIXME: for what might this method be used? + return 0; + } + + protected void scrollDueToClickInTrack(int dir) + { + // FIXME: for what might this method be overridden? + super.scrollDueToClickInTrack(dir); + } + + /** + * Paints the minor ticks for a slider with a horizontal orientation. + * + * @param g the graphics device. + * @param tickBounds the tick bounds. + * @param x the x value for the tick. + */ + protected void paintMinorTickForHorizSlider(Graphics g, Rectangle tickBounds, + int x) + { + // Note the incoming 'g' has a translation in place to get us to the + // start of the tick rect already... + if (slider.isEnabled()) + g.setColor(slider.getForeground()); + else + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x, TICK_BUFFER, x, TICK_BUFFER + tickLength / 2); + } + + /** + * Paints the major ticks for a slider with a horizontal orientation. + * + * @param g the graphics device. + * @param tickBounds the tick bounds. + * @param x the x value for the tick. + */ + protected void paintMajorTickForHorizSlider(Graphics g, Rectangle tickBounds, + int x) + { + // Note the incoming 'g' has a translation in place to get us to the + // start of the tick rect already... + if (slider.isEnabled()) + g.setColor(slider.getForeground()); + else + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x, TICK_BUFFER, x, TICK_BUFFER + tickLength - 1); + } + + /** + * Paints the minor ticks for a slider with a vertical orientation. + * + * @param g the graphics device. + * @param tickBounds the tick bounds. + * @param y the y value for the tick. + */ + protected void paintMinorTickForVertSlider(Graphics g, Rectangle tickBounds, + int y) + { + // Note the incoming 'g' has a translation in place to get us to the + // start of the tick rect already... + if (slider.isEnabled()) + g.setColor(slider.getForeground()); + else + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(TICK_BUFFER, y, TICK_BUFFER + tickLength / 2, y); + } + + /** + * Paints the major ticks for a slider with a vertical orientation. + * + * @param g the graphics device. + * @param tickBounds the tick bounds. + * @param y the y value for the tick. + */ + protected void paintMajorTickForVertSlider(Graphics g, Rectangle tickBounds, + int y) + { + // Note the incoming 'g' has a translation in place to get us to the + // start of the tick rect already... + if (slider.isEnabled()) + g.setColor(slider.getForeground()); + else + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(TICK_BUFFER, y, TICK_BUFFER + tickLength, y); + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java b/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java new file mode 100644 index 000000000..051499834 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java @@ -0,0 +1,264 @@ +/* MetalSplitPaneDivider.java +Copyright (C) 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.JButton; +import javax.swing.JSplitPane; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.plaf.basic.BasicSplitPaneDivider; + +/** + * The divider that is used by the {@link MetalSplitPaneUI}. + * + * @author Roman Kennke (roman@kennke.org) + */ +class MetalSplitPaneDivider extends BasicSplitPaneDivider +{ + /** + * The button pixel data, as indices into the colors array below. + * This is the version for 'left' buttons. + * + * This is slightly different from the icon in Sun's version, it is + * one pixel smaller and is more consistent with BUTTON_SPRITE_R. + */ + static final byte[][] BUTTON_SPRITE_L = {{ 0, 0, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 2, 1, 1, 0, 0, 0 }, + { 0, 2, 1, 1, 1, 1, 0, 0 }, + { 2, 1, 1, 1, 1, 1, 1, 0 }, + { 0, 3, 3, 3, 3, 3, 3, 3 }}; + + /** + * The button pixel data, as indices into the colors array below. + * This is the version for 'right' buttons. + */ + static final byte[][] BUTTON_SPRITE_R = {{ 2, 2, 2, 2, 2, 2, 2, 2 }, + { 0, 1, 1, 1, 1, 1, 1, 3 }, + { 0, 0, 1, 1, 1, 1, 3, 0 }, + { 0, 0, 0, 1, 1, 3, 0, 0 }, + { 0, 0, 0, 0, 3, 0, 0, 0 }}; + + private class MetalOneTouchButton + extends JButton + { + /** + * Denotes a left button. + */ + static final int LEFT = 0; + + /** + * Denotes a right button. + */ + static final int RIGHT = 1; + + /** + * The colors for the button sprite. + */ + private Color[] colors; + + /** + * Either LEFT or RIGHT. + */ + private int direction; + + /** + * Creates a new instance. + * + * @param dir either LEFT or RIGHT + */ + MetalOneTouchButton(int dir) + { + direction = dir; + colors = new Color[4]; + } + + /** + * Never allow borders. + */ + public void setBorder(Border b) + { + } + + /** + * Never allow focus traversal. + */ + public boolean isFocusTraversable() + { + return false; + } + + /** + * Paints the one touch button. + */ + public void paint(Graphics g) + { + if (splitPane != null) + { + // Update colors here to reflect dynamic changes to the theme. + colors[0] = getBackground(); + colors[1] = MetalLookAndFeel.getPrimaryControlDarkShadow(); + colors[2] = MetalLookAndFeel.getPrimaryControlInfo(); + colors[3] = MetalLookAndFeel.getPrimaryControlHighlight(); + + // Fill background. + g.setColor(getBackground()); + g.fillRect(0, 0, getWidth(), getHeight()); + + // Pressed buttons have slightly different color mapping. + if (getModel().isPressed()) + colors[1] = colors[2]; + + byte[][] sprite; + if (direction == LEFT) + sprite = BUTTON_SPRITE_L; + else + sprite = BUTTON_SPRITE_R; + + if (orientation == JSplitPane.VERTICAL_SPLIT) + { + // Draw the sprite as it is. + for (int y = 0; y < sprite.length; y++) + { + byte[] line = sprite[y]; + for (int x = 0; x < line.length; x++) + { + int c = line[x]; + if (c != 0) + { + g.setColor(colors[c]); + g.fillRect(x + 1, y + 1, 1, 1); + } + } + } + } + else + { + // Draw the sprite with swapped X and Y axis. + for (int y = 0; y < sprite.length; y++) + { + byte[] line = sprite[y]; + for (int x = 0; x < line.length; x++) + { + int c = line[x]; + if (c != 0) + { + g.setColor(colors[c]); + g.fillRect(y + 1, x + 1, 1, 1); + } + } + } + } + } + } + } + + /** The dark color in the pattern. */ + Color dark; + + /** The light color in the pattern. */ + Color light; + + /** The JSplitPane the divider is on. */ + JSplitPane splitPane; + + /** The split pane orientation. */ + int orientation; + + /** + * Creates a new instance of <code>MetalSplitPaneDivider</code>. + * + * @param ui the <code>MetalSplitPaneUI</code> that uses this divider + */ + public MetalSplitPaneDivider(MetalSplitPaneUI ui, Color light, Color dark) + { + super(ui); + this.splitPane = super.splitPane; + this.orientation = super.orientation; + this.light = light; + this.dark = dark; + } + + /** + * Paints the divider. + * + * @param g the <code>Graphics</code> context to use for painting + */ + public void paint(Graphics g) + { + Dimension s = getSize(); + + if (splitPane.hasFocus()) + { + g.setColor(UIManager.getColor("SplitPane.dividerFocusColor")); + g.fillRect(0, 0, s.width, s.height); + } + + // Paint border if one exists. + Border border = getBorder(); + if (border != null) + border.paintBorder(this, g, 0, 0, s.width, s.height); + + Insets i = getInsets(); + MetalUtils.fillMetalPattern(splitPane, g, i.left + 2, i.top + 2, + s.width - i.left - i.right - 4, + s.height - i.top - i.bottom - 4, + light, dark); + super.paint(g); + } + + protected JButton createLeftOneTouchButton() + { + JButton b = new MetalOneTouchButton(MetalOneTouchButton.LEFT); + b.setMinimumSize(new Dimension(ONE_TOUCH_SIZE, ONE_TOUCH_SIZE)); + b.setRequestFocusEnabled(false); + return b; + } + + protected JButton createRightOneTouchButton() + { + JButton b = new MetalOneTouchButton(MetalOneTouchButton.RIGHT); + b.setMinimumSize(new Dimension(ONE_TOUCH_SIZE, ONE_TOUCH_SIZE)); + b.setRequestFocusEnabled(false); + return b; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneUI.java new file mode 100644 index 000000000..5b8f2127e --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneUI.java @@ -0,0 +1,89 @@ +/* MetalSplitPaneUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; + +import javax.swing.JComponent; +import javax.swing.JSplitPane; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicSplitPaneDivider; +import javax.swing.plaf.basic.BasicSplitPaneUI; + +/** + * A UI delegate for the {@link JSplitPane} component. + */ +public class MetalSplitPaneUI extends BasicSplitPaneUI +{ + /** + * Constructs a new instance of <code>MetalSplitPaneUI</code>. + */ + public MetalSplitPaneUI() + { + super(); + } + + /** + * Returns a new instance of <code>MetalSplitPaneUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A new instance of <code>MetalSplitPaneUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalSplitPaneUI(); + } + + /** + * Returns the divider that is used by the <code>JSplitPane</code>. + * + * The divider returned by this method is a {@link BasicSplitPaneDivider} + * that is drawn using the Metal look. + * + * @return the default divider to use for <code>JSplitPane</code>s. + */ + public BasicSplitPaneDivider createDefaultDivider() + { + Color light = UIManager.getColor("SplitPane.highlight"); + Color dark = UIManager.getColor("SplitPane.darkShadow"); + return new MetalSplitPaneDivider(this, light, dark); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java new file mode 100644 index 000000000..77705ba0e --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java @@ -0,0 +1,1269 @@ +/* MetalTabbedPaneUI.java + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.LayoutManager; +import java.awt.Rectangle; + +import javax.swing.JComponent; +import javax.swing.JTabbedPane; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicTabbedPaneUI; + +/** + * A UI delegate for the {@link JTabbedPane} component. + */ +public class MetalTabbedPaneUI extends BasicTabbedPaneUI +{ + + /** + * A {@link LayoutManager} responsible for placing all the tabs and the + * visible component inside the {@link JTabbedPane}. This class is only used + * for {@link JTabbedPane#WRAP_TAB_LAYOUT}. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class TabbedPaneLayout + extends BasicTabbedPaneUI.TabbedPaneLayout + { + /** + * Creates a new instance of the layout manager. + */ + public TabbedPaneLayout() + { + // Nothing to do here. + } + + /** + * Overridden to do nothing, because tab runs are not rotated in the + * {@link MetalLookAndFeel}. + * + * @param tabPlacement the tab placement (one of {@link #TOP}, + * {@link #BOTTOM}, {@link #LEFT} or {@link #RIGHT}). + * @param selectedRun the index of the selected run. + */ + protected void rotateTabRuns(int tabPlacement, int selectedRun) + { + // do nothing, because tab runs are not rotated in the MetalLookAndFeel + } + + /** + * Overridden to do nothing, because the selected tab does not have extra + * padding in the {@link MetalLookAndFeel}. + * + * @param tabPlacement the tab placement (one of {@link #TOP}, + * {@link #BOTTOM}, {@link #LEFT} or {@link #RIGHT}). + * @param selectedIndex the index of the selected tab. + */ + protected void padSelectedTab(int tabPlacement, int selectedIndex) + { + // do nothing, because the selected tab does not have extra padding in + // the MetalLookAndFeel + } + + /** + * Overridden because tab runs are only normalized for TOP and BOTTOM + * tab placement in the Metal L&F. + */ + protected void normalizeTabRuns(int tabPlacement, int tabCount, int start, + int max) + { + if (tabPlacement == TOP || tabPlacement == BOTTOM) + super.normalizeTabRuns(tabPlacement, tabCount, start, max); + } + } + + /** + * The minimum tab width. + */ + protected int minTabWidth; + + /** + * The color for the selected tab. + */ + protected Color selectColor; + + /** + * The color for a highlighted selected tab. + */ + protected Color selectHighlight; + + /** + * The background color used for the tab area. + */ + protected Color tabAreaBackground; + + /** The graphics to draw the highlight below the tab. */ + private Graphics hg; + + /** + * Indicates if the tabs are having their background filled. + */ + private boolean tabsOpaque; + + /** + * Constructs a new instance of MetalTabbedPaneUI. + */ + public MetalTabbedPaneUI() + { + super(); + } + + /** + * Returns an instance of MetalTabbedPaneUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalTabbedPaneUI + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalTabbedPaneUI(); + } + + /** + * Creates and returns an instance of {@link TabbedPaneLayout}. + * + * @return A layout manager used by this UI delegate. + */ + protected LayoutManager createLayoutManager() + { + return (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT) + ? new MetalTabbedPaneUI.TabbedPaneLayout() + : super.createLayoutManager(); + } + + /** + * Paints the border for a single tab. + * + * @param g the graphics device. + * @param tabPlacement the tab placement ({@link #TOP}, {@link #LEFT}, + * {@link #BOTTOM} or {@link #RIGHT}). + * @param tabIndex the index of the tab to draw the border for. + * @param x the x-coordinate for the tab's bounding rectangle. + * @param y the y-coordinate for the tab's bounding rectangle. + * @param w the width for the tab's bounding rectangle. + * @param h the height for the tab's bounding rectangle. + * @param isSelected indicates whether or not the tab is selected. + */ + protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, + int x, int y, int w, int h, boolean isSelected) + { + int bottom = y + h - 1; + int right = x + w - 1; + + switch (tabPlacement) + { + case LEFT: + paintLeftTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected); + break; + case BOTTOM: + paintBottomTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected); + break; + case RIGHT: + paintRightTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected); + break; + case TOP: + default: + paintTopTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected); + } + } + + /** + * Paints the border for a tab assuming that the tab position is at the top + * ({@link #TOP}). + * + * @param tabIndex the tab index. + * @param g the graphics device. + * @param x the x-coordinate for the tab's bounding rectangle. + * @param y the y-coordinate for the tab's bounding rectangle. + * @param w the width for the tab's bounding rectangle. + * @param h the height for the tab's bounding rectangle. + * @param btm the y coordinate of the bottom border + * @param rght the x coordinate of the right border + * @param isSelected indicates whether the tab is selected. + */ + protected void paintTopTabBorder(int tabIndex, Graphics g, int x, int y, + int w, int h, int btm, int rght, boolean isSelected) + { + int tabCount = tabPane.getTabCount(); + int currentRun = getRunForTab(tabCount, tabIndex); + int right = w - 1; + int bottom = h - 1; + + // Paint gap. + if (shouldFillGap(currentRun, tabIndex, x, y)) + { + g.translate(x, y); + g.setColor(getColorForGap(currentRun, x, y + 1)); + g.fillRect(1, 0, 5, 3); + g.fillRect(1, 3, 2, 2); + g.translate(-x, -y); + } + + g.translate(x, y); + + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + if (isOcean && isSelected) + g.setColor(oceanSelectedBorder); + else + g.setColor(darkShadow); + + // Slant + g.drawLine(1, 5, 6, 0); + // Top. + g.drawLine(6, 0, right, 0); + // Right. + int lastIndex = lastTabInRun(tabCount, currentRun); + if (tabIndex == lastIndex) + g.drawLine(right, 1, right, bottom); + // Left. + int selectedIndex = tabPane.getSelectedIndex(); + if (isOcean && tabIndex - 1 == selectedIndex + && currentRun == getRunForTab(tabCount, selectedIndex)) + { + g.setColor(oceanSelectedBorder); + } + if (tabIndex != tabRuns[runCount - 1]) + { + if (isOcean && isSelected) + { + g.drawLine(0, 6, 0, bottom); + g.setColor(darkShadow); + g.drawLine(0, 0, 0, 5); + } + else + { + g.drawLine(0, 0, 0, bottom); + } + } + else + { + g.drawLine(0, 6, 0, bottom); + } + + // Paint the highlight. + g.setColor(isSelected ? selectHighlight : highlight); + // Slant. + g.drawLine(1, 6, 6, 1); + // Top. + g.drawLine(6, 1, right, 1); + // Left. + g.drawLine(1, 6, 1, bottom); + int firstIndex = tabRuns[currentRun]; + if (tabIndex == firstIndex && tabIndex != tabRuns[runCount - 1]) + { + if (tabPane.getSelectedIndex() == tabRuns[currentRun + 1]) + g.setColor(selectHighlight); + else + g.setColor(highlight); + g.drawLine(1, 0, 1, 4); + } + + g.translate(-x, -y); + } + + /** + * Paints the border for a tab assuming that the tab position is at the left + * ({@link #LEFT}). + * + * @param tabIndex the tab index. + * @param g the graphics device. + * @param x the x-coordinate for the tab's bounding rectangle. + * @param y the y-coordinate for the tab's bounding rectangle. + * @param w the width for the tab's bounding rectangle. + * @param h the height for the tab's bounding rectangle. + * @param btm ??? + * @param rght ??? + * @param isSelected indicates whether the tab is selected. + */ + protected void paintLeftTabBorder(int tabIndex, Graphics g, int x, int y, + int w, int h, int btm, int rght, boolean isSelected) + { + g.translate(x, y); + int bottom = h - 1; + int right = w - 1; + + int tabCount = tabPane.getTabCount(); + int currentRun = getRunForTab(tabCount, tabIndex); + int firstIndex = tabRuns[currentRun]; + + // Paint the part of the above tab. + if (tabIndex != firstIndex && tabIndex > 0 && tabsOpaque) + { + Color c; + if (tabPane.getSelectedIndex() == tabIndex - 1) + c = selectColor; + else + c = getUnselectedBackground(tabIndex - 1); + g.setColor(c); + g.fillRect(2, 0, 4, 3); + g.drawLine(2, 3, 2, 3); + } + + // Paint the highlight. + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + if (isOcean) + { + g.setColor(isSelected ? selectHighlight : MetalLookAndFeel.getWhite()); + } + else + { + g.setColor(isSelected ? selectHighlight : highlight); + } + // Slant. + g.drawLine(1, 6, 6, 1); + // Left. + g.drawLine(1, 6, 1, bottom); + // Top. + g.drawLine(6, 1, right, 1); + if (tabIndex != firstIndex) + { + if (isOcean) + { + g.setColor(MetalLookAndFeel.getWhite()); + } + g.drawLine(1, 0, 1, 4); + } + + // Paint border. + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + if (isOcean && isSelected) + { + g.setColor(oceanSelectedBorder); + } + else + { + g.setColor(darkShadow); + } + + // Slant. + g.drawLine(1, 5, 6, 0); + // Top. + g.drawLine(6, 0, right, 0); + // Bottom. + int lastIndex = lastTabInRun(tabCount, currentRun); + if (tabIndex == lastIndex) + { + g.drawLine(0, bottom, right, bottom); + } + // Left. + if (isOcean) + { + if (tabPane.getSelectedIndex() == tabIndex - 1) + { + g.drawLine(0, 6, 0, bottom); + if (tabIndex != firstIndex) + { + g.setColor(oceanSelectedBorder); + g.drawLine(0, 0, 0, 5); + } + } + else if (isSelected) + { + g.drawLine(0, 5, 0, bottom); + if (tabIndex != firstIndex) + { + g.setColor(darkShadow); + g.drawLine(0, 0, 0, 5); + } + } + else if (tabIndex != firstIndex) + { + g.drawLine(0, 0, 0, bottom); + } + else + { + g.drawLine(0, 6, 0, bottom); + } + } + else + { + if (tabIndex != firstIndex) + { + g.drawLine(0, 0, 0, bottom); + } + else + { + g.drawLine(0, 6, 0, bottom); + } + } + + g.translate(-x, -y); + } + + /** + * Paints the border for a tab assuming that the tab position is at the right + * ({@link #RIGHT}). + * + * @param tabIndex the tab index. + * @param g the graphics device. + * @param x the x-coordinate for the tab's bounding rectangle. + * @param y the y-coordinate for the tab's bounding rectangle. + * @param w the width for the tab's bounding rectangle. + * @param h the height for the tab's bounding rectangle. + * @param btm ??? + * @param rght ??? + * @param isSelected indicates whether the tab is selected. + */ + protected void paintRightTabBorder(int tabIndex, Graphics g, int x, int y, + int w, int h, int btm, int rght, boolean isSelected) + { + g.translate(x, y); + int bottom = h - 1; + int right = w - 1; + + int tabCount = tabPane.getTabCount(); + int currentRun = getRunForTab(tabCount, tabIndex); + int firstIndex = tabRuns[currentRun]; + + // Paint part of the above tab. + if (tabIndex != firstIndex && tabIndex > 0 && tabsOpaque) + { + Color c; + if (tabPane.getSelectedIndex() == tabIndex - 1) + c = selectColor; + else + c = getUnselectedBackground(tabIndex - 1); + g.setColor(c); + g.fillRect(right - 5, 0, 5, 3); + g.fillRect(right - 2, 3, 2, 2); + } + + // Paint highlight. + g.setColor(isSelected ? selectHighlight : highlight); + + // Slant. + g.drawLine(right - 6, 1, right - 1, 6); + // Top. + g.drawLine(0, 1, right - 6, 1); + // Left. + if (! isSelected) + { + g.drawLine(0, 1, 0, bottom); + } + + // Paint border. + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + if (isOcean && isSelected) + { + g.setColor(oceanSelectedBorder); + } + else + { + g.setColor(darkShadow); + } + + // Bottom. + int lastIndex = lastTabInRun(tabCount, currentRun); + if (tabIndex == lastIndex) + { + g.drawLine(0, bottom, right, bottom); + } + // Slant. + if (isOcean && tabPane.getSelectedIndex() == tabIndex - 1) + { + g.setColor(oceanSelectedBorder); + } + g.drawLine(right - 6, 0, right, 6); + // Top. + g.drawLine(0, 0, right - 6, 0); + // Right. + if (isOcean && isSelected) + { + g.drawLine(right, 6, right, bottom); + if (tabIndex != firstIndex) + { + g.setColor(darkShadow); + g.drawLine(right, 0, right, 5); + } + } + else if (isOcean && tabPane.getSelectedIndex() == tabIndex - 1) + { + if (tabIndex != firstIndex) + { + g.setColor(oceanSelectedBorder); + g.drawLine(right, 0, right, 6); + } + g.setColor(darkShadow); + g.drawLine(right, 7, right, bottom); + } + else if (tabIndex != firstIndex) + { + g.drawLine(right, 0, right, bottom); + } + else + { + g.drawLine(right, 6, right, bottom); + } + g.translate(-x, -y); + } + + /** + * Paints the border for a tab assuming that the tab position is at the bottom + * ({@link #BOTTOM}). + * + * @param tabIndex the tab index. + * @param g the graphics device. + * @param x the x-coordinate for the tab's bounding rectangle. + * @param y the y-coordinate for the tab's bounding rectangle. + * @param w the width for the tab's bounding rectangle. + * @param h the height for the tab's bounding rectangle. + * @param btm ??? + * @param rght ??? + * @param isSelected indicates whether the tab is selected. + */ + protected void paintBottomTabBorder(int tabIndex, Graphics g, int x, int y, + int w, int h, int btm, int rght, boolean isSelected) + { + int bottom = h - 1; + int right = w - 1; + + int tabCount = tabPane.getTabCount(); + int currentRun = getRunForTab(tabCount, tabIndex); + // Paint gap if necessary. + if (shouldFillGap(currentRun, tabIndex, x, y)) + { + g.translate(x, y); + g.setColor(getColorForGap(currentRun, x, y)); + g.fillRect(1, bottom - 4, 3, 5); + g.fillRect(4, bottom - 1, 2, 2); + g.translate(-x, -y); + } + + g.translate(x, y); + + // Paint border. + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + if (isOcean && isSelected) + { + g.setColor(oceanSelectedBorder); + } + else + { + g.setColor(darkShadow); + } + // Slant. + g.drawLine(1, bottom - 5, 6, bottom); + // Bottom. + g.drawLine(6, bottom, right, bottom); + // Right. + int lastIndex = lastTabInRun(tabCount, currentRun); + if (tabIndex == lastIndex) + { + g.drawLine(right, 0, right, bottom); + } + // Left. + if (isOcean && isSelected) + { + g.drawLine(0, 0, 0, bottom - 5); + + // Paint a connecting line to the tab below for all + // but the first tab in the last run. + if (tabIndex != tabRuns[runCount-1]) + { + g.setColor(darkShadow); + g.drawLine(0, bottom - 5, 0, bottom); + } + } + else + { + if (isOcean && tabIndex == tabPane.getSelectedIndex() + 1) + { + g.setColor(oceanSelectedBorder); + } + if (tabIndex != tabRuns[runCount - 1]) + { + g.drawLine(0, 0, 0, bottom); + } + else + { + g.drawLine(0, 0, 0, bottom - 6); + } + } + + // Paint highlight. + g.setColor(isSelected ? selectHighlight : highlight); + // Slant. + g.drawLine(1, bottom - 6, 6, bottom - 1); + // Left. + g.drawLine(1, 0, 1, bottom - 6); + + int firstIndex = tabRuns[currentRun]; + if (tabIndex == firstIndex && tabIndex != tabRuns[runCount - 1]) + { + if (tabPane.getSelectedIndex() == tabRuns[currentRun + 1]) + { + g.setColor(selectHighlight); + } + else + { + g.setColor(highlight); + } + g.drawLine(1, bottom - 4, 1, bottom); + } + + g.translate(-x, -y); + } + + /** + * Paints the background for a tab. + * + * @param g the graphics device. + * @param tabPlacement the tab placement ({@link #TOP}, {@link #LEFT}, + * {@link #BOTTOM} or {@link #RIGHT}). + * @param tabIndex the index of the tab to draw the border for. + * @param x the x-coordinate for the tab's bounding rectangle. + * @param y the y-coordinate for the tab's bounding rectangle. + * @param w the width for the tab's bounding rectangle. + * @param h the height for the tab's bounding rectangle. + * @param isSelected indicates whether or not the tab is selected. + */ + protected void paintTabBackground(Graphics g, int tabPlacement, + int tabIndex, int x, int y, int w, int h, boolean isSelected) + { + if (isSelected) + g.setColor(selectColor); + else + g.setColor(getUnselectedBackground(tabIndex)); + + switch (tabPlacement) + { + case LEFT: + g.fillRect(x + 5, y + 1, w - 5, h - 1); + g.fillRect(x + 2, y + 4, 3, h - 4); + break; + case BOTTOM: + g.fillRect(x + 2, y, w - 2, h - 3); + g.fillRect(x + 5, y + h - 4, w - 5, 3); + break; + case RIGHT: + g.fillRect(x, y + 1, w - 4, h - 1); + g.fillRect(x + w - 4, y + 5, 3, h - 5); + break; + case TOP: + default: + g.fillRect(x + 4, y + 2, w - 4, h - 2); + g.fillRect(x + 2, y + 5, 2, h - 5); + } + } + + /** + * This method paints the focus rectangle around the selected tab. + * + * @param g The Graphics object to paint with. + * @param tabPlacement The JTabbedPane's tab placement. + * @param rects The array of rectangles keeping track of size and position. + * @param tabIndex The tab index. + * @param iconRect The icon bounds. + * @param textRect The text bounds. + * @param isSelected Whether this tab is selected. + */ + protected void paintFocusIndicator(Graphics g, int tabPlacement, + Rectangle[] rects, int tabIndex, + Rectangle iconRect, Rectangle textRect, + boolean isSelected) + { + if (tabPane.hasFocus() && isSelected) + { + Rectangle rect = rects[tabIndex]; + + g.setColor(focus); + g.translate(rect.x, rect.y); + + switch (tabPlacement) + { + case LEFT: + // Top line + g.drawLine(7, 2, rect.width-2, 2); + + // Right line + g.drawLine(rect.width-1, 2, rect.width-1, rect.height-3); + + // Bottom line + g.drawLine(rect.width-2, rect.height-2, 3, rect.height-2); + + // Left line + g.drawLine(2, rect.height-3, 2, 7); + + // Slant + g.drawLine(2, 6, 6, 2); + break; + case RIGHT: + // Top line + g.drawLine(1, 2, rect.width-8, 2); + + // Slant + g.drawLine(rect.width-7, 2, rect.width-3, 6); + + // Right line + g.drawLine(rect.width-3, 7, rect.width-3, rect.height-3); + + // Bottom line + g.drawLine(rect.width-3, rect.height-2, 2, rect.height-2); + + // Left line + g.drawLine(1, rect.height-2, 1, 2); + break; + case BOTTOM: + // Top line + g.drawLine(2, 1, rect.width-2, 1); + + // Right line + g.drawLine(rect.width-1, 2, rect.width-1, rect.height-3); + + // Bottom line + g.drawLine(7, rect.height-3, rect.width-2, rect.height-3); + + // Slant + g.drawLine(6, rect.height-3, 2, rect.height-7); + + // Left line + g.drawLine(2, rect.height-8, 2, 2); + + break; + case TOP: + default: + // Top line + g.drawLine(6, 2, rect.width-2, 2); + + // Right line + g.drawLine(rect.width-1, 2, rect.width-1, rect.height-3); + + // Bottom line + g.drawLine(3, rect.height-3, rect.width-2, rect.height-3); + + // Left line + g.drawLine(2, rect.height-3, 2, 7); + + // Slant + g.drawLine(2, 6, 6, 2); + + } + + g.translate(-rect.x, -rect.y); + } + } + + /** + * Returns <code>true</code> if the tabs in the specified run should be + * padded to make the run fill the width/height of the {@link JTabbedPane}. + * + * @param tabPlacement the tab placement for the {@link JTabbedPane} (one of + * {@link #TOP}, {@link #BOTTOM}, {@link #LEFT} and {@link #RIGHT}). + * @param run the run index. + * + * @return A boolean. + */ + protected boolean shouldPadTabRun(int tabPlacement, int run) + { + // as far as I can tell, all runs should be padded except the last run + // (which is drawn at the very top for tabPlacement == TOP) + return run < this.runCount - 1; + } + + /** + * Installs the defaults for this UI. This method calls super.installDefaults + * and then loads the Metal specific defaults for TabbedPane. + */ + protected void installDefaults() + { + super.installDefaults(); + selectColor = UIManager.getColor("TabbedPane.selected"); + selectHighlight = UIManager.getColor("TabbedPane.selectHighlight"); + tabAreaBackground = UIManager.getColor("TabbedPane.tabAreaBackground"); + tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque"); + minTabWidth = 0; + } + + /** + * Returns the color for the gap. + * + * @param currentRun - The current run to return the color for + * @param x - The x position of the current run + * @param y - The y position of the current run + * + * @return the color for the gap in the current run. + */ + protected Color getColorForGap(int currentRun, int x, int y) + { + int index = tabForCoordinate(tabPane, x, y); + int selected = tabPane.getSelectedIndex(); + if (selected == index) + return selectColor; + return tabAreaBackground; + } + + /** + * Returns true if the gap should be filled in. + * + * @param currentRun - The current run + * @param tabIndex - The current tab + * @param x - The x position of the tab + * @param y - The y position of the tab + * + * @return true if the gap at the current run should be filled + */ + protected boolean shouldFillGap(int currentRun, int tabIndex, int x, int y) + { + // As far as I can tell, the gap is never filled in. + return false; + } + + /** + * Paints the highlight below the tab, if there is one. + */ + protected void paintHighlightBelowTab() + { + int selected = tabPane.getSelectedIndex(); + int tabPlacement = tabPane.getTabPlacement(); + Rectangle bounds = getTabBounds(tabPane, selected); + + hg.setColor(selectColor); + int x = bounds.x; + int y = bounds.y; + int w = bounds.width; + int h = bounds.height; + + if (tabPlacement == TOP) + hg.fillRect(x, y + h - 2, w, 30); + else if (tabPlacement == LEFT) + hg.fillRect(x + w - 1, y, 20, h); + else if (tabPlacement == BOTTOM) + hg.fillRect(x, y - h + 2, w, 30); + else if (tabPlacement == RIGHT) + hg.fillRect(x - 18, y, 20, h); + else + throw new AssertionError("Unrecognised 'tabPlacement' argument."); + hg = null; + } + + /** + * Returns true if we should rotate the tab runs. + * + * @param tabPlacement - The current tab placement. + * @param selectedRun - The selected run. + * + * @return true if the tab runs should be rotated. + */ + protected boolean shouldRotateTabRuns(int tabPlacement, + int selectedRun) + { + // false because tab runs are not rotated in the MetalLookAndFeel + return false; + } + + protected int calculateMaxTabHeight(int tabPlacement) + { + // FIXME: Why is this overridden? + return super.calculateMaxTabHeight(tabPlacement); + } + + /** + * Returns the amount of overlay among the tabs. In + * the Metal L&F the overlay for LEFT and RIGHT placement + * is half of the maxTabHeight. For TOP and BOTTOM placement + * the tabs do not overlay. + * + * @param tabPlacement the placement + * + * @return the amount of overlay among the tabs + */ + protected int getTabRunOverlay(int tabPlacement) + { + int overlay = 0; + if (tabPlacement == LEFT || tabPlacement == RIGHT) + { + int maxHeight = calculateMaxTabHeight(tabPlacement); + overlay = maxTabHeight / 2; + } + return overlay; + } + + /** + * Paints the upper edge of the content border. + * + * @param g the graphics to use for painting + * @param tabPlacement the tab placement + * @param selectedIndex the index of the selected tab + * @param x the upper left coordinate of the content area + * @param y the upper left coordinate of the content area + * @param w the width of the content area + * @param h the height of the content area + */ + protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, + int selectedIndex, int x, int y, + int w, int h) + { + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + if (isOcean) + { + g.setColor(oceanSelectedBorder); + } + else + { + g.setColor(selectHighlight); + } + + Rectangle rect = selectedIndex < 0 ? null : + getTabBounds(selectedIndex, calcRect); + + // If tabs are not placed on TOP, or if the selected tab is not in the + // run directly above the content or the selected tab is not visible, + // then we draw an unbroken line. + if (tabPlacement != TOP || selectedIndex < 0 + || rect.y + rect.height + 1 < y || rect.x < x || rect.x > x + w) + { + g.drawLine(x, y, x + w - 2, y); + if (isOcean && tabPlacement == TOP) + { + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x, y + 1, x + w - 2, y + 1); + } + } + else + { + boolean isLast = isLastTabInRun(selectedIndex); + if (isLast) + { + g.drawLine(x, y, rect.x + 1, y); + } + else + { + g.drawLine(x, y, rect.x, y); + } + + int right = x + w - 1; + if (rect.x + rect.width < right - 1) + { + if (isLast) + { + g.drawLine(rect.x + rect.width - 1, y, right - 1, y); + } + else + { + g.drawLine(rect.x + rect.width, y, right - 1, y); + } + } + else + { + g.setColor(shadow); + g.drawLine(x + w - 2, y, x + w - 2, y); + } + + // When in OceanTheme, draw another white line. + if (isOcean) + { + g.setColor(MetalLookAndFeel.getWhite()); + if (isLast) + { + g.drawLine(x, y + 1, rect.x + 1, y + 1); + } + else + { + g.drawLine(x, y + 1, rect.x, y + 1); + } + + if (rect.x + rect.width < right - 1) + { + if (isLast) + { + g.drawLine(rect.x + rect.width - 1, y + 1, right - 1, + y + 1); + } + else + { + g.drawLine(rect.x + rect.width, y + 1, right - 1, y + 1); + } + } + else + { + g.setColor(shadow); + g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1); + } + } + } + } + + /** + * Paints the lower edge of the content border. + * + * @param g the graphics to use for painting + * @param tabPlacement the tab placement + * @param selectedIndex the index of the selected tab + * @param x the upper left coordinate of the content area + * @param y the upper left coordinate of the content area + * @param w the width of the content area + * @param h the height of the content area + */ + protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, + int selectedIndex, int x, int y, + int w, int h) + { + g.setColor(darkShadow); + + // If tabs are not placed on BOTTOM, or if the selected tab is not in the + // run directly below the content or the selected tab is not visible, + // then we draw an unbroken line. + Rectangle rect = selectedIndex < 0 ? null : + getTabBounds(selectedIndex, calcRect); + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + if (tabPlacement != BOTTOM || selectedIndex < 0 || rect.y - 1 > h + || rect.x < x || rect.x > x + w) + { + if (isOcean && tabPlacement == BOTTOM) + { + g.setColor(oceanSelectedBorder); + } + g.drawLine(x, y + h - 1, x + w - 1, y + h - 1); + } + else + { + boolean isLast = isLastTabInRun(selectedIndex); + if (isOcean) + { + g.setColor(oceanSelectedBorder); + } + + int bottom = y + h - 1; + int right = x + w - 1; + if (isLast) + { + g.drawLine(x, bottom, rect.x, bottom); + } + else + { + g.drawLine(x, bottom, rect.x - 1, bottom); + } + + if (rect.x + rect.width < x + w - 2) + { + if (isLast) + { + g.drawLine(rect.x + rect.width - 1, bottom, right, bottom); + } + else + { + g.drawLine(rect.x + rect.width, bottom, right, bottom); + } + } + } + } + + /** + * Paints the left edge of the content border. + * + * @param g the graphics to use for painting + * @param tabPlacement the tab placement + * @param selectedIndex the index of the selected tab + * @param x the upper left coordinate of the content area + * @param y the upper left coordinate of the content area + * @param w the width of the content area + * @param h the height of the content area + */ + protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, + int selectedIndex, int x, int y, + int w, int h) + { + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + Rectangle rect = selectedIndex < 0 ? null : + getTabBounds(selectedIndex, calcRect); + + if (isOcean) + { + g.setColor(oceanSelectedBorder); + } + else + { + g.setColor(selectHighlight); + } + + // If tabs are not placed on LEFT, or if the selected tab is not in the + // run directly left to the content or the selected tab is not visible, + // then we draw an unbroken line. + if (tabPlacement != LEFT || selectedIndex < 0 + || rect.x + rect.width + 1 < x || rect.y < y || rect.y > y + h) + { + g.drawLine(x, y + 1, x, y + h - 2); + if (isOcean && tabPlacement == LEFT) + { + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x, y + 1, x, y + h - 2); + } + } + else + { + g.drawLine(x, y, x, rect.y + 1); + if (rect.y + rect.height < y + h - 2) + { + g.drawLine(x, rect.y + rect.height + 1, x, y + h + 2); + } + if (isOcean) + { + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x + 1, y + 1, x + 1, rect.y + 1); + if (rect.y + rect.height < y + h - 2) + { + g.drawLine(x + 1, rect.y + rect.height + 1, x + 1, y + h + 2); + } + } + } + + } + + /** + * Paints the right edge of the content border. + * + * @param g the graphics to use for painting + * @param tabPlacement the tab placement + * @param selectedIndex the index of the selected tab + * @param x the upper left coordinate of the content area + * @param y the upper left coordinate of the content area + * @param w the width of the content area + * @param h the height of the content area + */ + protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, + int selectedIndex, int x, int y, + int w, int h) + { + g.setColor(darkShadow); + Rectangle rect = selectedIndex < 0 ? null : + getTabBounds(selectedIndex, calcRect); + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + + // If tabs are not placed on RIGHT, or if the selected tab is not in the + // run directly right to the content or the selected tab is not visible, + // then we draw an unbroken line. + if (tabPlacement != RIGHT || selectedIndex < 0 || rect.x - 1 > w + || rect.y < y || rect.y > y + h) + { + if (isOcean && tabPlacement == RIGHT) + { + g.setColor(oceanSelectedBorder); + } + g.drawLine(x + w - 1, y, x + w - 1, y + h - 1); + } + else + { + if (isOcean) + { + g.setColor(oceanSelectedBorder); + } + g.drawLine(x + w - 1, y, x + w - 1, rect.y); + + if (rect.y + rect.height < y + h - 2) + { + g.drawLine(x + w - 1, rect.y + rect.height, x + w - 1, y + h - 2); + } + } + } + + /** + * Determines if the specified tab is the last tab in its tab run. + * + * @param tabIndex the index of the tab + * + * @return if the specified tab is the last tab in its tab run + */ + private boolean isLastTabInRun(int tabIndex) + { + int count = tabPane.getTabCount(); + int run = getRunForTab(count, tabIndex); + int lastIndex = lastTabInRun(count, run); + return tabIndex == lastIndex; + } + + /** + * Returns the background for an unselected tab. This first asks the + * JTabbedPane for the background at the specified tab index, if this + * is an UIResource (that means, it is inherited from the JTabbedPane) + * and the TabbedPane.unselectedBackground UI property is not null, + * this returns the value of the TabbedPane.unselectedBackground property, + * otherwise the value returned by the JTabbedPane. + * + * @param tabIndex the index of the tab for which we query the background + * + * @return the background for an unselected tab + */ + private Color getUnselectedBackground(int tabIndex) + { + Color bg = tabPane.getBackgroundAt(tabIndex); + Color unselectedBackground = + UIManager.getColor("TabbedPane.unselectedBackground"); + if (bg instanceof UIResource && unselectedBackground != null) + bg = unselectedBackground; + return bg; + } + + protected int getTabLabelShiftX(int tabPlacement, + int index, + boolean isSelected) + { + return 0; + } + + protected int getTabLabelShiftY(int tabPlacement, + int index, + boolean isSelected) + { + return 0; + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTextFieldUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalTextFieldUI.java new file mode 100644 index 000000000..f7b18dbd4 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalTextFieldUI.java @@ -0,0 +1,82 @@ +/* MetalTextFieldUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.beans.PropertyChangeEvent; + +import javax.swing.JComponent; +import javax.swing.JTextField; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTextFieldUI; + +/** + * A UI delegate for the {@link JTextField} component. + */ +public class MetalTextFieldUI extends BasicTextFieldUI +{ + /** + * Constructs a new instance of MetalTextFieldUI. + */ + public MetalTextFieldUI() + { + super(); + } + + /** + * Returns a new instance of <code>MetalTextFieldUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A new instance of <code>MetalTextFieldUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalTextFieldUI(); + } + + /** + * This method gets called when a bound property is changed on the associated + * JTextComponent. This is a hook which UI implementations may change to + * reflect how the UI displays bound properties of JTextComponent subclasses. + */ + public void propertyChange(PropertyChangeEvent evt) + { + super.propertyChange(evt); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTheme.java b/libjava/classpath/javax/swing/plaf/metal/MetalTheme.java new file mode 100644 index 000000000..209cbbe5e --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalTheme.java @@ -0,0 +1,576 @@ +/* MetalTheme.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + + +package javax.swing.plaf.metal; + +import java.awt.Color; + +import javax.swing.UIDefaults; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.FontUIResource; + +/** + * The base class for themes used by the {@link MetalLookAndFeel}. A default + * theme ({@link DefaultMetalTheme}) is provided, or you can create and use + * your own. + * + * @see MetalLookAndFeel#setCurrentTheme(MetalTheme) + */ +public abstract class MetalTheme +{ + private ColorUIResource BLACK = new ColorUIResource(Color.BLACK); + private ColorUIResource WHITE = new ColorUIResource(Color.WHITE); + + /** + * Default constructor. + */ + public MetalTheme() + { + // Do nothing here. + } + + /** + * Returns the name of the theme. + * + * @return The name of the theme. + */ + public abstract String getName(); + + /** + * Adds custom entries to the UI defaults table. This method is empty. + * + * @param table the table. + */ + public void addCustomEntriesToTable(UIDefaults table) + { + // Do nothing here. + // This method needs to be overridden to actually do something. + // It is called from MetalLookAndFeel.getDefaults(). + } + + /** + * Returns the accelerator foreground color. The default implementation + * returns the color from {@link #getPrimary1()}. + * + * @return The accelerator foreground color. + */ + public ColorUIResource getAcceleratorForeground() + { + return getPrimary1(); + } + + /** + * Returns the accelerator selected foreground color. The default + * implementation returns the color from {@link #getBlack()}. + * + * @return The accelerator selected foreground color. + */ + public ColorUIResource getAcceleratorSelectedForeground() + { + return getBlack(); + } + + /** + * Returns the control color. The default implementation returns the color + * from {@link #getSecondary3()}. + * + * @return The control color. + */ + public ColorUIResource getControl() + { + return getSecondary3(); + } + + /** + * Returns the color used for dark shadows on controls. The default + * implementation returns the color from {@link #getSecondary1()}. + * + * @return The color used for dark shadows on controls. + */ + public ColorUIResource getControlDarkShadow() + { + return getSecondary1(); + } + + /** + * Returns the color used for disabled controls. The default implementation + * returns the color from {@link #getSecondary1()}. + * + * @return The color used for disabled controls. + */ + public ColorUIResource getControlDisabled() + { + return getSecondary2(); + } + + /** + * Returns the color used to draw highlights for controls. The default + * implementation returns the color from {@link #getWhite()}. + * + * @return The color used to draw highlights for controls. + */ + public ColorUIResource getControlHighlight() + { + return getWhite(); + } + + /** + * Returns the color used to display control info. The default + * implementation returns the color from {@link #getBlack()}. + * + * @return The color used to display control info. + */ + public ColorUIResource getControlInfo() + { + return getBlack(); + } + + /** + * Returns the color used to draw shadows for controls. The default + * implementation returns the color from {@link #getSecondary2()}. + * + * @return The color used to draw shadows for controls. + */ + public ColorUIResource getControlShadow() + { + return getSecondary2(); + } + + /** + * Returns the color used for text on controls. The default implementation + * returns the color from {@link #getControlInfo()}. + * + * @return The color used for text on controls. + */ + public ColorUIResource getControlTextColor() + { + return getControlInfo(); + } + + /** + * Returns the color used for the desktop background. The default + * implementation returns the color from {@link #getPrimary2()}. + * + * @return The color used for the desktop background. + */ + public ColorUIResource getDesktopColor() + { + return getPrimary2(); + } + + /** + * Returns the color used to draw focus highlights. The default + * implementation returns the color from {@link #getPrimary2()}. + * + * @return The color used to draw focus highlights. + */ + public ColorUIResource getFocusColor() + { + return getPrimary2(); + } + + /** + * Returns the color used to draw highlighted text. The default + * implementation returns the color from {@link #getHighlightedTextColor()}. + * + * @return The color used to draw highlighted text. + */ + public ColorUIResource getHighlightedTextColor() + { + return getControlTextColor(); + } + + /** + * Returns the color used to draw text on inactive controls. The default + * implementation returns the color from {@link #getControlDisabled()}. + * + * @return The color used to draw text on inactive controls. + */ + public ColorUIResource getInactiveControlTextColor() + { + return getControlDisabled(); + } + + /** + * Returns the color used to draw inactive system text. The default + * implementation returns the color from {@link #getSecondary2()}. + * + * @return The color used to draw inactive system text. + */ + public ColorUIResource getInactiveSystemTextColor() + { + return getSecondary2(); + } + + /** + * Returns the background color for menu items. The default implementation + * returns the color from {@link #getSecondary3()}. + * + * @return The background color for menu items. + * + * @see #getMenuSelectedBackground() + */ + public ColorUIResource getMenuBackground() + { + return getSecondary3(); + } + + /** + * Returns the foreground color for disabled menu items. The default + * implementation returns the color from {@link #getSecondary2()}. + * + * @return The foreground color for disabled menu items. + * + * @see #getMenuForeground() + */ + public ColorUIResource getMenuDisabledForeground() + { + return getSecondary2(); + } + + /** + * Returns the foreground color for menu items. The default implementation + * returns the color from {@link #getBlack()}. + * + * @return The foreground color for menu items. + * + * @see #getMenuDisabledForeground() + * @see #getMenuSelectedForeground() + */ + public ColorUIResource getMenuForeground() + { + return getBlack(); + } + + /** + * Returns the background color for selected menu items. The default + * implementation returns the color from {@link #getPrimary2()}. + * + * @return The background color for selected menu items. + * + * @see #getMenuBackground() + */ + public ColorUIResource getMenuSelectedBackground() + { + return getPrimary2(); + } + + /** + * Returns the foreground color for selected menu items. The default + * implementation returns the value from {@link #getBlack()}. + * + * @return The foreground color for selected menu items. + * + * @see #getMenuForeground() + */ + public ColorUIResource getMenuSelectedForeground() + { + return getBlack(); + } + + /** + * Returns the primary color for controls. The default implementation + * returns the color from {@link #getPrimary3()}. + * + * @return The primary color for controls. + */ + public ColorUIResource getPrimaryControl() + { + return getPrimary3(); + } + + /** + * Returns the primary color for the dark shadow on controls. The default + * implementation returns the color from {@link #getPrimary1()}. + * + * @return The primary color for the dark shadow on controls. + */ + public ColorUIResource getPrimaryControlDarkShadow() + { + return getPrimary1(); + } + + /** + * Returns the primary color for the highlight on controls. The default + * implementation returns the color from {@link #getWhite()}. + * + * @return The primary color for the highlight on controls. + */ + public ColorUIResource getPrimaryControlHighlight() + { + return getWhite(); + } + + /** + * Returns the primary color for the information on controls. The default + * implementation returns the color from {@link #getBlack()}. + * + * @return The primary color for the information on controls. + */ + public ColorUIResource getPrimaryControlInfo() + { + return getBlack(); + } + + /** + * Returns the primary color for the shadow on controls. The default + * implementation returns the color from {@link #getPrimary2()}. + * + * @return The primary color for the shadow on controls. + */ + public ColorUIResource getPrimaryControlShadow() + { + return getPrimary2(); + } + + /** + * Returns the background color for separators. The default implementation + * returns the color from {@link #getWhite()}. + * + * @return The background color for separators. + */ + public ColorUIResource getSeparatorBackground() + { + return getWhite(); + } + + /** + * Returns the foreground color for separators. The default implementation + * returns the value from {@link #getPrimary1()}. + * + * @return The foreground color for separators. + */ + public ColorUIResource getSeparatorForeground() + { + return getPrimary1(); + } + + /** + * Returns the color used for system text. The default implementation + * returns the color from {@link #getBlack()}. + * + * @return The color used for system text. + */ + public ColorUIResource getSystemTextColor() + { + return getBlack(); + } + + /** + * Returns the color used to highlight text. The default implementation + * returns the color from {@link #getPrimary3()}. + * + * @return The color used to highlight text. + */ + public ColorUIResource getTextHighlightColor() + { + return getPrimary3(); + } + + /** + * Returns the color used to display user text. The default implementation + * returns the color from {@link #getBlack()}. + * + * @return The color used to display user text. + */ + public ColorUIResource getUserTextColor() + { + return getBlack(); + } + + /** + * Returns the window background color. The default implementation returns + * the color from {@link #getWhite()}. + * + * @return The window background color. + */ + public ColorUIResource getWindowBackground() + { + return getWhite(); + } + + /** + * Returns the window title background color. The default implementation + * returns the color from {@link #getPrimary3()}. + * + * @return The window title background color. + */ + public ColorUIResource getWindowTitleBackground() + { + return getPrimary3(); + } + + /** + * Returns the window title foreground color. The default implementation + * returns the color from {@link #getBlack()}. + * + * @return The window title foreground color. + */ + public ColorUIResource getWindowTitleForeground() + { + return getBlack(); + } + + /** + * Returns the background color for an inactive window title. The default + * implementation returns the color from {@link #getSecondary3()}. + * + * @return The background color for an inactive window title. + */ + public ColorUIResource getWindowTitleInactiveBackground() + { + return getSecondary3(); + } + + /** + * Returns the foreground color for an inactive window title. The default + * implementation returns the color from {@link #getBlack()}. + * + * @return The foreground color for an inactive window title. + */ + public ColorUIResource getWindowTitleInactiveForeground() + { + return getBlack(); + } + + /** + * Returns the color used for black. + * + * @return The color used for black. + */ + protected ColorUIResource getBlack() + { + return BLACK; + } + + /** + * Returns the color used for white. + * + * @return The color used for white. + */ + protected ColorUIResource getWhite() + { + return WHITE; + } + + /** + * Returns the first primary color for this theme. + * + * @return The first primary color. + */ + protected abstract ColorUIResource getPrimary1(); + + /** + * Returns the second primary color for this theme. + * + * @return The second primary color. + */ + protected abstract ColorUIResource getPrimary2(); + + /** + * Returns the third primary color for this theme. + * + * @return The third primary color. + */ + protected abstract ColorUIResource getPrimary3(); + + /** + * Returns the first secondary color for this theme. + * + * @return The first secondary color. + */ + protected abstract ColorUIResource getSecondary1(); + + /** + * Returns the second secondary color for this theme. + * + * @return The second secondary color. + */ + protected abstract ColorUIResource getSecondary2(); + + /** + * Returns the third secondary color for this theme. + * + * @return The third secondary color. + */ + protected abstract ColorUIResource getSecondary3(); + + /** + * Returns the font used for text on controls. + * + * @return The font used for text on controls. + */ + public abstract FontUIResource getControlTextFont(); + + /** + * Returns the font used for text in menus. + * + * @return The font used for text in menus. + */ + public abstract FontUIResource getMenuTextFont(); + + /** + * Returns the font used for sub text. + * + * @return The font used for sub text. + */ + public abstract FontUIResource getSubTextFont(); + + /** + * Returns the font used for system text. + * + * @return The font used for system text. + */ + public abstract FontUIResource getSystemTextFont(); + + /** + * Returns the font used for user text. + * + * @return The font used for user text. + */ + public abstract FontUIResource getUserTextFont(); + + /** + * Returns the font used for window titles. + * + * @return The font used for window titles. + */ + public abstract FontUIResource getWindowTitleFont(); + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java new file mode 100644 index 000000000..2dacd7fec --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java @@ -0,0 +1,230 @@ +/* MetalToggleButtonUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JComponent; +import javax.swing.JToggleButton; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicButtonUI; +import javax.swing.plaf.basic.BasicToggleButtonUI; + +/** + * A UI delegate for the {@link JToggleButton} component. + */ +public class MetalToggleButtonUI + extends BasicToggleButtonUI +{ + + /** The color for the focus border. */ + protected Color focusColor; + + /** The color that indicates a selected button. */ + protected Color selectColor; + + /** The color for disabled button labels. */ + protected Color disabledTextColor; + + /** + * Returns a new instance of <code>MetalToggleButtonUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A new instance of <code>MetalToggleButtonUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalToggleButtonUI(); + } + + /** + * Constructs a new instance of <code>MetalToggleButtonUI</code>. + */ + public MetalToggleButtonUI() + { + super(); + } + + /** + * Returns the color for the focus border. + * + * @return the color for the focus border + */ + protected Color getFocusColor() + { + return focusColor; + } + + /** + * Returns the color that indicates a selected button. + * + * @return the color that indicates a selected button + */ + protected Color getSelectColor() + { + return selectColor; + } + + /** + * Returns the color for the text label of disabled buttons. The value + * is initialised in the {@link #installDefaults(AbstractButton)} method + * by reading the <code>ToggleButton.disabledText</code> item from the UI + * defaults. + * + * @return The color for the text label of disabled buttons. + */ + protected Color getDisabledTextColor() + { + return disabledTextColor; + } + + /** + * Updates the button with the defaults for this look and feel. + * + * @param b the button. + */ + public void installDefaults(AbstractButton b) + { + super.installDefaults(b); + focusColor = UIManager.getColor(getPropertyPrefix() + "focus"); + selectColor = UIManager.getColor(getPropertyPrefix() + "select"); + disabledTextColor = UIManager.getColor(getPropertyPrefix() + "disabledText"); + } + + /** + * Paints the button background when it is pressed/selected. + * + * @param g the graphics device. + * @param b the button. + */ + protected void paintButtonPressed(Graphics g, AbstractButton b) + { + if (b.isContentAreaFilled() && b.isOpaque()) + { + Color saved = g.getColor(); + Rectangle bounds = SwingUtilities.getLocalBounds(b); + g.setColor(selectColor); + g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); + g.setColor(saved); + } + } + + /** + * Paints the text for the button. + * + * As of JDK 1.4 this method is obsolete. + * Use {@link BasicButtonUI#paintText(java.awt.Graphics, + * javax.swing.AbstractButton, java.awt.Rectangle, java.lang.String)}. + * + * @param g the graphics device. + * @param c the component. + * @param textRect the bounds for the text. + * @param text the text. + * + */ + protected void paintText(Graphics g, JComponent c, Rectangle textRect, + String text) + { + Font savedFont = g.getFont(); + Color savedColor = g.getColor(); + g.setFont(c.getFont()); + if (c.isEnabled()) + g.setColor(c.getForeground()); + else + g.setColor(disabledTextColor); + FontMetrics fm = g.getFontMetrics(c.getFont()); + int ascent = fm.getAscent(); + g.drawString(text, textRect.x, textRect.y + ascent); + g.setFont(savedFont); + g.setColor(savedColor); + } + + /** + * Draws the focus highlight around the text and icon. + * + * @param g the graphics device. + * @param b the button. + */ + protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, + Rectangle textRect, Rectangle iconRect) + { + if (!b.hasFocus()) + return; + Color saved = g.getColor(); + g.setColor(focusColor); + Rectangle fr = iconRect.union(textRect); + g.drawRect(fr.x - 1, fr.y - 1, fr.width + 1, fr.height + 1); + g.setColor(saved); + } + + /** + * If the property <code>ToggleButton.gradient</code> is set, then a gradient + * is painted as background, otherwise the normal superclass behaviour is + * called. + */ + public void update(Graphics g, JComponent c) + { + AbstractButton b = (AbstractButton) c; + ButtonModel m = b.getModel(); + if (b.getBackground() instanceof UIResource + && b.isContentAreaFilled() + && b.isEnabled() && ! m.isArmed() && ! m.isPressed() + && UIManager.get(getPropertyPrefix() + "gradient") != null) + { + MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(), + SwingConstants.VERTICAL, + getPropertyPrefix() + "gradient"); + paint(g, c); + } + else + super.update(g, c); + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java new file mode 100644 index 000000000..64e679c67 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java @@ -0,0 +1,298 @@ +/* MetalToolBarUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Graphics; +import java.awt.Point; +import java.awt.event.ContainerListener; +import java.awt.event.MouseEvent; + +import java.beans.PropertyChangeListener; + +import javax.swing.JComponent; +import javax.swing.JToolBar; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicToolBarUI; + +/** + * A UI delegate for the {@link JToolBar} component. + */ +public class MetalToolBarUI extends BasicToolBarUI +{ + + /** + * A listener (no longer used) that responds when components are added to or + * removed from the {@link JToolBar}. The required behaviour is now + * handled in the super class. + * + * @see MetalToolBarUI#createContainerListener() + */ + protected class MetalContainerListener + extends BasicToolBarUI.ToolBarContListener + { + /** + * Creates a new instance. + */ + protected MetalContainerListener() + { + // Nothing to do here. + } + } + + /** + * A listener (no longer used) that responds to property change events in a + * {@link JToolBar} component. The required behaviour is now handled in the + * super class. + * + * @see MetalToolBarUI#createRolloverListener() + */ + protected class MetalRolloverListener + extends BasicToolBarUI.PropertyListener + { + /** + * Creates a new instance. + */ + protected MetalRolloverListener() + { + // Nothing to do here. + } + } + + /** + * The container listener (an implementation specific field, according to the + * spec, and not used in GNU Classpath). + */ + protected ContainerListener contListener; + + /** + * The rollover listener (an implementation specific field, according to the + * spec, and not used in GNU Classpath). + */ + protected PropertyChangeListener rolloverListener; + + /** + * Creates a new instance of this UI delegate. + */ + public MetalToolBarUI() + { + super(); + } + + /** + * Returns a new instance of <code>MetalToolBarUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A new instance of <code>MetalToolBarUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalToolBarUI(); + } + + /** + * Returns <code>null</code> as permitted by recent versions of the API + * specification. Originally it seems this method returned a new instance of + * {@link MetalRolloverListener}, but this is now redundant. + * + * @return <code>null</code>. + */ + protected PropertyChangeListener createRolloverListener() + { + return null; + } + + /** + * Returns <code>null</code> as permitted by recent versions of the API + * specification. Originally it seems this method returned a new instance of + * {@link MetalContainerListener}, but this is now redundant. + * + * @return <code>null</code>. + */ + protected ContainerListener createContainerListener() + { + return null; + } + + /** + * Returns a border with no rollover effect for buttons in the tool bar. + * + * @return A border. + * + * @see MetalBorders#getToolbarButtonBorder() + */ + protected Border createNonRolloverBorder() + { + return MetalBorders.getToolbarButtonBorder(); + } + + /** + * Sets the offset for the window used for dragging the toolbar. + * It is set as long as the window is not null (it has been installed). + */ + protected void setDragOffset(Point p) + { + if (dragWindow != null) + dragWindow.setOffset(p); + } + + /** + * Creates and returns an instance of MetalDockingListener. + * + * @return an instance of MetalDockingListener. + */ + protected MouseInputListener createDockingListener() + { + return new MetalDockingListener(toolBar); + } + + /** + * This is the MouseHandler class that allows the user to drag the JToolBar + * in and out of the parent and dock it if it can. + */ + protected class MetalDockingListener extends BasicToolBarUI.DockingListener + { + /** + * Creates a new DockingListener object. + * + * @param t The JToolBar this DockingListener is being used for. + */ + public MetalDockingListener(JToolBar t) + { + super(t); + } + + /** + * This method is called when the mouse is pressed in the JToolBar. If the + * press doesn't occur in a place where it causes the JToolBar to be + * dragged, it returns. Otherwise, it starts a drag session. + * + * @param e The MouseEvent. + */ + public void mousePressed(MouseEvent e) + { + super.mousePressed(e); + setDragOffset(new Point(e.getX(), e.getY())); + } + + /** + * This method is called when the mouse is dragged. It delegates the drag + * painting to the dragTo method. + * + * @param e The MouseEvent. + */ + public void mouseDragged(MouseEvent e) + { + // Does not do anything differently than dragging + // BasicToolBarUI.DockingListener + super.mouseDragged(e); + } + } + + /** + * Installs the UI on the toolbar. This calls super and sets the rollover + * property according to the <code>UIManager</code> property + * "ToolBar.isRollover". + * + * @param c the component to install the UI on + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JToolBar) + { + JToolBar tb = (JToolBar) c; + tb.setRollover(UIManager.getBoolean("ToolBar.isRollover")); + } + } + + /** + * Uninstalls the UI from the toolbar. This calls super and resets the + * rollover property. + * + * @param c the component to uninstall the UI from + */ + public void uninstallUI(JComponent c) + { + if (c instanceof JToolBar) + { + JToolBar tb = (JToolBar) c; + tb.setRollover(false); + } + super.uninstallUI(c); + } + + /** + * Paints the background of the component if necessary and then calls + * <code>paint(g, c)</code>. + * + * This is overridden to implement the OceanTheme gradient when an OceanTheme + * is installed. + * + * @param g the graphics to use + * @param c the component to paint. + * + * @since 1.5 + */ + public void update(Graphics g, JComponent c) + { + // TODO: Sun's implementation uses the MenuBar.gradient here. + // I would consider this a bug, but implement it like this + // for compatibility. + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme + && UIManager.get("MenuBar.gradient") != null) + { + if (c.isOpaque()) + { + MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(), + SwingConstants.VERTICAL, + "MenuBar.gradient"); + } + paint(g, c); + } + else + { + super.update(g, c); + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalToolTipUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalToolTipUI.java new file mode 100644 index 000000000..742ff2204 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalToolTipUI.java @@ -0,0 +1,276 @@ +/* MetalToolTipUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.JMenuItem; +import javax.swing.JToolTip; +import javax.swing.KeyStroke; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicToolTipUI; + +/** + * A UI delegate for the {@link JToolTip} component. + */ +public class MetalToolTipUI + extends BasicToolTipUI +{ + /** + * The amount of space between the tool tip text and the accelerator + * description (if visible). + */ + public static final int padSpaceBetweenStrings = 12; + + /** The shared UI instance. */ + private static MetalToolTipUI instance; + + /** A flag controlling the visibility of the accelerator (if there is one). */ + private boolean isAcceleratorHidden; + + /** A string representing the accelerator key for the component. */ + private String acceleratorString; + + /** + * The delimiter for the accelerator string. + */ + private String acceleratorDelimiter; + + /** The font for the accelerator string. */ + private Font acceleratorFont; + + /** The color for the accelerator string. */ + private Color acceleratorForeground; + + /** The active border. */ + private Border activeBorder; + + /** The inactive border. */ + private Border inactiveBorder; + + /** + * Constructs a new instance of <code>MetalToolTipUI</code>. + */ + public MetalToolTipUI() + { + super(); + activeBorder = UIManager.getBorder("ToolTip.border"); + inactiveBorder = UIManager.getBorder("ToolTip.borderInactive"); + isAcceleratorHidden = UIManager.getBoolean("ToolTip.hideAccelerator"); + acceleratorFont = UIManager.getFont("MenuItem.acceleratorFont"); + acceleratorForeground = UIManager.getColor("MenuItem.acceleratorForeground"); + acceleratorDelimiter = UIManager.getString("MenuItem.acceleratorDelimiter"); + } + + /** + * Returns a shared instance of the <code>MetalToolTipUI</code> class. + * Although this UI delegate does maintain state information, there is never + * more than one tool tip visible, so it is OK to use a shared instance. + * + * @param component the component (a {@link JToolTip}). + * + * @return A shared instance of the <code>MetalToolTipUI</code> class. + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalToolTipUI(); + return instance; + } + + /** + * Returns a string representing the accelerator key (if there is one) for + * the component that the tool tip belongs to. + * + * @return A string representing the accelerator key. + */ + public String getAcceleratorString() + { + return acceleratorString; + } + + /** + * Installs the UI for the specified component (a {@link JToolTip}). + * + * @param c the {@link JToolTip} component. + */ + public void installUI(JComponent c) + { + super.installUI(c); + Border existingBorder = c.getBorder(); + if (existingBorder == null || existingBorder instanceof UIResource) + { + if (c.isEnabled()) + c.setBorder(activeBorder); + else + c.setBorder(inactiveBorder); + } + } + + /** + * Clears the defaults set in {@link #installUI(JComponent)}. + * + * @param c the component. + */ + public void uninstallUI(JComponent c) + { + super.uninstallUI(c); + if (c.getBorder() instanceof UIResource) + c.setBorder(null); + } + + /** + * Returns <code>true</code> if the accelerator string is hidden, and + * <code>false</code> otherwise. This setting is controlled by the + * <code>ToolTip.hideAccelerator</code> entry in the UI defaults table. + * + * @return A boolean. + */ + protected boolean isAcceleratorHidden() + { + return isAcceleratorHidden; + } + + /** + * Returns the preferred size for the {@link JToolTip} component. + * + * @param c the component (a {@link JToolTip}). + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + Dimension d = super.getPreferredSize(c); + String acc = getAcceleratorString(); + if (acc != null && ! acc.equals("")) + { + FontMetrics fm = c.getFontMetrics(c.getFont()); + d.width += fm.stringWidth(acc); + } + return d; + } + + /** + * Paints the tool tip. + * + * @param g the graphics context. + * @param c the {@link JToolTip} component. + */ + public void paint(Graphics g, JComponent c) + { + super.paint(g, c); + // Somehow paint accelerator. Keep care for possible HTML rendering. + } + + /** + * Returns a string representing the accelerator for the component, or + * <code>null</code> if the component has no accelerator. + * + * @param c the component. + * + * @return A string representing the accelerator (possibly + * <code>null</code>). + */ + private String fetchAcceleratorString(JComponent c) + { + String result = null; + if (c instanceof JToolTip) + { + JToolTip toolTip = (JToolTip) c; + JComponent component = toolTip.getComponent(); + KeyStroke ks = null; + int mne = 0; + if (component instanceof JMenuItem) + { + JMenuItem item = (JMenuItem) component; + ks = item.getAccelerator(); + if (ks == null) + mne = item.getMnemonic(); + } + else if (component instanceof AbstractButton) + { + AbstractButton button = (AbstractButton) component; + mne = button.getMnemonic(); + } + if (mne > 0) + ks = KeyStroke.getKeyStroke(Character.toUpperCase((char) mne), + InputEvent.ALT_MASK, false); + if (ks != null) + result = acceleratorToString(ks); + } + return result; + } + + /** + * Returns a string representing an accelerator. + * + * @param accelerator the accelerator (<code>null</code> not permitted). + * + * @return A string representing an accelerator. + */ + private String acceleratorToString(KeyStroke accelerator) + { + // convert keystroke into string format + String modifiersText = ""; + int modifiers = accelerator.getModifiers(); + char keyChar = accelerator.getKeyChar(); + int keyCode = accelerator.getKeyCode(); + + if (modifiers != 0) + modifiersText = KeyEvent.getKeyModifiersText(modifiers) + + acceleratorDelimiter; + + if (keyCode == KeyEvent.VK_UNDEFINED) + return modifiersText + keyChar; + else + return modifiersText + KeyEvent.getKeyText(keyCode); + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java new file mode 100644 index 000000000..bdfa2d4f6 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java @@ -0,0 +1,317 @@ +/* MetalTreeUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JComponent; +import javax.swing.JTree; +import javax.swing.UIManager; +import javax.swing.tree.TreePath; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTreeUI; + +/** + * A UI delegate for the {@link JTree} component. + */ +public class MetalTreeUI extends BasicTreeUI +{ + /** + * Listens for property changes of the line style and updates the + * internal setting. + */ + private class LineStyleListener + implements PropertyChangeListener + { + + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals(LINE_STYLE_PROPERTY)) + decodeLineStyle(e.getNewValue()); + } + + } + + /** + * The key to the lineStyle client property. + */ + private static final String LINE_STYLE_PROPERTY = "JTree.lineStyle"; + + /** + * The property value indicating no line style. + */ + private static final String LINE_STYLE_VALUE_NONE = "None"; + + /** + * The property value indicating angled line style. + */ + private static final String LINE_STYLE_VALUE_ANGLED = "Angled"; + + /** + * The property value indicating horizontal line style. + */ + private static final String LINE_STYLE_VALUE_HORIZONTAL = "Horizontal"; + + /** + * The line style for None. + */ + private static final int LINE_STYLE_NONE = 0; + + /** + * The line style for Angled. + */ + private static final int LINE_STYLE_ANGLED = 1; + + /** + * The line style for Horizontal. + */ + private static final int LINE_STYLE_HORIZONTAL = 2; + + /** + * The current line style. + */ + private int lineStyle; + + /** + * Listens for changes on the line style property and updates the + * internal settings. + */ + private PropertyChangeListener lineStyleListener; + + /** + * Constructs a new instance of <code>MetalTreeUI</code>. + */ + public MetalTreeUI() + { + super(); + } + + /** + * Returns a new instance of <code>MetalTreeUI</code>. + * + * @param component the component for which we return an UI instance + * + * @return A new instance of <code>MetalTreeUI</code>. + */ + public static ComponentUI createUI(JComponent component) + { + return new MetalTreeUI(); + } + + /** + * The horizontal element of legs between nodes starts at the right of the + * left-hand side of the child node by default. This method makes the + * leg end before that. + */ + protected int getHorizontalLegBuffer() + { + return super.getHorizontalLegBuffer(); + } + + /** + * Configures the specified component appropriate for the look and feel. + * This method is invoked when the ComponentUI instance is being installed + * as the UI delegate on the specified component. This method should completely + * configure the component for the look and feel, including the following: + * 1. Install any default property values for color, fonts, borders, icons, + * opacity, etc. on the component. Whenever possible, property values + * initialized by the client program should not be overridden. + * 2. Install a LayoutManager on the component if necessary. + * 3. Create/add any required sub-components to the component. + * 4. Create/install event listeners on the component. + * 5. Create/install a PropertyChangeListener on the component in order + * to detect and respond to component property changes appropriately. + * 6. Install keyboard UI (mnemonics, traversal, etc.) on the component. + * 7. Initialize any appropriate instance data. + */ + public void installUI(JComponent c) + { + super.installUI(c); + + Object lineStyleProp = c.getClientProperty(LINE_STYLE_PROPERTY); + decodeLineStyle(lineStyleProp); + if (lineStyleListener == null) + lineStyleListener = new LineStyleListener(); + c.addPropertyChangeListener(lineStyleListener); + } + + /** + * Reverses configuration which was done on the specified component during + * installUI. This method is invoked when this UIComponent instance is being + * removed as the UI delegate for the specified component. This method should + * undo the configuration performed in installUI, being careful to leave the + * JComponent instance in a clean state (no extraneous listeners, + * look-and-feel-specific property objects, etc.). This should include + * the following: + * 1. Remove any UI-set borders from the component. + * 2. Remove any UI-set layout managers on the component. + * 3. Remove any UI-added sub-components from the component. + * 4. Remove any UI-added event/property listeners from the component. + * 5. Remove any UI-installed keyboard UI from the component. + * 6. Nullify any allocated instance data objects to allow for GC. + */ + public void uninstallUI(JComponent c) + { + super.uninstallUI(c); + if (lineStyleListener != null) + c.removePropertyChangeListener(lineStyleListener); + lineStyleListener = null; + } + + /** + * This function converts between the string passed into the client + * property and the internal representation (currently an int). + * + * @param lineStyleFlag - String representation + */ + protected void decodeLineStyle(Object lineStyleFlag) + { + if (lineStyleFlag == null || lineStyleFlag.equals(LINE_STYLE_VALUE_ANGLED)) + lineStyle = LINE_STYLE_ANGLED; + else if (lineStyleFlag.equals(LINE_STYLE_VALUE_HORIZONTAL)) + lineStyle = LINE_STYLE_HORIZONTAL; + else if (lineStyleFlag.equals(LINE_STYLE_VALUE_NONE)) + lineStyle = LINE_STYLE_NONE; + else + lineStyle = LINE_STYLE_ANGLED; + } + + /** + * Checks if the location is in expand control. + * + * @param row - current row + * @param rowLevel - current level + * @param mouseX - current x location of the mouse click + * @param mouseY - current y location of the mouse click + */ + protected boolean isLocationInExpandControl(int row, int rowLevel, + int mouseX, int mouseY) + { + return super.isLocationInExpandControl(tree.getPathForRow(row), + mouseX, mouseY); + } + + /** + * Paints the specified component appropriate for the look and feel. + * This method is invoked from the ComponentUI.update method when the + * specified component is being painted. Subclasses should override this + * method and use the specified Graphics object to render the content of + * the component. + * + * @param g - the current graphics configuration. + * @param c - the current component to draw + */ + public void paint(Graphics g, JComponent c) + { + // Calls BasicTreeUI's paint since it takes care of painting all + // types of icons. + super.paint(g, c); + + if (lineStyle == LINE_STYLE_HORIZONTAL) + paintHorizontalSeparators(g, c); + } + + /** + * Paints the horizontal separators. + * + * @param g - the current graphics configuration. + * @param c - the current component to draw + */ + protected void paintHorizontalSeparators(Graphics g, JComponent c) + { + g.setColor(UIManager.getColor("Tree.line")); + Rectangle clip = g.getClipBounds(); + int row0 = getRowForPath(tree, getClosestPathForLocation(tree, 0, clip.y)); + int row1 = + getRowForPath(tree, getClosestPathForLocation(tree, 0, + clip.y + clip.height - 1)); + if (row0 >= 0 && row1 >= 0) + { + for (int i = row0; i <= row1; i++) + { + TreePath p = getPathForRow(tree, i); + if (p != null && p.getPathCount() == 2) + { + Rectangle r = getPathBounds(tree, getPathForRow(tree, i)); + if (r != null) + { + g.drawLine(clip.x, r.y, clip.x + clip.width, r.y); + } + } + } + } + } + + + /** + * Paints the vertical part of the leg. The receiver should NOT modify + * clipBounds, insets. + * + * @param g - the current graphics configuration. + * @param clipBounds - + * @param insets - + * @param path - the current path + */ + protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, + Insets insets, TreePath path) + { + if (lineStyle == LINE_STYLE_ANGLED) + super.paintVerticalPartOfLeg(g, clipBounds, insets, path); + } + + /** + * Paints the horizontal part of the leg. The receiver should NOT \ + * modify clipBounds, or insets. + * NOTE: parentRow can be -1 if the root is not visible. + */ + protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds, + Insets insets, Rectangle bounds, + TreePath path, int row, + boolean isExpanded, boolean hasBeenExpanded, + boolean isLeaf) + { + if (lineStyle == LINE_STYLE_ANGLED) + super.paintHorizontalPartOfLeg(g, clipBounds, insets, bounds, path, row, + isExpanded, hasBeenExpanded, isLeaf); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java new file mode 100644 index 000000000..247f92265 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java @@ -0,0 +1,597 @@ +/* MetalUtils.java +Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.metal; + +import gnu.classpath.SystemProperties; + +import java.awt.Color; +import java.awt.Component; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.TexturePaint; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.util.List; + +import javax.swing.SwingConstants; +import javax.swing.UIManager; + +/** + * Some utility and helper methods for the Metal Look & Feel. + * + * @author Roman Kennke (roman@kennke.org) + */ +class MetalUtils +{ + + /** + * The typical metal pattern for use with Graphics2D. + */ + static BufferedImage pattern2D; + + /** + * The light color to draw the pattern. + */ + static Color lightColor; + + /** + * The dark color to draw to draw the pattern. + */ + static Color darkColor; + + /** + * Fills a rectangle with the typical Metal pattern. + * + * @param g the <code>Graphics</code> context to use + * @param x the X coordinate of the upper left corner of the rectangle to + * fill + * @param y the Y coordinate of the upper left corner of the rectangle to + * fill + * @param w the width of the rectangle to fill + * @param h the height of the rectangle to fill + * @param light the light color to use + * @param dark the dark color to use + */ + static void fillMetalPattern(Component c, Graphics g, int x, int y, int w, int h, + Color light, Color dark) + { + if (g instanceof Graphics2D + && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") == null) + fillMetalPattern2D((Graphics2D) g, x, y, w, h, light, dark); + else + { + int xOff = 0; + for (int mY = y; mY < (y + h); mY++) + { + // set color alternating with every line + if (((mY - y) % 2) == 0) + g.setColor(light); + else + g.setColor(dark); + + for (int mX = x + xOff; mX < (x + w); mX += 4) + { + g.fillRect(mX, mY, 1, 1); + } + + // increase x offset + xOff++; + if (xOff > 3) + xOff = 0; + } + } + } + + /** + * Fills a rectangle with the typical Metal pattern using Java2D. + * + * @param g2d the <code>Graphics2D</code> context to use + * @param x the X coordinate of the upper left corner of the rectangle to + * fill + * @param y the Y coordinate of the upper left corner of the rectangle to + * fill + * @param w the width of the rectangle to fill + * @param h the height of the rectangle to fill + */ + static void fillMetalPattern2D(Graphics2D g2d, int x, int y, int w, int h, + Color light, Color dark) + { + if (pattern2D == null || !darkColor.equals(dark) || !lightColor.equals(light)) + initializePattern(light, dark); + + // Prepare the texture. + TexturePaint texture = + new TexturePaint(pattern2D, new Rectangle2D.Double(0., 0., 4., 4.)); + g2d.setPaint(texture); + g2d.fillRect(x, y, w, h); + } + + /** + * Initializes the pattern image. + */ + static void initializePattern(Color light, Color dark) + { + pattern2D = new BufferedImage(4, 4, BufferedImage.TYPE_INT_ARGB); + lightColor = light; + darkColor = dark; + Graphics g = pattern2D.getGraphics(); + g.setColor(light); + g.fillRect(0, 0, 1, 1); + g.fillRect(2, 2, 1, 1); + g.setColor(dark); + g.fillRect(1, 1, 1, 1); + g.fillRect(3, 3, 1, 1); + g.dispose(); + } + + /** + * Paints the typical Metal gradient. See {@link #paintGradient(Graphics, + * int, int, int, int, float, float, Color, Color, Color, int, int[][])} + * for more details. + * + * This variant paints a gradient without a mask. + * + * @param g the graphics context to use + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param dir the direction of the gradient, either + * @param uiProp the key of the UIManager property that has the parameters + */ + static void paintGradient(Graphics g, int x, int y, int w, int h, + int dir, String uiProp) + { + paintGradient(g, x, y, w, h, dir, uiProp, null); + } + + /** + * Paints the typical Metal gradient. See {@link #paintGradient(Graphics, + * int, int, int, int, float, float, Color, Color, Color, int, int[][])} + * for more details. + * + * The parameters are fetched from the UIManager using the key + * <code>uiProp</code>. The value is expected to be a {@link List} that + * contains 4 values: two {@link Double}s and 3 {@link Color} object that + * together make up the parameters passed to the painting method. + * + * @param g the graphics context to use + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param dir the direction of the gradient, either + * @param uiProp the key of the UIManager property that has the parameters + * @param mask the mask that should be used when painting the gradient as + * described above + */ + static void paintGradient(Graphics g, int x, int y, int w, int h, + int dir, String uiProp, int[][] mask) + { + List params = (List) UIManager.get(uiProp); + float g1 = ((Float) params.get(0)).floatValue(); + float g2 = ((Float) params.get(1)).floatValue(); + Color c1 = (Color) params.get(2); + Color c2 = (Color) params.get(3); + Color c3 = (Color) params.get(4); + paintGradient(g, x, y, w, h, g1, g2, c1, c2, c3, dir, mask); + } + + /** + * Paints the typical Metal gradient. The gradient is painted as follows: + * <pre> + * + * +-------+--------+--------+-----------------------------+ + * | | | | | + * +-------+--------+--------+-----------------------------+ + * c1 -> c2 -- c2 -> c1 --------> c3 + * < -g1- > < -g2- > < -g1- > + * </pre> + * + * There are 4 distinct areas in this gradient: + * <ol> + * <li>A gradient from color 1 to color 2 with the relative width specified + * by <code>g1</code></li> + * <li>A solid area with the color 2 and the relative width specified by + * <code>g2</code></li> + * <li>A gradient from color 2 to color 1 with the relative width specified + * by <code>g1</code></li> + * + * The <code>mask</code> parameter is an array if int arrays, where the first + * index specifies the row (in the gradient direction), and the second index + * is the starting and end offset of that line. This way you can specify a + * mask that should be laid over the gradient for paintint non-rectangular + * gradients. The following example should demonstrate this for painting + * a circular shaped gradient (note that the first and last line should not + * be drawn at all, they are only here to show the circular shape more + * clearly). Everything <em>inside</code> the surrounded area is filled by + * the gradient: + * + * <pre> + * 012345678 + * xxx + * 0 x x { {4, 7}, + * 1 x x {3, 8}, + * 2 x x {3, 8}, + * 3 x x {3, 8}, + * 4 x x {4, 7} } + * xxx + * </pre> + * + * The <code>mask</code> array is expected to have <code>w</code> or + * <code>h</code> array elements, depending on the direction. + * + * If the <code>mask</code> parameter is null, then the gradient is painted + * without a mask. + * + * @param g the graphics context to use + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param g1 the relative width of the c1->c2 gradients + * @param g2 the relative width of the c2 solid area + * @param c1 the color 1 + * @param c2 the color 2 + * @param c3 the color 3 + * @param dir the direction of the gradient, either + * {@link SwingConstants#HORIZONTAL} or {@link SwingConstants#VERTICAL} + * @param mask the mask that should be used when painting the gradient as + * described above + */ + static void paintGradient(Graphics g, int x, int y, int w, int h, float g1, + float g2, Color c1, Color c2, Color c3, int dir, + int[][] mask) + { + if (dir == SwingConstants.HORIZONTAL) + paintHorizontalGradient(g, x, y, w, h, g1, g2, c1, c2, c3, mask); + else + paintVerticalGradient(g, x, y, w, h, g1, g2, c1, c2, c3, mask); + } + + /** + * Paints a horizontal gradient. See {@link #paintGradient(Graphics, int, + * int, int, int, float, float, Color, Color, Color, int, int[][])} + * for details. + * + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param g1 the relative width of the c1->c2 gradients + * @param g2 the relative width of the c2 solid area + * @param c1 the color 1 + * @param c2 the color 2 + * @param c3 the color 3 + * @param mask the mask that should be used when painting the gradient as + * described above + */ + static void paintHorizontalGradient(Graphics g, int x, int y, int w, int h, + float g1, float g2, Color c1, Color c2, + Color c3, int[][] mask) + { + + if (g instanceof Graphics2D + && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") == null) + { + paintHorizontalGradient2D((Graphics2D) g, x, y, w, h, g1, g2, c1, c2, + c3, mask); + return; + } + + // Calculate the coordinates. + int y0 = y; + int y1 = y + h; + // The size of the first gradient area (c1->2). + int w1 = (int) (w * g1); + // The size of the solid c2 area. + int w2 = (int) (w * g2); + int x0 = x; + int x1 = x0 + w1; + int x2 = x1 + w2; + int x3 = x2 + w1; + int x4 = x + w; + + // Paint first gradient area (c1->c2). + int xc; // The current y coordinate. + for (xc = x0; xc < x1; xc++) + { + if (xc > x + w) + break; + + // Perform color interpolation; + double factor = (xc - x0) / (double) w1; + int rInt = (int) ((c2.getRed() - c1.getRed()) * factor + c1.getRed()); + int gInt = (int) ((c2.getGreen() - c1.getGreen()) * factor + + c1.getGreen()); + int bInt = (int) ((c2.getBlue() - c1.getBlue()) * factor + + c1.getBlue()); + Color interpolated = new Color(rInt, gInt, bInt); + g.setColor(interpolated); + if (mask != null) + { + y0 = mask[xc - x0][0] + y; + y1 = mask[xc - x0][1] + y; + } + g.fillRect(xc, y0, 1, y1 - y0); + } + // Paint solid c2 area. + g.setColor(c2); + if (mask == null) + { + g.fillRect(x1, y, x2 - x1, h); + } + else + { + for (xc = x1; xc < x2; xc++) + { + y0 = mask[xc - x0][0] + y; + y1 = mask[xc - x0][1] + y; + g.fillRect(xc, y0, 1, y1 - y0); + } + } + + // Paint second gradient area (c2->c1). + for (xc = x2; xc < x3; xc++) + { + if (xc > x + w) + break; + + // Perform color interpolation; + double factor = (xc - x2) / (double) w1; + int rInt = (int) ((c1.getRed() - c2.getRed()) * factor + c2.getRed()); + int gInt = (int) ((c1.getGreen() - c2.getGreen()) * factor + + c2.getGreen()); + int bInt = (int) ((c1.getBlue() - c2.getBlue()) * factor + + c2.getBlue()); + Color interpolated = new Color(rInt, gInt, bInt); + g.setColor(interpolated); + if (mask != null) + { + y0 = mask[xc - x0][0] + y; + y1 = mask[xc - x0][1] + y; + } + g.fillRect(xc, y0, 1, y1 - y0); + } + + // Paint third gradient area (c1->c3). + for (xc = x3; xc < x4; xc++) + { + if (xc > x + w) + break; + + // Perform color interpolation; + double factor = (xc - x3) / (double) (x4 - x3); + int rInt = (int) ((c3.getRed() - c1.getRed()) * factor + c1.getRed()); + int gInt = (int) ((c3.getGreen() - c1.getGreen()) * factor + + c1.getGreen()); + int bInt = (int) ((c3.getBlue() - c1.getBlue()) * factor + + c1.getBlue()); + Color interpolated = new Color(rInt, gInt, bInt); + g.setColor(interpolated); + if (mask != null) + { + y0 = mask[xc - x0][0] + y; + y1 = mask[xc - x0][1] + y; + } + g.drawLine(xc, y0, xc, y1); + } + } + + /** + * Paints a vertical gradient. See {@link #paintGradient(Graphics, int, int, + * int, int, float, float, Color, Color, Color, int, int[][])} for details. + * + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param g1 the relative width of the c1->c2 gradients + * @param g2 the relative width of the c2 solid area + * @param c1 the color 1 + * @param c2 the color 2 + * @param c3 the color 3 + * @param mask the mask that should be used when painting the gradient as + * described above + */ + static void paintVerticalGradient(Graphics g, int x, int y, int w, int h, + float g1, float g2, Color c1, Color c2, + Color c3, int[][] mask) + { + if (g instanceof Graphics2D + && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") == null) + { + paintVerticalGradient2D((Graphics2D) g, x, y, w, h, g1, g2, c1, c2, + c3, mask); + return; + } + + // Calculate the coordinates. + int x0 = x; + int x1 = x + w; + // The size of the first gradient area (c1->2). + int w1 = (int) (h * g1); + // The size of the solid c2 area. + int w2 = (int) (h * g2); + int y0 = y; + int y1 = y0 + w1; + int y2 = y1 + w2; + int y3 = y2 + w1; + int y4 = y + h; + + // Paint first gradient area (c1->c2). + int yc; // The current y coordinate. + for (yc = y0; yc < y1; yc++) + { + if (yc > y + h) + break; + + // Perform color interpolation; + double factor = (yc - y0) / (double) w1; + int rInt = (int) ((c2.getRed() - c1.getRed()) * factor + c1.getRed()); + int gInt = (int) ((c2.getGreen() - c1.getGreen()) * factor + + c1.getGreen()); + int bInt = (int) ((c2.getBlue() - c1.getBlue()) * factor + + c1.getBlue()); + Color interpolated = new Color(rInt, gInt, bInt); + g.setColor(interpolated); + if (mask != null) + { + x0 = mask[yc - y0][0] + x; + x1 = mask[yc - y0][1] + x; + } + g.fillRect(x0, yc, x1 - x0, 1); + } + // Paint solid c2 area. + g.setColor(c2); + if (mask == null) + { + g.fillRect(x, y1, w, y2 - y1); + } + else + { + for (yc = y1; yc < y2; yc++) + { + x0 = mask[yc - y0][0] + x; + x1 = mask[yc - y0][1] + x; + g.fillRect(x0, yc, x1 - x0, 1); + } + } + + // Paint second gradient area (c2->c1). + for (yc = y2; yc < y3; yc++) + { + if (yc > y + h) + break; + + // Perform color interpolation; + double factor = (yc - y2) / (double) w1; + int rInt = (int) ((c1.getRed() - c2.getRed()) * factor + c2.getRed()); + int gInt = (int) ((c1.getGreen() - c2.getGreen()) * factor + + c2.getGreen()); + int bInt = (int) ((c1.getBlue() - c2.getBlue()) * factor + + c2.getBlue()); + Color interpolated = new Color(rInt, gInt, bInt); + g.setColor(interpolated); + if (mask != null) + { + x0 = mask[yc - y0][0] + x; + x1 = mask[yc - y0][1] + x; + } + g.fillRect(x0, yc, x1 - x0, 1); + } + + // Paint third gradient area (c1->c3). + for (yc = y3; yc < y4; yc++) + { + if (yc > y + h) + break; + + // Perform color interpolation; + double factor = (yc - y3) / (double) (y4 - y3); + int rInt = (int) ((c3.getRed() - c1.getRed()) * factor + c1.getRed()); + int gInt = (int) ((c3.getGreen() - c1.getGreen()) * factor + + c1.getGreen()); + int bInt = (int) ((c3.getBlue() - c1.getBlue()) * factor + + c1.getBlue()); + Color interpolated = new Color(rInt, gInt, bInt); + g.setColor(interpolated); + if (mask != null) + { + x0 = mask[yc - y0][0] + x; + x1 = mask[yc - y0][1] + x; + } + g.fillRect(x0, yc, x1 - x0, 1); + } + } + + /** + * Paints a horizontal gradient using Graphics2D functionality. + * + * @param g the Graphics2D instance + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param g1 the relative width of the c1->c2 gradients + * @param g2 the relative width of the c2 solid area + * @param c1 the color 1 + * @param c2 the color 2 + * @param c3 the color 3 + * @param mask the mask that should be used when painting the gradient as + * described above + */ + private static void paintHorizontalGradient2D(Graphics2D g, int x, int y, + int w, int h, float g1, + float g2, Color c1, + Color c2, Color c3, + int[][] mask) + { + // FIXME: Handle the mask somehow, or do Graphics2D clipping instead. + GradientPaint p1 = new GradientPaint(x, y, c1, x + w * g1, y, c2); + g.setPaint(p1); + // This fills the first gradient and the solid area in one go. + g.fillRect(x, y, (int) (w * (g1 + g2)), h); + + GradientPaint p2 = new GradientPaint(x + (w * (g1 + g2)), y, c2, x + w, y, + c3); + g.setPaint(p2); + g.fillRect((int) (x + (w * (g1 + g2))), y, + (int) (w * (1. - (g1 + g2))), h); + } + + private static void paintVerticalGradient2D(Graphics2D g, int x, int y, + int w, int h, float g1, + float g2, Color c1, + Color c2, Color c3, + int[][] mask) + { + // FIXME: Handle the mask somehow, or do Graphics2D clipping instead. + GradientPaint p1 = new GradientPaint(x, y, c1, x, y + h * g1, c2); + g.setPaint(p1); + // This fills the first gradient and the solid area in one go. + g.fillRect(x, y, w, (int) (h * (g1 + g2))); + + GradientPaint p2 = new GradientPaint(x, y + (h * (g1 + g2)), c2, x, y + h, + c3); + g.setPaint(p2); + g.fillRect(x, (int) (y + (h * (g1 + g2))), w, + (int) (h * (1. - (g1 + g2)))); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/OceanTheme.java b/libjava/classpath/javax/swing/plaf/metal/OceanTheme.java new file mode 100644 index 000000000..6a6a3f5aa --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/OceanTheme.java @@ -0,0 +1,318 @@ +/* DefaultMetalTheme.java -- A modern theme for the Metal L&F + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Insets; +import java.util.Arrays; + +import javax.swing.UIDefaults; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.BorderUIResource.LineBorderUIResource; + +/** + * A modern theme for the Metal Look & Feel. + * @since 1.5 + * + * @author Roman Kennke (roman@kennke.org) + */ +public class OceanTheme extends DefaultMetalTheme +{ + /** + * The OceanTheme value for black. + */ + static final ColorUIResource BLACK = new ColorUIResource(51, 51, 51); + + /** + * The OceanTheme value for primary1. + */ + static final ColorUIResource PRIMARY1 = new ColorUIResource(99, 130, 191); + + /** + * The OceanTheme value for primary1. + */ + static final ColorUIResource PRIMARY2 = new ColorUIResource(163, 184, 204); + + /** + * The OceanTheme value for primary1. + */ + static final ColorUIResource PRIMARY3 = new ColorUIResource(184, 207, 229); + + /** + * The OceanTheme value for secondary1. + */ + static final ColorUIResource SECONDARY1 = new ColorUIResource(122, 138, 153); + + /** + * The OceanTheme value for secondary2. + */ + static final ColorUIResource SECONDARY2 = new ColorUIResource(184, 207, 229); + + /** + * The OceanTheme value for secondary3. + */ + static final ColorUIResource SECONDARY3 = new ColorUIResource(238, 238, 238); + + /** + * The OceanTheme value for inactive control text. + */ + static final ColorUIResource INACTIVE_CONTROL_TEXT = + new ColorUIResource(153, 153, 153); + + /** + * Returns the name of this theme, "Ocean" + */ + public String getName() + { + return "Ocean"; + } + + /** + * Returns the color for control text, which is the + * value of the theme's black value. + */ + public ColorUIResource getControlTextColor() + { + return getBlack(); + } + + /** + * Returns the desktop color, which is the theme's white color. + */ + public ColorUIResource getDesktopColor() + { + return getWhite(); + } + + /** + * Returns the color for inactive control text, which is the + * RGB value (153, 153, 153). + */ + public ColorUIResource getInactiveControlTextColor() + { + return INACTIVE_CONTROL_TEXT; + } + + /** + * Returns the OceanTheme's color for disabled menu foreground, + * + */ + public ColorUIResource getMenuDisabledForeground() + { + return INACTIVE_CONTROL_TEXT; + } + + + /** + * Returns the OceanTheme's color for black, the RGB value + * (51, 51, 51). + * + * @return Returns the OceanTheme's value for black + */ + protected ColorUIResource getBlack() + { + return BLACK; + } + + /** + * Return the OceanTheme's value for primary 1, the RGB value + * (99, 130, 191). + */ + protected ColorUIResource getPrimary1() + { + return PRIMARY1; + } + + /** + * Return the OceanTheme's value for primary 2, the RGB value + * (163, 184, 204). + */ + protected ColorUIResource getPrimary2() + { + return PRIMARY2; + } + + /** + * Return the OceanTheme's value for primary 1, the RGB value + * (184, 207, 229). + */ + protected ColorUIResource getPrimary3() + { + return PRIMARY3; + } + + /** + * Return the OceanTheme's value for secondary 1, the RGB value + * (122, 138, 153). + */ + protected ColorUIResource getSecondary1() + { + return SECONDARY1; + } + + /** + * Return the OceanTheme's value for secondary 2, the RGB value + * (184, 207, 229). + */ + protected ColorUIResource getSecondary2() + { + return SECONDARY2; + } + /** + * Return the OceanTheme's value for secondary 3, the RGB value + * (238, 238, 238). + */ + protected ColorUIResource getSecondary3() + { + return SECONDARY3; + } + + /** + * Adds customized entries to the UIDefaults table. + * + * @param defaults the UI defaults table + */ + public void addCustomEntriesToTable(UIDefaults defaults) + { + // Gradients. + defaults.put("Button.gradient", Arrays.asList(new Object[] + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); + defaults.put("CheckBox.gradient", Arrays.asList(new Object[] + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); + defaults.put("CheckBoxMenuItem.gradient", Arrays.asList(new Object[] + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); + defaults.put("MenuBar.gradient", Arrays.asList(new Object[] + {new Float(1.0), new Float(0.0), new ColorUIResource(Color.WHITE), + new ColorUIResource(218, 218, 218), new ColorUIResource(218, 218, 218)})); + defaults.put("RadioButton.gradient", Arrays.asList(new Object[] + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); + defaults.put("RadioButtonMenuItem.gradient", Arrays.asList(new Object[] + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); + defaults.put("ScrollBar.gradient", Arrays.asList(new Object[] + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); + defaults.put("Slider.gradient", Arrays.asList(new Object[] + {new Float(0.3), new Float(0.2), new ColorUIResource(200, 221, 242), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); + defaults.put("Slider.focusGradient", Arrays.asList(new Object[] + {new Float(0.3), new Float(0.2), new ColorUIResource(200, 221, 242), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); + defaults.put("ToggleButton.gradient", Arrays.asList(new Object[] + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); + defaults.put("InternalFrame.activeTitleGradient", Arrays.asList(new Object[] + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); + + // Colors. + ColorUIResource c1 = new ColorUIResource(200, 221, 242); + ColorUIResource c2 = new ColorUIResource(153, 153, 153); + ColorUIResource c3 = new ColorUIResource(204, 204, 204); + ColorUIResource c4 = new ColorUIResource(210, 226, 239); + ColorUIResource c5 = new ColorUIResource(218, 218, 218); + defaults.put("Button.disabledToolBarBorderBackground", c3); + defaults.put("Button.toolBarBorderBackground", c2); + defaults.put("Label.disabledForeground", c2); + defaults.put("MenuBar.borderColor", c3); + defaults.put("Slider.altTrackColor", c4); + defaults.put("SplitPane.dividerFocusColor", c1); + defaults.put("TabbedPane.contentAreaColor", c1); + defaults.put("TabbedPane.borderHightlightColor", PRIMARY1); + defaults.put("TabbedPane.selected", c1); + defaults.put("TabbedPane.tabAreaBackground", c5); + defaults.put("TabbedPane.unselectedBackground", SECONDARY3); + defaults.put("Table.gridColor", SECONDARY1); + defaults.put("ToolBar.borderColor", c3); + defaults.put("Tree.selectionBorderColor", PRIMARY1); + + // Borders. + defaults.put("List.focusCellHighlightBorder", + new LineBorderUIResource(getPrimary1())); + defaults.put("Table.focusCellHighlightBorder", + new LineBorderUIResource(getPrimary1())); + + // Insets. + defaults.put("TabbedPane.contentBorderInsets", new Insets(4, 2, 3, 3)); + defaults.put("TabbedPane.tabAreaInsets", new Insets(2, 2, 0, 6)); + + // Flags. + defaults.put("SplitPane.oneTouchButtonsOpaque", Boolean.FALSE); + defaults.put("Menu.opaque", Boolean.FALSE); + defaults.put("ToolBar.isRollover", Boolean.TRUE); + defaults.put("RadioButton.rollover", Boolean.TRUE); + defaults.put("CheckBox.rollover", Boolean.TRUE); + defaults.put("Button.rollover", Boolean.TRUE); + + // Icons. + // FIXME: Add OceanTheme icons. +// defaults.put("Tree.leafIcon", XXX); +// defaults.put("Tree.expandedIcon", XXX); +// defaults.put("Tree.openIcon", XXX); +// defaults.put("Tree.closedIcon", XXX); +// defaults.put("Tree.collapsedIcon", XXX); +// defaults.put("FileChooser.newFolderIcon", XXX); +// defaults.put("FileChooser.homeFolderIcon", XXX); +// defaults.put("FileChooser.upFolderIcon", XXX); +// defaults.put("FileView.hardDriveIcon", XXX); +// defaults.put("FileView.floppyDriveIcon", XXX); +// defaults.put("FileView.fileIcon", XXX); +// defaults.put("FileView.computerIcon", XXX); +// defaults.put("FileView.directoryIcon", XXX); +// defaults.put("OptionPane.questionIcon", XXX); +// defaults.put("OptionPane.errorIcon", XXX); +// defaults.put("OptionPane.warningIcon", XXX); +// defaults.put("OptionPane.informationIcon", XXX); +// defaults.put("InternalFrame.icon", XXX); +// defaults.put("InternalFrame.closeIcon", XXX); +// defaults.put("InternalFrame.iconifyIcon", XXX); +// defaults.put("InternalFrame.minimizeIcon", XXX); +// defaults.put("InternalFrame.maximizeIcon", XXX); +// defaults.put("InternalFrame.paletteCloseIcon", XXX); + + // UI classes. + defaults.put("MenuBarUI", "javax.swing.plaf.metal.MetalMenuBarUI"); + + // Others. + defaults.put("Button.rolloverIconType", "ocean"); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/package.html b/libjava/classpath/javax/swing/plaf/metal/package.html new file mode 100644 index 000000000..8675493b6 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/package.html @@ -0,0 +1,55 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.plaf.metal package. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.plaf.metal</title></head> + +<body> +<p>Provides a cross-platform look and feel known as "Metal". To install this +look and feel, add the following code (or something similar) +near the start of your application:</p> +<pre>try + { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + } +catch (UnsupportedLookAndFeelException e) + { + e.printStackTrace(); + }</pre> +</body> +</html> |