19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing.plaf.synth; 26 27 import java.awt.*; 28 import javax.swing.*; 29 import javax.swing.border.Border; 30 import javax.swing.plaf.UIResource; 31 import javax.swing.plaf.basic.BasicLookAndFeel; 32 import javax.swing.text.DefaultEditorKit; 33 import java.util.HashMap; 34 import java.util.Map; 35 import javax.swing.text.JTextComponent; 36 import sun.swing.SwingUtilities2; 37 38 /** 39 * <code>SynthStyle</code> is a set of style properties. 40 * Each <code>SynthUI</code> references at least one 41 * <code>SynthStyle</code> that is obtained using a 42 * <code>SynthStyleFactory</code>. You typically don't need to interact with 43 * this class directly, rather you will load a 44 * <a href="doc-files/synthFileFormat.html">Synth File Format file</a> into 45 * <code>SynthLookAndFeel</code> that will create a set of SynthStyles. 46 * 47 * @see SynthLookAndFeel 48 * @see SynthStyleFactory 49 * 50 * @since 1.5 51 * @author Scott Violet 52 */ 53 public abstract class SynthStyle { 54 /** 55 * Contains the default values for certain properties. 56 */ 57 private static Map<Object, Object> DEFAULT_VALUES; 58 59 /** 60 * Shared SynthGraphics. 61 */ 62 private static final SynthGraphicsUtils SYNTH_GRAPHICS = 63 new SynthGraphicsUtils(); 64 65 /** 719 if (DEFAULT_VALUES == null) { 720 DEFAULT_VALUES = new HashMap<Object, Object>(); 721 populateDefaultValues(); 722 } 723 Object value = DEFAULT_VALUES.get(key); 724 if (value instanceof UIDefaults.LazyValue) { 725 value = ((UIDefaults.LazyValue)value).createValue(null); 726 DEFAULT_VALUES.put(key, value); 727 } 728 return value; 729 } 730 } 731 732 /** 733 * Constructs a SynthStyle. 734 */ 735 public SynthStyle() { 736 } 737 738 /** 739 * Returns the <code>SynthGraphicUtils</code> for the specified context. 740 * 741 * @param context SynthContext identifying requester 742 * @return SynthGraphicsUtils 743 */ 744 public SynthGraphicsUtils getGraphicsUtils(SynthContext context) { 745 return SYNTH_GRAPHICS; 746 } 747 748 /** 749 * Returns the color for the specified state. This gives precedence to 750 * foreground and background of the <code>JComponent</code>. If the 751 * <code>Color</code> from the <code>JComponent</code> is not appropriate, 752 * or not used, this will invoke <code>getColorForState</code>. Subclasses 753 * should generally not have to override this, instead override 754 * {@link #getColorForState}. 755 * 756 * @param context SynthContext identifying requester 757 * @param type Type of color being requested. 758 * @return Color 759 */ 760 public Color getColor(SynthContext context, ColorType type) { 761 JComponent c = context.getComponent(); 762 Region id = context.getRegion(); 763 764 if ((context.getComponentState() & SynthConstants.DISABLED) != 0) { 765 //This component is disabled, so return the disabled color. 766 //In some cases this means ignoring the color specified by the 767 //developer on the component. In other cases it means using a 768 //specified disabledTextColor, such as on JTextComponents. 769 //For example, JLabel doesn't specify a disabled color that the 770 //developer can set, yet it should have a disabled color to the 771 //text when the label is disabled. This code allows for that. 772 if (c instanceof JTextComponent) { 801 // Then use what we've locally defined 802 color = getColorForState(context, type); 803 } 804 805 if (color == null) { 806 // No color, fallback to that of the widget. 807 if (type == ColorType.BACKGROUND || 808 type == ColorType.TEXT_BACKGROUND) { 809 return c.getBackground(); 810 } 811 else if (type == ColorType.FOREGROUND || 812 type == ColorType.TEXT_FOREGROUND) { 813 return c.getForeground(); 814 } 815 } 816 return color; 817 } 818 819 /** 820 * Returns the color for the specified state. This should NOT call any 821 * methods on the <code>JComponent</code>. 822 * 823 * @param context SynthContext identifying requester 824 * @param type Type of color being requested. 825 * @return Color to render with 826 */ 827 protected abstract Color getColorForState(SynthContext context, 828 ColorType type); 829 830 /** 831 * Returns the Font for the specified state. This redirects to the 832 * <code>JComponent</code> from the <code>context</code> as necessary. 833 * If this does not redirect 834 * to the JComponent {@link #getFontForState} is invoked. 835 * 836 * @param context SynthContext identifying requester 837 * @return Font to render with 838 */ 839 public Font getFont(SynthContext context) { 840 JComponent c = context.getComponent(); 841 if (context.getComponentState() == SynthConstants.ENABLED) { 842 return c.getFont(); 843 } 844 Font cFont = c.getFont(); 845 if (cFont != null && !(cFont instanceof UIResource)) { 846 return cFont; 847 } 848 return getFontForState(context); 849 } 850 851 /** 852 * Returns the font for the specified state. This should NOT call any 853 * method on the <code>JComponent</code>. 854 * 855 * @param context SynthContext identifying requester 856 * @return Font to render with 857 */ 858 protected abstract Font getFontForState(SynthContext context); 859 860 /** 861 * Returns the Insets that are used to calculate sizing information. 862 * 863 * @param context SynthContext identifying requester 864 * @param insets Insets to place return value in. 865 * @return Sizing Insets. 866 */ 867 public Insets getInsets(SynthContext context, Insets insets) { 868 if (insets == null) { 869 insets = new Insets(0, 0, 0, 0); 870 } 871 insets.top = insets.bottom = insets.left = insets.right = 0; 872 return insets; 873 } 874 875 /** 876 * Returns the <code>SynthPainter</code> that will be used for painting. 877 * This may return null. 878 * 879 * @param context SynthContext identifying requester 880 * @return SynthPainter to use 881 */ 882 public SynthPainter getPainter(SynthContext context) { 883 return null; 884 } 885 886 /** 887 * Returns true if the region is opaque. 888 * 889 * @param context SynthContext identifying requester 890 * @return true if region is opaque. 891 */ 892 public boolean isOpaque(SynthContext context) { 893 return true; 894 } 895 896 /** 903 public Object get(SynthContext context, Object key) { 904 return getDefaultValue(key); 905 } 906 907 void installDefaults(SynthContext context, SynthUI ui) { 908 // Special case the Border as this will likely change when the LAF 909 // can have more control over this. 910 if (!context.isSubregion()) { 911 JComponent c = context.getComponent(); 912 Border border = c.getBorder(); 913 914 if (border == null || border instanceof UIResource) { 915 c.setBorder(new SynthBorder(ui, getInsets(context, null))); 916 } 917 } 918 installDefaults(context); 919 } 920 921 /** 922 * Installs the necessary state from this Style on the 923 * <code>JComponent</code> from <code>context</code>. 924 * 925 * @param context SynthContext identifying component to install properties 926 * to. 927 */ 928 public void installDefaults(SynthContext context) { 929 if (!context.isSubregion()) { 930 JComponent c = context.getComponent(); 931 Region region = context.getRegion(); 932 Font font = c.getFont(); 933 934 if (font == null || (font instanceof UIResource)) { 935 c.setFont(getFontForState(context)); 936 } 937 Color background = c.getBackground(); 938 if (background == null || (background instanceof UIResource)) { 939 c.setBackground(getColorForState(context, 940 ColorType.BACKGROUND)); 941 } 942 Color foreground = c.getForeground(); 943 if (foreground == null || (foreground instanceof UIResource)) { 944 c.setForeground(getColorForState(context, 945 ColorType.FOREGROUND)); 946 } 947 LookAndFeel.installProperty(c, "opaque", Boolean.valueOf(isOpaque(context))); 948 } 949 } 950 951 /** 952 * Uninstalls any state that this style installed on 953 * the <code>JComponent</code> from <code>context</code>. 954 * <p> 955 * Styles should NOT depend upon this being called, in certain cases 956 * it may never be called. 957 * 958 * @param context SynthContext identifying component to install properties 959 * to. 960 */ 961 public void uninstallDefaults(SynthContext context) { 962 if (!context.isSubregion()) { 963 // NOTE: because getForeground, getBackground and getFont will look 964 // at the parent Container, if we set them to null it may 965 // mean we they return a non-null and non-UIResource value 966 // preventing install from correctly settings its colors/font. For 967 // this reason we do not uninstall the fg/bg/font. 968 969 JComponent c = context.getComponent(); 970 Border border = c.getBorder(); 971 972 if (border instanceof UIResource) { 973 c.setBorder(null); 974 } 975 } 976 } 977 978 /** 979 * Convenience method to get a specific style property whose value is 980 * a <code>Number</code>. If the value is a <code>Number</code>, 981 * <code>intValue</code> is returned, otherwise <code>defaultValue</code> 982 * is returned. 983 * 984 * @param context SynthContext identifying requester 985 * @param key Property being requested. 986 * @param defaultValue Value to return if the property has not been 987 * specified, or is not a Number 988 * @return Value of the named property 989 */ 990 public int getInt(SynthContext context, Object key, int defaultValue) { 991 Object value = get(context, key); 992 993 if (value instanceof Number) { 994 return ((Number)value).intValue(); 995 } 996 return defaultValue; 997 } 998 999 /** 1000 * Convenience method to get a specific style property whose value is 1001 * an Boolean. | 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing.plaf.synth; 26 27 import java.awt.*; 28 import javax.swing.*; 29 import javax.swing.border.Border; 30 import javax.swing.plaf.UIResource; 31 import javax.swing.plaf.basic.BasicLookAndFeel; 32 import javax.swing.text.DefaultEditorKit; 33 import java.util.HashMap; 34 import java.util.Map; 35 import javax.swing.text.JTextComponent; 36 import sun.swing.SwingUtilities2; 37 38 /** 39 * {@code SynthStyle} is a set of style properties. 40 * Each {@code SynthUI} references at least one 41 * {@code SynthStyle} that is obtained using a 42 * {@code SynthStyleFactory}. You typically don't need to interact with 43 * this class directly, rather you will load a 44 * <a href="doc-files/synthFileFormat.html">Synth File Format file</a> into 45 * {@code SynthLookAndFeel} that will create a set of SynthStyles. 46 * 47 * @see SynthLookAndFeel 48 * @see SynthStyleFactory 49 * 50 * @since 1.5 51 * @author Scott Violet 52 */ 53 public abstract class SynthStyle { 54 /** 55 * Contains the default values for certain properties. 56 */ 57 private static Map<Object, Object> DEFAULT_VALUES; 58 59 /** 60 * Shared SynthGraphics. 61 */ 62 private static final SynthGraphicsUtils SYNTH_GRAPHICS = 63 new SynthGraphicsUtils(); 64 65 /** 719 if (DEFAULT_VALUES == null) { 720 DEFAULT_VALUES = new HashMap<Object, Object>(); 721 populateDefaultValues(); 722 } 723 Object value = DEFAULT_VALUES.get(key); 724 if (value instanceof UIDefaults.LazyValue) { 725 value = ((UIDefaults.LazyValue)value).createValue(null); 726 DEFAULT_VALUES.put(key, value); 727 } 728 return value; 729 } 730 } 731 732 /** 733 * Constructs a SynthStyle. 734 */ 735 public SynthStyle() { 736 } 737 738 /** 739 * Returns the {@code SynthGraphicUtils} for the specified context. 740 * 741 * @param context SynthContext identifying requester 742 * @return SynthGraphicsUtils 743 */ 744 public SynthGraphicsUtils getGraphicsUtils(SynthContext context) { 745 return SYNTH_GRAPHICS; 746 } 747 748 /** 749 * Returns the color for the specified state. This gives precedence to 750 * foreground and background of the {@code JComponent}. If the 751 * {@code Color} from the {@code JComponent} is not appropriate, 752 * or not used, this will invoke {@code getColorForState}. Subclasses 753 * should generally not have to override this, instead override 754 * {@link #getColorForState}. 755 * 756 * @param context SynthContext identifying requester 757 * @param type Type of color being requested. 758 * @return Color 759 */ 760 public Color getColor(SynthContext context, ColorType type) { 761 JComponent c = context.getComponent(); 762 Region id = context.getRegion(); 763 764 if ((context.getComponentState() & SynthConstants.DISABLED) != 0) { 765 //This component is disabled, so return the disabled color. 766 //In some cases this means ignoring the color specified by the 767 //developer on the component. In other cases it means using a 768 //specified disabledTextColor, such as on JTextComponents. 769 //For example, JLabel doesn't specify a disabled color that the 770 //developer can set, yet it should have a disabled color to the 771 //text when the label is disabled. This code allows for that. 772 if (c instanceof JTextComponent) { 801 // Then use what we've locally defined 802 color = getColorForState(context, type); 803 } 804 805 if (color == null) { 806 // No color, fallback to that of the widget. 807 if (type == ColorType.BACKGROUND || 808 type == ColorType.TEXT_BACKGROUND) { 809 return c.getBackground(); 810 } 811 else if (type == ColorType.FOREGROUND || 812 type == ColorType.TEXT_FOREGROUND) { 813 return c.getForeground(); 814 } 815 } 816 return color; 817 } 818 819 /** 820 * Returns the color for the specified state. This should NOT call any 821 * methods on the {@code JComponent}. 822 * 823 * @param context SynthContext identifying requester 824 * @param type Type of color being requested. 825 * @return Color to render with 826 */ 827 protected abstract Color getColorForState(SynthContext context, 828 ColorType type); 829 830 /** 831 * Returns the Font for the specified state. This redirects to the 832 * {@code JComponent} from the {@code context} as necessary. 833 * If this does not redirect 834 * to the JComponent {@link #getFontForState} is invoked. 835 * 836 * @param context SynthContext identifying requester 837 * @return Font to render with 838 */ 839 public Font getFont(SynthContext context) { 840 JComponent c = context.getComponent(); 841 if (context.getComponentState() == SynthConstants.ENABLED) { 842 return c.getFont(); 843 } 844 Font cFont = c.getFont(); 845 if (cFont != null && !(cFont instanceof UIResource)) { 846 return cFont; 847 } 848 return getFontForState(context); 849 } 850 851 /** 852 * Returns the font for the specified state. This should NOT call any 853 * method on the {@code JComponent}. 854 * 855 * @param context SynthContext identifying requester 856 * @return Font to render with 857 */ 858 protected abstract Font getFontForState(SynthContext context); 859 860 /** 861 * Returns the Insets that are used to calculate sizing information. 862 * 863 * @param context SynthContext identifying requester 864 * @param insets Insets to place return value in. 865 * @return Sizing Insets. 866 */ 867 public Insets getInsets(SynthContext context, Insets insets) { 868 if (insets == null) { 869 insets = new Insets(0, 0, 0, 0); 870 } 871 insets.top = insets.bottom = insets.left = insets.right = 0; 872 return insets; 873 } 874 875 /** 876 * Returns the {@code SynthPainter} that will be used for painting. 877 * This may return null. 878 * 879 * @param context SynthContext identifying requester 880 * @return SynthPainter to use 881 */ 882 public SynthPainter getPainter(SynthContext context) { 883 return null; 884 } 885 886 /** 887 * Returns true if the region is opaque. 888 * 889 * @param context SynthContext identifying requester 890 * @return true if region is opaque. 891 */ 892 public boolean isOpaque(SynthContext context) { 893 return true; 894 } 895 896 /** 903 public Object get(SynthContext context, Object key) { 904 return getDefaultValue(key); 905 } 906 907 void installDefaults(SynthContext context, SynthUI ui) { 908 // Special case the Border as this will likely change when the LAF 909 // can have more control over this. 910 if (!context.isSubregion()) { 911 JComponent c = context.getComponent(); 912 Border border = c.getBorder(); 913 914 if (border == null || border instanceof UIResource) { 915 c.setBorder(new SynthBorder(ui, getInsets(context, null))); 916 } 917 } 918 installDefaults(context); 919 } 920 921 /** 922 * Installs the necessary state from this Style on the 923 * {@code JComponent} from {@code context}. 924 * 925 * @param context SynthContext identifying component to install properties 926 * to. 927 */ 928 public void installDefaults(SynthContext context) { 929 if (!context.isSubregion()) { 930 JComponent c = context.getComponent(); 931 Region region = context.getRegion(); 932 Font font = c.getFont(); 933 934 if (font == null || (font instanceof UIResource)) { 935 c.setFont(getFontForState(context)); 936 } 937 Color background = c.getBackground(); 938 if (background == null || (background instanceof UIResource)) { 939 c.setBackground(getColorForState(context, 940 ColorType.BACKGROUND)); 941 } 942 Color foreground = c.getForeground(); 943 if (foreground == null || (foreground instanceof UIResource)) { 944 c.setForeground(getColorForState(context, 945 ColorType.FOREGROUND)); 946 } 947 LookAndFeel.installProperty(c, "opaque", Boolean.valueOf(isOpaque(context))); 948 } 949 } 950 951 /** 952 * Uninstalls any state that this style installed on 953 * the {@code JComponent} from {@code context}. 954 * <p> 955 * Styles should NOT depend upon this being called, in certain cases 956 * it may never be called. 957 * 958 * @param context SynthContext identifying component to install properties 959 * to. 960 */ 961 public void uninstallDefaults(SynthContext context) { 962 if (!context.isSubregion()) { 963 // NOTE: because getForeground, getBackground and getFont will look 964 // at the parent Container, if we set them to null it may 965 // mean we they return a non-null and non-UIResource value 966 // preventing install from correctly settings its colors/font. For 967 // this reason we do not uninstall the fg/bg/font. 968 969 JComponent c = context.getComponent(); 970 Border border = c.getBorder(); 971 972 if (border instanceof UIResource) { 973 c.setBorder(null); 974 } 975 } 976 } 977 978 /** 979 * Convenience method to get a specific style property whose value is 980 * a {@code Number}. If the value is a {@code Number}, 981 * {@code intValue} is returned, otherwise {@code defaultValue} 982 * is returned. 983 * 984 * @param context SynthContext identifying requester 985 * @param key Property being requested. 986 * @param defaultValue Value to return if the property has not been 987 * specified, or is not a Number 988 * @return Value of the named property 989 */ 990 public int getInt(SynthContext context, Object key, int defaultValue) { 991 Object value = get(context, key); 992 993 if (value instanceof Number) { 994 return ((Number)value).intValue(); 995 } 996 return defaultValue; 997 } 998 999 /** 1000 * Convenience method to get a specific style property whose value is 1001 * an Boolean. |