Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/CSSColor.java URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/CSSColor.java?rev=1913470&r1=1913469&r2=1913470&view=diff ============================================================================== --- pivot/trunk/wtk/src/org/apache/pivot/wtk/CSSColor.java (original) +++ pivot/trunk/wtk/src/org/apache/pivot/wtk/CSSColor.java Tue Oct 31 19:15:47 2023 @@ -1,376 +1,376 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.pivot.wtk; - -import java.awt.Color; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import org.apache.pivot.wtk.util.ColorUtilities; - -/** - * The complete enumeration of the CSS3/X11 color names and values, - * taken from here: - * <a href="http://www.w3.org/TR/css3-color/">http://www.w3.org/TR/css3-color/</a>, - * and including the Java {@link Color} names (with all British/American - * spelling variants). - * <p> Ugly note: Several of these colors including (but not limited to), "pink", - * "green", the "grays", etc. are different between the Java colors and these CSS - * definitions. So, to support everything, the following conventions have been - * established: - * <ol><li>The color names are (more-or-less) case-sensitive.</li> - * <li>Where there are CSS colors and Java colors with similar names (except for - * case differences), the Java colors are found using all lower case (e.g., "green") - * or all UPPER case (e.g., "GREEN") and the CSS value with a mixed-case name - * (e.g., "Green").</li> - * <li>If there is no duplicate (e.g., "AliceBlue") then the value can be found - * using any of these variants.</li> - * <li>NOTE: this means that other combinations (e.g., "gReEn") which might have - * worked in the past will now fail and throw an exception. - * </ol> - * <p> This list also contains the Java versions of the names (complete with spelling - * variations) for complete compatibility, and we put the Java variants in first - * for the sake of the lookup maps. - * <p> Note: these are available through the - * {@link GraphicsUtilities#decodeColor GraphicsUtilities.decodeColor()} - * and {@link org.apache.pivot.wtk.content.ColorItem#allCSSColors} methods. - */ -public enum CSSColor { - AliceBlue(240, 248, 255), - AntiqueWhite(250, 235, 215), - Aqua( 0, 255, 255), - Aquamarine(127, 255, 212), - Azure(240, 255, 255), - Beige(245, 245, 220), - Bisque(255, 228, 196), - black(Color.black), - BLACK(Color.BLACK), - Black( 0, 0, 0), - BlanchedAlmond(255, 235, 205), - blue(Color.blue), - BLUE(Color.BLUE), - Blue( 0, 0, 255), - BlueViolet(138, 43, 226), - Brown(165, 42, 42), - Burlywood(222, 184, 135), - CadetBlue( 95, 158, 160), - Chartreuse(127, 255, 0), - Chocolate(210, 105, 30), - Coral(255, 127, 80), - CornflowerBlue(100, 149, 237), - Cornsilk(255, 248, 220), - Crimson(220, 20, 60), - cyan(Color.cyan), - CYAN(Color.CYAN), - Cyan( 0, 255, 255), - DarkBlue( 0, 0, 139), - DarkCyan( 0, 139, 139), - DarkGoldenrod(184, 134, 11), - darkGray(Color.darkGray), - DARK_GRAY(Color.DARK_GRAY), - DarkGray(169, 169, 169), - DarkGreen( 0, 100, 0), - DarkGrey(169, 169, 169), - DarkKhaki(189, 183, 107), - DarkMagenta(139, 0, 139), - DarkOliveGreen( 85, 107, 47), - DarkOrange(255, 140, 0), - DarkOrchid(153, 50, 204), - DarkRed(139, 0, 0), - DarkSalmon(233, 150, 122), - DarkSeaGreen(143, 188, 143), - DarkSlateBlue( 72, 61, 139), - DarkSlateGray( 47, 79, 79), - DarkSlateGrey( 47, 79, 79), - DarkTurquoise( 0, 206, 209), - DarkViolet(148, 0, 211), - DeepPink(255, 20, 147), - DeepSkyBlue( 0, 191, 255), - DimGray(105, 105, 105), - DimGrey(105, 105, 105), - DodgerBlue( 30, 144, 255), - FireBrick(178, 34, 34), - FloralWhite(255, 250, 240), - ForestGreen( 34, 139, 34), - Fuchsia(255, 0, 255), - Gainsboro(220, 220, 220), - GhostWhite(248, 248, 255), - Gold(255, 215, 0), - Goldenrod(218, 165, 32), - gray(Color.gray), - GRAY(Color.GRAY), - Gray(128, 128, 128), - green(Color.green), - GREEN(Color.GREEN), - Green( 0, 128, 0), - GreenYellow(173, 255, 47), - Grey(128, 128, 128), - Honeydew(240, 255, 240), - HotPink(255, 105, 180), - IndianRed(205, 92, 92), - Indigo( 75, 0, 130), - Ivory(255, 255, 240), - Khaki(240, 230, 140), - Lavender(230, 230, 250), - LavenderBlush(255, 240, 245), - LawnGreen(124, 252, 0), - LemonChiffon(255, 250, 205), - LightBlue(173, 216, 230), - LightCoral(240, 128, 128), - LightCyan(224, 255, 255), - LightGoldenrodYellow(250, 250, 210), - lightGray(Color.lightGray), - LIGHT_GRAY(Color.LIGHT_GRAY), - LightGray(211, 211, 211), - LightGreen(144, 238, 144), - LightGrey(211, 211, 211), - LightPink(255, 182, 193), - LightSalmon(255, 160, 122), - LightSeaGreen( 32, 178, 170), - LightSkyBlue(135, 206, 250), - LightSlateGray(119, 136, 153), - LightSlateGrey(119, 136, 153), - LightSteelBlue(176, 196, 222), - LightYellow(255, 255, 224), - Lime( 0, 255, 0), - LimeGreen( 50, 205, 50), - Linen(250, 240, 230), - magenta(Color.magenta), - MAGENTA(Color.MAGENTA), - Magenta(255, 0, 255), - Maroon(128, 0, 0), - MediumAquamarine(102, 205, 170), - MediumBlue( 0, 0, 205), - MediumOrchid(186, 85, 211), - MediumPurple(147, 112, 219), - MediumSeaGreen( 60, 179, 113), - MediumSlateBlue(123, 104, 238), - MediumSpringGreen( 0, 250, 154), - MediumTurquoise( 72, 209, 204), - MediumVioletRed(199, 21, 133), - MidnightBlue( 25, 25, 112), - MintCream(245, 255, 250), - MistyRose(255, 228, 225), - Moccasin(255, 228, 181), - NavajoWhite(255, 222, 173), - Navy( 0, 0, 128), - OldLace(253, 245, 230), - Olive(128, 128, 0), - OliveDrab(107, 142, 35), - orange(Color.orange), - ORANGE(Color.ORANGE), - Orange(255, 165, 0), - OrangeRed(255, 69, 0), - Orchid(218, 112, 214), - PaleGoldenrod(238, 232, 170), - PaleGreen(152, 251, 152), - PaleTurquoise(175, 238, 238), - PaleVioletRed(219, 112, 147), - PapayaWhip(255, 239, 213), - PeachPuff(255, 218, 185), - Peru(205, 133, 63), - pink(Color.pink), - PINK(Color.PINK), - Pink(255, 192, 203), - Plum(221, 160, 221), - PowderBlue(176, 224, 230), - Purple(128, 0, 128), - red(Color.red), - RED(Color.RED), - Red(255, 0, 0), - RosyBrown(188, 143, 143), - RoyalBlue( 65, 105, 225), - SaddleBrown(139, 69, 19), - Salmon(250, 128, 114), - SandyBrown(244, 164, 96), - SeaGreen( 46, 139, 87), - Seashell(255, 245, 238), - Sienna(160, 82, 45), - Silver(192, 192, 192), - SkyBlue(135, 206, 235), - SlateBlue(106, 90, 205), - SlateGray(112, 128, 144), - SlateGrey(112, 128, 144), - Snow(255, 250, 250), - SpringGreen( 0, 255, 127), - SteelBlue( 70, 130, 180), - Tan(210, 180, 140), - Teal( 0, 128, 128), - Thistle(216, 191, 216), - Tomato(255, 99, 71), - Turquoise( 64, 224, 208), - Violet(238, 130, 238), - Wheat(245, 222, 179), - white(Color.white), - WHITE(Color.WHITE), - White(255, 255, 255), - WhiteSmoke(245, 245, 245), - yellow(Color.yellow), - YELLOW(Color.YELLOW), - Yellow(255, 255, 0), - YellowGreen(154, 205, 50); - - /** The color value associated with this CSS color name. */ - private Color color; - /** The enum name for this color for matching (note: this value, plus the upper- or lower-case - * equivalent can be used). */ - private String colorName; - - /** - * Private class that allows us to initialize lookup maps at constructor time, - * instead of in a static initializer block later. - */ - private static class Lookup { - /** A map to translate from a color name to the enum value. */ - private static Map<String, CSSColor> colorNameMap = new HashMap<>(); - /** A map to translate from a color value to the enum value. */ - private static Map<Color, CSSColor> colorValueMap = new HashMap<>(); - } - - /** - * Construct from integer R,G,B values. - * @param r The red component of the color. - * @param g The green component. - * @param b And finally the blue value. - */ - CSSColor(final int r, final int g, final int b) { - this(new Color(r, g, b)); - } - - /** - * Construct from one of the {@link Color} equivalents. - * @param awtColor The Java AWT color value this corresponds to. - */ - CSSColor(final Color awtColor) { - this.color = awtColor; - // Okay, this is ugly, BUT Color.GREEN isn't the same color as our "Green" - // (0,255,0) vs. (0,128,0), so make an ugly hack involving case, such that - // "Green" is our color, but "green" or "GREEN" is the Java version. - String cssName = super.toString(); - this.colorName = cssName; - String lowerName = cssName.toLowerCase(Locale.ENGLISH); - String upperName = cssName.toUpperCase(Locale.ENGLISH); - // Put the value in as both the native version and the lower- and - // upper-case variants, if they differ. - // Note: this generally means the Java equivalents (in lower- and - // upper-case) must come before the CSS version in mixed-case in - // the enum list. - Lookup.colorNameMap.put(cssName, this); - Lookup.colorNameMap.putIfAbsent(lowerName, this); - Lookup.colorNameMap.putIfAbsent(upperName, this); - // Note: this reverse map WILL have values replaced by later enums - // since many of these colors have the same RGB values. - Lookup.colorValueMap.put(this.color, this); - } - - /** - * @return The standard color value (RGB) for this color according - * to the W3C CSS color spec. - */ - public Color getColor() { - return this.color; - } - - /** - * @return The name of this color (as defined in the - * W3C CSS color spec), or the Java {@link Color} name. - */ - public String getColorName() { - return this.colorName; - } - - /** - * @return The enum value of the given color name (which can be upper-, lower-, - * or mixed-case) if it can be found. - * @param colorName The name of a color to match with one of our values. - * @throws IllegalArgumentException if the color name cannot be found. - */ - public static CSSColor fromString(final String colorName) { - // Note: we entered names as lower-, upper-, or mixed-case values - // (for the "green" confusion), so one of the variants should match. - CSSColor color = Lookup.colorNameMap.get(colorName); - if (color == null) { - throw new IllegalArgumentException("Incorrect Color format. " - + "Color name \"" + colorName + "\" is not valid."); - } - return color; - } - - /** - * @return The enum value of the given color value (solid color) - * if it can be found. Any transparency in the given color is stripped out - * before a match is attempted. - * @param color The solid color to match with one of our values. - * @throws IllegalArgumentException if the color value cannot be found. - */ - public static CSSColor fromColor(final Color color) { - Color solidColor = ColorUtilities.toSolidColor(color); - CSSColor cssColor = Lookup.colorValueMap.get(solidColor); - if (cssColor == null) { - throw new IllegalArgumentException("Incorrect Color value. " - + color.toString() + " does not match any CSS color."); - } - return cssColor; - } - - /** - * Return the set of all these colors with the same RGB value as the given color. - * <p> This could be a bit time-consuming because we have to search all the values. - * @param color An RGB (solid) color to match with these values. - * @return The complete set (could be empty) of these colors with the same RGB values. - */ - public static Set<CSSColor> getMatchingColors(final Color color) { - Set<CSSColor> matches = EnumSet.noneOf(CSSColor.class); - Color solidColor = ColorUtilities.toSolidColor(color); - for (CSSColor cssColor : values()) { - if (cssColor.color.equals(solidColor)) { - matches.add(cssColor); - } - } - return matches; - } - - /** - * Return the set of all these colors with the same RGB value as the given {@code CSSColor}, - * in other words, the synonyms for this color. - * <p> This could be a bit time-consuming because we have to search all the values. - * @param color One of these colors to find the matching enum values. - * @return The complete set (could be empty) of these colors with the same RGB value (not - * including the given color). - */ - public static Set<CSSColor> getMatchingColors(final CSSColor color) { - Set<CSSColor> matches = EnumSet.noneOf(CSSColor.class); - Color solidColor = color.color; - for (CSSColor cssColor : values()) { - if (cssColor.color.equals(solidColor) && cssColor != color) { - matches.add(cssColor); - } - } - return matches; - } - - /** - * @return The number of colors in this list. - */ - public static int numberOfColors() { - return values().length; - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pivot.wtk; + +import java.awt.Color; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import org.apache.pivot.wtk.util.ColorUtilities; + +/** + * The complete enumeration of the CSS3/X11 color names and values, + * taken from here: + * <a href="http://www.w3.org/TR/css3-color/">http://www.w3.org/TR/css3-color/</a>, + * and including the Java {@link Color} names (with all British/American + * spelling variants). + * <p> Ugly note: Several of these colors including (but not limited to), "pink", + * "green", the "grays", etc. are different between the Java colors and these CSS + * definitions. So, to support everything, the following conventions have been + * established: + * <ol><li>The color names are (more-or-less) case-sensitive.</li> + * <li>Where there are CSS colors and Java colors with similar names (except for + * case differences), the Java colors are found using all lower case (e.g., "green") + * or all UPPER case (e.g., "GREEN") and the CSS value with a mixed-case name + * (e.g., "Green").</li> + * <li>If there is no duplicate (e.g., "AliceBlue") then the value can be found + * using any of these variants.</li> + * <li>NOTE: this means that other combinations (e.g., "gReEn") which might have + * worked in the past will now fail and throw an exception. + * </ol> + * <p> This list also contains the Java versions of the names (complete with spelling + * variations) for complete compatibility, and we put the Java variants in first + * for the sake of the lookup maps. + * <p> Note: these are available through the + * {@link GraphicsUtilities#decodeColor GraphicsUtilities.decodeColor()} + * and {@link org.apache.pivot.wtk.content.ColorItem#allCSSColors} methods. + */ +public enum CSSColor { + AliceBlue(240, 248, 255), + AntiqueWhite(250, 235, 215), + Aqua( 0, 255, 255), + Aquamarine(127, 255, 212), + Azure(240, 255, 255), + Beige(245, 245, 220), + Bisque(255, 228, 196), + black(Color.black), + BLACK(Color.BLACK), + Black( 0, 0, 0), + BlanchedAlmond(255, 235, 205), + blue(Color.blue), + BLUE(Color.BLUE), + Blue( 0, 0, 255), + BlueViolet(138, 43, 226), + Brown(165, 42, 42), + Burlywood(222, 184, 135), + CadetBlue( 95, 158, 160), + Chartreuse(127, 255, 0), + Chocolate(210, 105, 30), + Coral(255, 127, 80), + CornflowerBlue(100, 149, 237), + Cornsilk(255, 248, 220), + Crimson(220, 20, 60), + cyan(Color.cyan), + CYAN(Color.CYAN), + Cyan( 0, 255, 255), + DarkBlue( 0, 0, 139), + DarkCyan( 0, 139, 139), + DarkGoldenrod(184, 134, 11), + darkGray(Color.darkGray), + DARK_GRAY(Color.DARK_GRAY), + DarkGray(169, 169, 169), + DarkGreen( 0, 100, 0), + DarkGrey(169, 169, 169), + DarkKhaki(189, 183, 107), + DarkMagenta(139, 0, 139), + DarkOliveGreen( 85, 107, 47), + DarkOrange(255, 140, 0), + DarkOrchid(153, 50, 204), + DarkRed(139, 0, 0), + DarkSalmon(233, 150, 122), + DarkSeaGreen(143, 188, 143), + DarkSlateBlue( 72, 61, 139), + DarkSlateGray( 47, 79, 79), + DarkSlateGrey( 47, 79, 79), + DarkTurquoise( 0, 206, 209), + DarkViolet(148, 0, 211), + DeepPink(255, 20, 147), + DeepSkyBlue( 0, 191, 255), + DimGray(105, 105, 105), + DimGrey(105, 105, 105), + DodgerBlue( 30, 144, 255), + FireBrick(178, 34, 34), + FloralWhite(255, 250, 240), + ForestGreen( 34, 139, 34), + Fuchsia(255, 0, 255), + Gainsboro(220, 220, 220), + GhostWhite(248, 248, 255), + Gold(255, 215, 0), + Goldenrod(218, 165, 32), + gray(Color.gray), + GRAY(Color.GRAY), + Gray(128, 128, 128), + green(Color.green), + GREEN(Color.GREEN), + Green( 0, 128, 0), + GreenYellow(173, 255, 47), + Grey(128, 128, 128), + Honeydew(240, 255, 240), + HotPink(255, 105, 180), + IndianRed(205, 92, 92), + Indigo( 75, 0, 130), + Ivory(255, 255, 240), + Khaki(240, 230, 140), + Lavender(230, 230, 250), + LavenderBlush(255, 240, 245), + LawnGreen(124, 252, 0), + LemonChiffon(255, 250, 205), + LightBlue(173, 216, 230), + LightCoral(240, 128, 128), + LightCyan(224, 255, 255), + LightGoldenrodYellow(250, 250, 210), + lightGray(Color.lightGray), + LIGHT_GRAY(Color.LIGHT_GRAY), + LightGray(211, 211, 211), + LightGreen(144, 238, 144), + LightGrey(211, 211, 211), + LightPink(255, 182, 193), + LightSalmon(255, 160, 122), + LightSeaGreen( 32, 178, 170), + LightSkyBlue(135, 206, 250), + LightSlateGray(119, 136, 153), + LightSlateGrey(119, 136, 153), + LightSteelBlue(176, 196, 222), + LightYellow(255, 255, 224), + Lime( 0, 255, 0), + LimeGreen( 50, 205, 50), + Linen(250, 240, 230), + magenta(Color.magenta), + MAGENTA(Color.MAGENTA), + Magenta(255, 0, 255), + Maroon(128, 0, 0), + MediumAquamarine(102, 205, 170), + MediumBlue( 0, 0, 205), + MediumOrchid(186, 85, 211), + MediumPurple(147, 112, 219), + MediumSeaGreen( 60, 179, 113), + MediumSlateBlue(123, 104, 238), + MediumSpringGreen( 0, 250, 154), + MediumTurquoise( 72, 209, 204), + MediumVioletRed(199, 21, 133), + MidnightBlue( 25, 25, 112), + MintCream(245, 255, 250), + MistyRose(255, 228, 225), + Moccasin(255, 228, 181), + NavajoWhite(255, 222, 173), + Navy( 0, 0, 128), + OldLace(253, 245, 230), + Olive(128, 128, 0), + OliveDrab(107, 142, 35), + orange(Color.orange), + ORANGE(Color.ORANGE), + Orange(255, 165, 0), + OrangeRed(255, 69, 0), + Orchid(218, 112, 214), + PaleGoldenrod(238, 232, 170), + PaleGreen(152, 251, 152), + PaleTurquoise(175, 238, 238), + PaleVioletRed(219, 112, 147), + PapayaWhip(255, 239, 213), + PeachPuff(255, 218, 185), + Peru(205, 133, 63), + pink(Color.pink), + PINK(Color.PINK), + Pink(255, 192, 203), + Plum(221, 160, 221), + PowderBlue(176, 224, 230), + Purple(128, 0, 128), + red(Color.red), + RED(Color.RED), + Red(255, 0, 0), + RosyBrown(188, 143, 143), + RoyalBlue( 65, 105, 225), + SaddleBrown(139, 69, 19), + Salmon(250, 128, 114), + SandyBrown(244, 164, 96), + SeaGreen( 46, 139, 87), + Seashell(255, 245, 238), + Sienna(160, 82, 45), + Silver(192, 192, 192), + SkyBlue(135, 206, 235), + SlateBlue(106, 90, 205), + SlateGray(112, 128, 144), + SlateGrey(112, 128, 144), + Snow(255, 250, 250), + SpringGreen( 0, 255, 127), + SteelBlue( 70, 130, 180), + Tan(210, 180, 140), + Teal( 0, 128, 128), + Thistle(216, 191, 216), + Tomato(255, 99, 71), + Turquoise( 64, 224, 208), + Violet(238, 130, 238), + Wheat(245, 222, 179), + white(Color.white), + WHITE(Color.WHITE), + White(255, 255, 255), + WhiteSmoke(245, 245, 245), + yellow(Color.yellow), + YELLOW(Color.YELLOW), + Yellow(255, 255, 0), + YellowGreen(154, 205, 50); + + /** The color value associated with this CSS color name. */ + private Color color; + /** The enum name for this color for matching (note: this value, plus the upper- or lower-case + * equivalent can be used). */ + private String colorName; + + /** + * Private class that allows us to initialize lookup maps at constructor time, + * instead of in a static initializer block later. + */ + private static class Lookup { + /** A map to translate from a color name to the enum value. */ + private static Map<String, CSSColor> colorNameMap = new HashMap<>(); + /** A map to translate from a color value to the enum value. */ + private static Map<Color, CSSColor> colorValueMap = new HashMap<>(); + } + + /** + * Construct from integer R,G,B values. + * @param r The red component of the color. + * @param g The green component. + * @param b And finally the blue value. + */ + CSSColor(final int r, final int g, final int b) { + this(new Color(r, g, b)); + } + + /** + * Construct from one of the {@link Color} equivalents. + * @param awtColor The Java AWT color value this corresponds to. + */ + CSSColor(final Color awtColor) { + this.color = awtColor; + // Okay, this is ugly, BUT Color.GREEN isn't the same color as our "Green" + // (0,255,0) vs. (0,128,0), so make an ugly hack involving case, such that + // "Green" is our color, but "green" or "GREEN" is the Java version. + String cssName = super.toString(); + this.colorName = cssName; + String lowerName = cssName.toLowerCase(Locale.ENGLISH); + String upperName = cssName.toUpperCase(Locale.ENGLISH); + // Put the value in as both the native version and the lower- and + // upper-case variants, if they differ. + // Note: this generally means the Java equivalents (in lower- and + // upper-case) must come before the CSS version in mixed-case in + // the enum list. + Lookup.colorNameMap.put(cssName, this); + Lookup.colorNameMap.putIfAbsent(lowerName, this); + Lookup.colorNameMap.putIfAbsent(upperName, this); + // Note: this reverse map WILL have values replaced by later enums + // since many of these colors have the same RGB values. + Lookup.colorValueMap.put(this.color, this); + } + + /** + * @return The standard color value (RGB) for this color according + * to the W3C CSS color spec. + */ + public Color getColor() { + return this.color; + } + + /** + * @return The name of this color (as defined in the + * W3C CSS color spec), or the Java {@link Color} name. + */ + public String getColorName() { + return this.colorName; + } + + /** + * @return The enum value of the given color name (which can be upper-, lower-, + * or mixed-case) if it can be found. + * @param colorName The name of a color to match with one of our values. + * @throws IllegalArgumentException if the color name cannot be found. + */ + public static CSSColor fromString(final String colorName) { + // Note: we entered names as lower-, upper-, or mixed-case values + // (for the "green" confusion), so one of the variants should match. + CSSColor color = Lookup.colorNameMap.get(colorName); + if (color == null) { + throw new IllegalArgumentException("Incorrect Color format. " + + "Color name \"" + colorName + "\" is not valid."); + } + return color; + } + + /** + * @return The enum value of the given color value (solid color) + * if it can be found. Any transparency in the given color is stripped out + * before a match is attempted. + * @param color The solid color to match with one of our values. + * @throws IllegalArgumentException if the color value cannot be found. + */ + public static CSSColor fromColor(final Color color) { + Color solidColor = ColorUtilities.toSolidColor(color); + CSSColor cssColor = Lookup.colorValueMap.get(solidColor); + if (cssColor == null) { + throw new IllegalArgumentException("Incorrect Color value. " + + color.toString() + " does not match any CSS color."); + } + return cssColor; + } + + /** + * Return the set of all these colors with the same RGB value as the given color. + * <p> This could be a bit time-consuming because we have to search all the values. + * @param color An RGB (solid) color to match with these values. + * @return The complete set (could be empty) of these colors with the same RGB values. + */ + public static Set<CSSColor> getMatchingColors(final Color color) { + Set<CSSColor> matches = EnumSet.noneOf(CSSColor.class); + Color solidColor = ColorUtilities.toSolidColor(color); + for (CSSColor cssColor : values()) { + if (cssColor.color.equals(solidColor)) { + matches.add(cssColor); + } + } + return matches; + } + + /** + * Return the set of all these colors with the same RGB value as the given {@code CSSColor}, + * in other words, the synonyms for this color. + * <p> This could be a bit time-consuming because we have to search all the values. + * @param color One of these colors to find the matching enum values. + * @return The complete set (could be empty) of these colors with the same RGB value (not + * including the given color). + */ + public static Set<CSSColor> getMatchingColors(final CSSColor color) { + Set<CSSColor> matches = EnumSet.noneOf(CSSColor.class); + Color solidColor = color.color; + for (CSSColor cssColor : values()) { + if (cssColor.color.equals(solidColor) && cssColor != color) { + matches.add(cssColor); + } + } + return matches; + } + + /** + * @return The number of colors in this list. + */ + public static int numberOfColors() { + return values().length; + } + +}
Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/CSSColor.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/ComponentTextInputMethodListener.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/FontUtilities.java URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/FontUtilities.java?rev=1913470&r1=1913469&r2=1913470&view=diff ============================================================================== --- pivot/trunk/wtk/src/org/apache/pivot/wtk/FontUtilities.java (original) +++ pivot/trunk/wtk/src/org/apache/pivot/wtk/FontUtilities.java Tue Oct 31 19:15:47 2023 @@ -1,407 +1,407 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.pivot.wtk; - -import java.awt.Font; -import java.awt.FontFormatException; -import java.awt.GraphicsEnvironment; -import java.io.File; -import java.io.InputStream; -import java.io.IOException; -import java.util.Locale; - -import org.apache.pivot.collections.Dictionary; -import org.apache.pivot.json.JSONSerializer; -import org.apache.pivot.serialization.SerializationException; -import org.apache.pivot.util.Utils; - -/** - * Utility class for dealing with fonts. - */ -public final class FontUtilities { - - /** The standard name for the {@code Arial} font. */ - public static final String ARIAL = "Arial"; - - /** - * A list of "standard" sans-serif fonts, useful when cross-platform - * support is necessary. - */ - public static final String SANS_SERIF_FONTS = - "Verdana, Helvetica, Arial, SansSerif"; - - /** - * A list of monospaced fonts, useful for text editing areas for code, where - * column position must be consistent. - * <p> Note: this list is adapted from the list at - * <a href="https://en.wikipedia.org/wiki/List_of_monospaced_typefaces"> - * https://en.wikipedia.org/wiki/List_of_monospaced_typefaces</a> with the most-popular or - * readily available ones listed here. - */ - public static final String MONOSPACED_FONTS = - "Courier New, Andale Mono, Cascadia Code, Consolas, Courier, DejaVu Sans Mono, " - + "Droid Sans Mono, FreeMono, Inconsolata, Letter Gothic, Liberation Mono, " - + "Lucida Console, Menlo, Monaco, Noto Mono, Overpass Mono, Monospaced"; - - - /** The obvious factor needed to convert a number to a percentage value. */ - private static final float PERCENT_SCALE = 100.0f; - - /** - * Private constructor for utility class. - */ - private FontUtilities() { - } - - /** - * Parse out just the "name" part of a font specification. - * <p> Note: this logic follows the logic in {@link Font#decode(String)}. - * - * @param str The font specification to parse. - * @return Just the font name part (which could be a list). - */ - private static String getFontName(final String str) { - String fontName = str; - int lastHyphen = str.lastIndexOf('-'); - int lastSpace = str.lastIndexOf(' '); - char sepChar = (lastHyphen > lastSpace) ? '-' : ' '; - int sizeIndex = str.lastIndexOf(sepChar); - int styleIndex = str.lastIndexOf(sepChar, sizeIndex - 1); - int length = str.length(); - - if (sizeIndex > 0 && sizeIndex + 1 < length) { - try { - Integer.valueOf(str.substring(sizeIndex + 1)); - } catch (NumberFormatException nfe) { - /* Invalid size, maybe this is the style */ - styleIndex = sizeIndex; - sizeIndex = length; - while (sizeIndex > 0 && str.charAt(sizeIndex - 1) == sepChar) { - sizeIndex--; - } - } - } - - if (styleIndex >= 0 && styleIndex + 1 < length) { - String styleName = str.substring(styleIndex + 1, sizeIndex); - styleName = styleName.toLowerCase(Locale.ENGLISH); - switch (styleName) { - case "bolditalic": - case "italic": - case "bold": - case "plain": - break; - default: - /* Not a recognized style, must be part of the name */ - styleIndex = sizeIndex; - while (styleIndex > 0 && str.charAt(styleIndex - 1) == sepChar) { - styleIndex--; - } - break; - } - fontName = str.substring(0, styleIndex); - } else { - int fontEnd = length; - if (styleIndex > 0) { - fontEnd = styleIndex; - } else if (sizeIndex > 0) { - fontEnd = sizeIndex; - } - while (fontEnd > 0 && str.charAt(fontEnd - 1) == sepChar) { - fontEnd--; - } - fontName = str.substring(0, fontEnd); - } - - return fontName; - } - - /** - * Interpret a string as a font specification. - * - * @param value Either a JSON dictionary {@link Theme#deriveFont describing - * a font relative to the current theme}, or one of the - * {@link Font#decode(String) standard Java font specifications}. - * @return The font corresponding to the specification. - * @throws IllegalArgumentException if the given string is {@code null} - * or empty or the font specification cannot be decoded. - */ - public static Font decodeFont(final String value) { - Utils.checkNullOrEmpty(value, "font"); - - Font font; - if (value.startsWith("{")) { - try { - font = Theme.deriveFont(JSONSerializer.parseMap(value)); - } catch (SerializationException exception) { - throw new IllegalArgumentException(exception); - } - } else { - font = decode(value); - } - - return font; - } - - /** - * Decode a font specification. - * <p> This is the same as {@link Font#decode(String)} except that we will allow multiple - * font/family names separated by commas as the <code><i>fontname</i></code> part of the - * spec (much the same as CSS allows). - * <p>The list of allowed formats is: - * <ul><li><i>fontname-style-pointsize</i></li> - * <li><i>fontname-pointsize</i></li> - * <li><i>fontname-style</i></li> - * <li><i>fontname</i></li> - * <li><i>fontname style pointsize</i></li> - * <li><i>fontname pointsize</i></li> - * <li><i>fontname style</i></li> - * <li><i>fontname</i></li> - * </ul> - * where <i>fontname</i> can be <i>fontname</i>[,<i>fontname</i>]*. - * - * @param str The font specification as above. - * @return The font according to the desired specification as much as possible. - * @see Font#decode(String) - */ - public static Font decode(final String str) { - if (Utils.isNullOrEmpty(str)) { - return Font.decode(str); - } - - if (str.indexOf(',') > 0) { - String name = getFontName(str); - int pos = name.length(); - String spec = pos < str.length() ? str.substring(pos) : ""; - - String[] names = name.split("\\s*,\\s*"); - for (String nm : names) { - Font f = Font.decode(nm + spec); - if (f.getName().equalsIgnoreCase(nm) || f.getFamily().equalsIgnoreCase(nm)) { - return f; - } - } - - // No names matched in the list, so use the default name - return Font.decode(Font.DIALOG + spec); - } - - return Font.decode(str); - } - - /** - * Decode a font specification, choosing the first font in the list capable of displaying - * the given characters. If only one font name is given, that font will be selected - * regardless of its ability to display the test string of characters. If no fonts in the - * list are capable of displaying the characters then the default system font (<code>DIALOG</code>) - * will be returned. - * <p> This is the same as {@link Font#decode(String)} except that we will allow multiple - * font/family names separated by commas as the <code><i>fontname</i></code> part of the - * spec (much the same as CSS allows), with the proviso that any font chosen from the list must be - * capable of displaying all the given characters. - * <p>The list of allowed formats is: - * <ul><li><i>fontname-style-pointsize</i></li> - * <li><i>fontname-pointsize</i></li> - * <li><i>fontname-style</i></li> - * <li><i>fontname</i></li> - * <li><i>fontname style pointsize</i></li> - * <li><i>fontname pointsize</i></li> - * <li><i>fontname style</i></li> - * <li><i>fontname</i></li> - * </ul> - * where <i>fontname</i> can be <i>fontname</i>[,<i>fontname</i>]*. - * - * @param str The font specification as above. - * @param testString The characters that must have glyphs available to display (can be <code>null</code> - * to skip the "capable" test) (only applicable if multiple font names are given to - * choose from). - * @return The font according to the desired specification as much as possible. - * @see Font#decode(String) - */ - public static Font decodeCapable(final String str, final String testString) { - if (Utils.isNullOrEmpty(str)) { - return Font.decode(str); - } - - if (str.indexOf(',') > 0) { - String name = getFontName(str); - int pos = name.length(); - String spec = pos < str.length() ? str.substring(pos) : ""; - - String[] names = name.split("\\s*,\\s*"); - for (String nm : names) { - Font f = Font.decode(nm + spec); - if (f.getName().equalsIgnoreCase(nm) || f.getFamily().equalsIgnoreCase(nm)) { - if (testString == null || testString.isEmpty() || f.canDisplayUpTo(testString) < 0) { - return f; - } - } - } - - // No names matched in the list, so use the default name (either monospaced or not) - if (str.indexOf("Mono") >= 0) { - return Font.decode(Font.MONOSPACED + spec); - } else { - return Font.decode(Font.DIALOG + spec); - } - } - - return Font.decode(str); - } - /** - * Get a new font with the given name, style, and size. - * <p> The {@code name} can be a comma-separated list of names, and the first one matched will be used. - * - * @param name The font name, which can be a list (such as <code>Arial,Verdana,SansSerif</code> with - * no spaces). - * @param style The integer font style (as in {@link Font#PLAIN} or {@link Font#ITALIC}). - * @param size The integer font size (in points). - * @return The newly created font with these attributes. - */ - public static Font getFont(final String name, final int style, final int size) { - if (Utils.isNullOrEmpty(name)) { - return new Font(name, style, size); - } - - if (name.indexOf(',') > 0) { - String[] names = name.split("\\s*,\\s*"); - for (String nm : names) { - Font f = new Font(nm, style, size); - if (f.getName().equalsIgnoreCase(nm) || f.getFamily().equalsIgnoreCase(nm)) { - return f; - } - } - - // No names matched in the list, so use the default name - return new Font(Font.DIALOG, style, size); - } - - return new Font(name, style, size); - } - - /** - * Decode a font size specification, taking into account "nnn%" form, and the existing size. - * - * @param sizeValue The input size value, could be a number or a numeric string, or a number - * followed by "%". - * @param existingSize The existing font size, which will be adjusted by the percentage. - * Can be null, in which case the original size is returned. Otherwise it is unused. - * @return The new font size value. - * @throws IllegalArgumentException if the sizeValue cannot be decoded. - */ - public static int decodeFontSize(final Object sizeValue, final int existingSize) { - int adjustedSize = existingSize; - - if (sizeValue != null) { - if (sizeValue instanceof String) { - String string = (String) sizeValue; - - try { - if (string.endsWith("%")) { - float percentage = Float.parseFloat(string.substring(0, string.length() - 1)) / PERCENT_SCALE; - adjustedSize = Math.round(existingSize * percentage); - } else { - adjustedSize = Float.valueOf(string).intValue(); - } - } catch (NumberFormatException nfe) { - throw new IllegalArgumentException("\"" + sizeValue + "\" is not a valid font size!"); - } - } else if (sizeValue instanceof Number) { - adjustedSize = ((Number) sizeValue).intValue(); - } else { - throw new IllegalArgumentException("\"" + sizeValue + "\" is not a valid font size!"); - } - } - - return adjustedSize; - } - - /** - * Convert any object we support into its corresponding font. - * <p> Uses {@link #decodeFont} or {@link Theme#deriveFont} - * to do the work. - * - * @param fontValue The object to be converted to a font. - * @return The converted font. - * @throws IllegalArgumentException if the value is {@code null} or - * cannot be converted. - */ - public static Font fromObject(final Object fontValue) { - Utils.checkNull(fontValue, "font"); - - if (fontValue instanceof Font) { - return (Font) fontValue; - } else if (fontValue instanceof String) { - return decodeFont((String) fontValue); - } else if (fontValue instanceof Dictionary) { - @SuppressWarnings("unchecked") - Dictionary<String, ?> fontDictionary = (Dictionary<String, ?>) fontValue; - return Theme.deriveFont(fontDictionary); - } else { - throw new IllegalArgumentException("Unable to convert " - + fontValue.getClass().getSimpleName() + " to Font!"); - } - } - - /** - * Install a new font for use by this program (only). - * - * @param fullFontFilePath The complete path (on disk) to the local font file - * (must be a TrueType font in this case). - * @return The newly created / registered font if successful, <code>null</code> otherwise. - * @throws IOException if there was a problem reading the font from the file. - * @throws FontFormatException if the font file itself was malformed. - */ - public static Font registerFont(final File fullFontFilePath) - throws IOException, FontFormatException { - try { - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - Font f = Font.createFont(Font.TRUETYPE_FONT, fullFontFilePath); - if (ge.registerFont(f)) { - return f; - } - return null; - } catch (IOException | FontFormatException ex) { - throw ex; - } - } - - /** - * Install a new font for use by this program (only). - * - * @param fontInputStream The stream of bytes describing this font - * (must be a TrueType font in this case). Also note that the - * caller is responsible for closing this input stream. - * @return The newly created / registered font if successful, <code>null</code> otherwise. - * @throws IOException if there was a problem reading the font from the file. - * @throws FontFormatException if the font file itself was malformed. - */ - public static Font registerFont(final InputStream fontInputStream) - throws IOException, FontFormatException { - try { - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - Font f = Font.createFont(Font.TRUETYPE_FONT, fontInputStream); - if (ge.registerFont(f)) { - return f; - } - return null; - } catch (IOException | FontFormatException ex) { - throw ex; - } - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pivot.wtk; + +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.GraphicsEnvironment; +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.util.Locale; + +import org.apache.pivot.collections.Dictionary; +import org.apache.pivot.json.JSONSerializer; +import org.apache.pivot.serialization.SerializationException; +import org.apache.pivot.util.Utils; + +/** + * Utility class for dealing with fonts. + */ +public final class FontUtilities { + + /** The standard name for the {@code Arial} font. */ + public static final String ARIAL = "Arial"; + + /** + * A list of "standard" sans-serif fonts, useful when cross-platform + * support is necessary. + */ + public static final String SANS_SERIF_FONTS = + "Verdana, Helvetica, Arial, SansSerif"; + + /** + * A list of monospaced fonts, useful for text editing areas for code, where + * column position must be consistent. + * <p> Note: this list is adapted from the list at + * <a href="https://en.wikipedia.org/wiki/List_of_monospaced_typefaces"> + * https://en.wikipedia.org/wiki/List_of_monospaced_typefaces</a> with the most-popular or + * readily available ones listed here. + */ + public static final String MONOSPACED_FONTS = + "Courier New, Andale Mono, Cascadia Code, Consolas, Courier, DejaVu Sans Mono, " + + "Droid Sans Mono, FreeMono, Inconsolata, Letter Gothic, Liberation Mono, " + + "Lucida Console, Menlo, Monaco, Noto Mono, Overpass Mono, Monospaced"; + + + /** The obvious factor needed to convert a number to a percentage value. */ + private static final float PERCENT_SCALE = 100.0f; + + /** + * Private constructor for utility class. + */ + private FontUtilities() { + } + + /** + * Parse out just the "name" part of a font specification. + * <p> Note: this logic follows the logic in {@link Font#decode(String)}. + * + * @param str The font specification to parse. + * @return Just the font name part (which could be a list). + */ + private static String getFontName(final String str) { + String fontName = str; + int lastHyphen = str.lastIndexOf('-'); + int lastSpace = str.lastIndexOf(' '); + char sepChar = (lastHyphen > lastSpace) ? '-' : ' '; + int sizeIndex = str.lastIndexOf(sepChar); + int styleIndex = str.lastIndexOf(sepChar, sizeIndex - 1); + int length = str.length(); + + if (sizeIndex > 0 && sizeIndex + 1 < length) { + try { + Integer.valueOf(str.substring(sizeIndex + 1)); + } catch (NumberFormatException nfe) { + /* Invalid size, maybe this is the style */ + styleIndex = sizeIndex; + sizeIndex = length; + while (sizeIndex > 0 && str.charAt(sizeIndex - 1) == sepChar) { + sizeIndex--; + } + } + } + + if (styleIndex >= 0 && styleIndex + 1 < length) { + String styleName = str.substring(styleIndex + 1, sizeIndex); + styleName = styleName.toLowerCase(Locale.ENGLISH); + switch (styleName) { + case "bolditalic": + case "italic": + case "bold": + case "plain": + break; + default: + /* Not a recognized style, must be part of the name */ + styleIndex = sizeIndex; + while (styleIndex > 0 && str.charAt(styleIndex - 1) == sepChar) { + styleIndex--; + } + break; + } + fontName = str.substring(0, styleIndex); + } else { + int fontEnd = length; + if (styleIndex > 0) { + fontEnd = styleIndex; + } else if (sizeIndex > 0) { + fontEnd = sizeIndex; + } + while (fontEnd > 0 && str.charAt(fontEnd - 1) == sepChar) { + fontEnd--; + } + fontName = str.substring(0, fontEnd); + } + + return fontName; + } + + /** + * Interpret a string as a font specification. + * + * @param value Either a JSON dictionary {@link Theme#deriveFont describing + * a font relative to the current theme}, or one of the + * {@link Font#decode(String) standard Java font specifications}. + * @return The font corresponding to the specification. + * @throws IllegalArgumentException if the given string is {@code null} + * or empty or the font specification cannot be decoded. + */ + public static Font decodeFont(final String value) { + Utils.checkNullOrEmpty(value, "font"); + + Font font; + if (value.startsWith("{")) { + try { + font = Theme.deriveFont(JSONSerializer.parseMap(value)); + } catch (SerializationException exception) { + throw new IllegalArgumentException(exception); + } + } else { + font = decode(value); + } + + return font; + } + + /** + * Decode a font specification. + * <p> This is the same as {@link Font#decode(String)} except that we will allow multiple + * font/family names separated by commas as the <code><i>fontname</i></code> part of the + * spec (much the same as CSS allows). + * <p>The list of allowed formats is: + * <ul><li><i>fontname-style-pointsize</i></li> + * <li><i>fontname-pointsize</i></li> + * <li><i>fontname-style</i></li> + * <li><i>fontname</i></li> + * <li><i>fontname style pointsize</i></li> + * <li><i>fontname pointsize</i></li> + * <li><i>fontname style</i></li> + * <li><i>fontname</i></li> + * </ul> + * where <i>fontname</i> can be <i>fontname</i>[,<i>fontname</i>]*. + * + * @param str The font specification as above. + * @return The font according to the desired specification as much as possible. + * @see Font#decode(String) + */ + public static Font decode(final String str) { + if (Utils.isNullOrEmpty(str)) { + return Font.decode(str); + } + + if (str.indexOf(',') > 0) { + String name = getFontName(str); + int pos = name.length(); + String spec = pos < str.length() ? str.substring(pos) : ""; + + String[] names = name.split("\\s*,\\s*"); + for (String nm : names) { + Font f = Font.decode(nm + spec); + if (f.getName().equalsIgnoreCase(nm) || f.getFamily().equalsIgnoreCase(nm)) { + return f; + } + } + + // No names matched in the list, so use the default name + return Font.decode(Font.DIALOG + spec); + } + + return Font.decode(str); + } + + /** + * Decode a font specification, choosing the first font in the list capable of displaying + * the given characters. If only one font name is given, that font will be selected + * regardless of its ability to display the test string of characters. If no fonts in the + * list are capable of displaying the characters then the default system font (<code>DIALOG</code>) + * will be returned. + * <p> This is the same as {@link Font#decode(String)} except that we will allow multiple + * font/family names separated by commas as the <code><i>fontname</i></code> part of the + * spec (much the same as CSS allows), with the proviso that any font chosen from the list must be + * capable of displaying all the given characters. + * <p>The list of allowed formats is: + * <ul><li><i>fontname-style-pointsize</i></li> + * <li><i>fontname-pointsize</i></li> + * <li><i>fontname-style</i></li> + * <li><i>fontname</i></li> + * <li><i>fontname style pointsize</i></li> + * <li><i>fontname pointsize</i></li> + * <li><i>fontname style</i></li> + * <li><i>fontname</i></li> + * </ul> + * where <i>fontname</i> can be <i>fontname</i>[,<i>fontname</i>]*. + * + * @param str The font specification as above. + * @param testString The characters that must have glyphs available to display (can be <code>null</code> + * to skip the "capable" test) (only applicable if multiple font names are given to + * choose from). + * @return The font according to the desired specification as much as possible. + * @see Font#decode(String) + */ + public static Font decodeCapable(final String str, final String testString) { + if (Utils.isNullOrEmpty(str)) { + return Font.decode(str); + } + + if (str.indexOf(',') > 0) { + String name = getFontName(str); + int pos = name.length(); + String spec = pos < str.length() ? str.substring(pos) : ""; + + String[] names = name.split("\\s*,\\s*"); + for (String nm : names) { + Font f = Font.decode(nm + spec); + if (f.getName().equalsIgnoreCase(nm) || f.getFamily().equalsIgnoreCase(nm)) { + if (testString == null || testString.isEmpty() || f.canDisplayUpTo(testString) < 0) { + return f; + } + } + } + + // No names matched in the list, so use the default name (either monospaced or not) + if (str.indexOf("Mono") >= 0) { + return Font.decode(Font.MONOSPACED + spec); + } else { + return Font.decode(Font.DIALOG + spec); + } + } + + return Font.decode(str); + } + /** + * Get a new font with the given name, style, and size. + * <p> The {@code name} can be a comma-separated list of names, and the first one matched will be used. + * + * @param name The font name, which can be a list (such as <code>Arial,Verdana,SansSerif</code> with + * no spaces). + * @param style The integer font style (as in {@link Font#PLAIN} or {@link Font#ITALIC}). + * @param size The integer font size (in points). + * @return The newly created font with these attributes. + */ + public static Font getFont(final String name, final int style, final int size) { + if (Utils.isNullOrEmpty(name)) { + return new Font(name, style, size); + } + + if (name.indexOf(',') > 0) { + String[] names = name.split("\\s*,\\s*"); + for (String nm : names) { + Font f = new Font(nm, style, size); + if (f.getName().equalsIgnoreCase(nm) || f.getFamily().equalsIgnoreCase(nm)) { + return f; + } + } + + // No names matched in the list, so use the default name + return new Font(Font.DIALOG, style, size); + } + + return new Font(name, style, size); + } + + /** + * Decode a font size specification, taking into account "nnn%" form, and the existing size. + * + * @param sizeValue The input size value, could be a number or a numeric string, or a number + * followed by "%". + * @param existingSize The existing font size, which will be adjusted by the percentage. + * Can be null, in which case the original size is returned. Otherwise it is unused. + * @return The new font size value. + * @throws IllegalArgumentException if the sizeValue cannot be decoded. + */ + public static int decodeFontSize(final Object sizeValue, final int existingSize) { + int adjustedSize = existingSize; + + if (sizeValue != null) { + if (sizeValue instanceof String) { + String string = (String) sizeValue; + + try { + if (string.endsWith("%")) { + float percentage = Float.parseFloat(string.substring(0, string.length() - 1)) / PERCENT_SCALE; + adjustedSize = Math.round(existingSize * percentage); + } else { + adjustedSize = Float.valueOf(string).intValue(); + } + } catch (NumberFormatException nfe) { + throw new IllegalArgumentException("\"" + sizeValue + "\" is not a valid font size!"); + } + } else if (sizeValue instanceof Number) { + adjustedSize = ((Number) sizeValue).intValue(); + } else { + throw new IllegalArgumentException("\"" + sizeValue + "\" is not a valid font size!"); + } + } + + return adjustedSize; + } + + /** + * Convert any object we support into its corresponding font. + * <p> Uses {@link #decodeFont} or {@link Theme#deriveFont} + * to do the work. + * + * @param fontValue The object to be converted to a font. + * @return The converted font. + * @throws IllegalArgumentException if the value is {@code null} or + * cannot be converted. + */ + public static Font fromObject(final Object fontValue) { + Utils.checkNull(fontValue, "font"); + + if (fontValue instanceof Font) { + return (Font) fontValue; + } else if (fontValue instanceof String) { + return decodeFont((String) fontValue); + } else if (fontValue instanceof Dictionary) { + @SuppressWarnings("unchecked") + Dictionary<String, ?> fontDictionary = (Dictionary<String, ?>) fontValue; + return Theme.deriveFont(fontDictionary); + } else { + throw new IllegalArgumentException("Unable to convert " + + fontValue.getClass().getSimpleName() + " to Font!"); + } + } + + /** + * Install a new font for use by this program (only). + * + * @param fullFontFilePath The complete path (on disk) to the local font file + * (must be a TrueType font in this case). + * @return The newly created / registered font if successful, <code>null</code> otherwise. + * @throws IOException if there was a problem reading the font from the file. + * @throws FontFormatException if the font file itself was malformed. + */ + public static Font registerFont(final File fullFontFilePath) + throws IOException, FontFormatException { + try { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + Font f = Font.createFont(Font.TRUETYPE_FONT, fullFontFilePath); + if (ge.registerFont(f)) { + return f; + } + return null; + } catch (IOException | FontFormatException ex) { + throw ex; + } + } + + /** + * Install a new font for use by this program (only). + * + * @param fontInputStream The stream of bytes describing this font + * (must be a TrueType font in this case). Also note that the + * caller is responsible for closing this input stream. + * @return The newly created / registered font if successful, <code>null</code> otherwise. + * @throws IOException if there was a problem reading the font from the file. + * @throws FontFormatException if the font file itself was malformed. + */ + public static Font registerFont(final InputStream fontInputStream) + throws IOException, FontFormatException { + try { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + Font f = Font.createFont(Font.TRUETYPE_FONT, fontInputStream); + if (ge.registerFont(f)) { + return f; + } + return null; + } catch (IOException | FontFormatException ex) { + throw ex; + } + } + +} Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/FontUtilities.java ------------------------------------------------------------------------------ svn:eol-style = native