/* * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package build.tools.generatenimbus; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlElements; class UIStyle { public static enum CacheMode { NO_CACHING, FIXED_SIZES, NINE_SQUARE_SCALE } @XmlElement private UIColor textForeground = null; @XmlElement(name="inherit-textForeground") private boolean textForegroundInherited = true; @XmlElement private UIColor textBackground = null; @XmlElement(name="inherit-textBackground") private boolean textBackgroundInherited = true; @XmlElement private UIColor background = null; @XmlElement(name="inherit-background") private boolean backgroundInherited = true; @XmlElement private boolean cacheSettingsInherited = true; @XmlElement CacheMode cacheMode = CacheMode.FIXED_SIZES; @XmlElement String maxHozCachedImgScaling = "1.0"; @XmlElement String maxVertCachedImgScaling = "1.0"; @XmlElement(name="uiProperty") @XmlElementWrapper(name="uiproperties") private List<UIProperty> uiProperties = new ArrayList<UIProperty>(); private UIStyle parentStyle = null; public void setParentStyle(UIStyle parentStyle) { this.parentStyle = parentStyle; } public CacheMode getCacheMode() { if (cacheSettingsInherited) { return (parentStyle == null ? CacheMode.FIXED_SIZES : parentStyle.getCacheMode()); } else { return cacheMode; } } public String getMaxHozCachedImgScaling() { if (cacheSettingsInherited) { return (parentStyle == null ? "1.0" : parentStyle.getMaxHozCachedImgScaling()); } else { return maxHozCachedImgScaling; } } public String getMaxVertCachedImgScaling() { if (cacheSettingsInherited) { return (parentStyle == null ? "1.0" : parentStyle.getMaxVertCachedImgScaling()); } else { return maxVertCachedImgScaling; } } public String write(String prefix) { StringBuilder sb = new StringBuilder(); if (! textForegroundInherited) { sb.append(String.format(" addColor(d, \"%s%s\", %s);\n", prefix, "textForeground", textForeground.getValue().write())); } if (! textBackgroundInherited) { sb.append(String.format(" addColor(d, \"%s%s\", %s);\n", prefix, "textBackground", textBackground.getValue().write())); } if (! backgroundInherited) { sb.append(String.format(" addColor(d, \"%s%s\", %s);\n", prefix, "background", background.getValue().write())); } for (UIProperty property : uiProperties) { sb.append(property.write(prefix)); } return sb.toString(); } } class UIRegion { @XmlAttribute protected String name; @XmlAttribute protected String key; @XmlAttribute private boolean opaque = false; @XmlElement private Insets contentMargins = new Insets(0, 0, 0, 0); @XmlElement(name="state") @XmlElementWrapper(name="backgroundStates") protected List<UIState> backgroundStates = new ArrayList<UIState>(); public List<UIState> getBackgroundStates() { return backgroundStates; } @XmlElement(name="state") @XmlElementWrapper(name="foregroundStates") protected List<UIState> foregroundStates = new ArrayList<UIState>(); public List<UIState> getForegroundStates() { return foregroundStates; } @XmlElement(name="state") @XmlElementWrapper(name="borderStates") protected List<UIState> borderStates = new ArrayList<UIState>(); public List<UIState> getBorderStates() { return borderStates; } @XmlElement private UIStyle style = new UIStyle(); @XmlElements({ @XmlElement(name = "region", type = UIRegion.class), @XmlElement(name = "uiComponent", type = UIComponent.class), @XmlElement(name = "uiIconRegion", type = UIIconRegion.class) }) @XmlElementWrapper(name="regions") private List<UIRegion> subRegions = new ArrayList<UIRegion>(); public List<UIRegion> getSubRegions() { return subRegions; } protected void initStyles(UIStyle parentStyle) { style.setParentStyle(parentStyle); for (UIState state: backgroundStates) { state.getStyle().setParentStyle(this.style); } for (UIState state: foregroundStates) { state.getStyle().setParentStyle(this.style); } for (UIState state: borderStates) { state.getStyle().setParentStyle(this.style); } for (UIRegion region: subRegions) { region.initStyles(this.style); } } public String getKey() { return key == null || "".equals(key) ? name : key; } private boolean hasCanvas() { for (UIState s : backgroundStates) { if (s.hasCanvas()) return true; } for (UIState s : borderStates) { if (s.hasCanvas()) return true; } for (UIState s : foregroundStates) { if (s.hasCanvas()) return true; } for (UIRegion r: subRegions) { if (r.hasCanvas()) return true; } return false; } public void write(StringBuilder sb, StringBuilder styleBuffer, UIComponent comp, String prefix, String pkg) { // write content margins sb.append(String.format(" d.put(\"%s.contentMargins\", %s);\n", prefix, contentMargins.write(true))); // write opaque if true if (opaque) { sb.append(String.format(" d.put(\"%s.opaque\", Boolean.TRUE);\n", prefix)); } // register component with LAF String regionCode = "Region." + Utils.regionNameToCaps(name); styleBuffer.append(String.format(" register(%s, \"%s\");\n", regionCode, prefix)); //write the State, if necessary StringBuffer regString = new StringBuffer(); List<UIStateType> types = comp.getStateTypes(); if (types != null && types.size() > 0) { for (UIStateType type : types) { regString.append(type.getKey()); regString.append(","); } //remove the last "," regString.deleteCharAt(regString.length() - 1); } if (! regString.equals("Enabled,MouseOver,Pressed,Disabled,Focused,Selected,Default") && types.size() > 0) { //there were either custom states, or the normal states were in a custom order //so go ahead and write out prefix.State sb.append(String.format(" d.put(\"%s.States\", \"%s\");\n", prefix, regString)); } // write out any custom states, if necessary for (UIStateType type : types) { String synthState = type.getKey(); if (! "Enabled".equals(synthState) && ! "MouseOver".equals(synthState) && ! "Pressed".equals(synthState) && ! "Disabled".equals(synthState) && ! "Focused".equals(synthState) && ! "Selected".equals(synthState) && ! "Default".equals(synthState)) { //what we have here, gentlemen, is a bona-fide custom state. //if the type is not one of the standard types, then construct a name for //the new type, and write out a new subclass of State. String className = Utils.normalize(prefix) + synthState + "State"; sb.append(String.format(" d.put(\"%s.%s\", new %s());\n", prefix, synthState, className)); String body = type.getCodeSnippet(); Map<String, String> variables = Generator.getVariables(); variables.put("STATE_NAME", className); variables.put("STATE_KEY", synthState); variables.put("BODY", body); Generator.writeSrcFile("StateImpl", variables, className); } } // write style sb.append(style.write(prefix + '.')); String fileName = Utils.normalize(prefix) + "Painter"; boolean hasCanvas = hasCanvas(); if (hasCanvas) { PainterGenerator.writePainter(this, fileName); } // write states ui defaults for (UIState state : backgroundStates) { state.write(sb, prefix, pkg, fileName, "background"); } for (UIState state : foregroundStates) { state.write(sb, prefix, pkg, fileName, "foreground"); } for (UIState state : borderStates) { state.write(sb, prefix, pkg, fileName, "border"); } // handle sub regions for (UIRegion subreg : subRegions) { String p = prefix; if (! (subreg instanceof UIIconRegion)) { p = prefix + ":" + Utils.escape(subreg.getKey()); } UIComponent c = comp; if (subreg instanceof UIComponent) { c = (UIComponent) subreg; } subreg.write(sb, styleBuffer, c, p, pkg); } } } class UIIconRegion extends UIRegion { @XmlAttribute private String basicKey; @Override public void write(StringBuilder sb, StringBuilder styleBuffer, UIComponent comp, String prefix, String pkg) { Dimension size = null; String fileNamePrefix = Utils.normalize(prefix) + "Painter"; // write states ui defaults for (UIState state : backgroundStates) { Canvas canvas = state.getCanvas(); if (!canvas.isBlank()) { state.write(sb, prefix, pkg, fileNamePrefix, getKey()); size = canvas.getSize(); } } if (size != null) { // Put SynthIconImpl wrapper in UiDefaults String k = (basicKey == null ? prefix + "." + getKey() : basicKey); sb.append(String.format( " d.put(\"%s\", new NimbusIcon(\"%s\", \"%sPainter\", %d, %d));\n", k, prefix, getKey(), size.width, size.height)); } } } class UIComponent extends UIRegion { @XmlAttribute private String componentName; @XmlElement(name="stateType") @XmlElementWrapper(name="stateTypes") private List<UIStateType> stateTypes = new ArrayList<UIStateType>(); public List<UIStateType> getStateTypes() { return stateTypes; } @Override public String getKey() { if (key == null || "".equals(key)) { if (componentName == null || "".equals(componentName)) { return name; } else { return "\"" + componentName + "\""; } } else { return key; } } } class UIState { @XmlAttribute private String stateKeys; public String getStateKeys() { return stateKeys; } /** Indicates whether to invert the meaning of the 9-square stretching insets */ @XmlAttribute private boolean inverted; /** A cached string representing the list of stateKeys deliminated with "+" */ private String cachedName = null; @XmlElement private Canvas canvas; public Canvas getCanvas() { return canvas; } @XmlElement private UIStyle style; public UIStyle getStyle() { return style; } public boolean hasCanvas() { return ! canvas.isBlank(); } public static List<String> stringToKeys(String keysString) { return Arrays.asList(keysString.split("\\+")); } public String getName() { if (cachedName == null) { StringBuilder buf = new StringBuilder(); List<String> keys = stringToKeys(stateKeys); Collections.sort(keys); for (Iterator<String> iter = keys.iterator(); iter.hasNext();) { buf.append(iter.next()); if (iter.hasNext()) { buf.append('+'); } } cachedName = buf.toString(); } return cachedName; } public void write(StringBuilder sb, String prefix, String pkg, String fileNamePrefix, String painterPrefix) { String statePrefix = prefix + "[" + getName() + "]"; // write state style sb.append(style.write(statePrefix + '.')); // write painter if (hasCanvas()) { writeLazyPainter(sb, statePrefix, pkg, fileNamePrefix, painterPrefix); } } private void writeLazyPainter(StringBuilder sb, String statePrefix, String packageNamePrefix, String fileNamePrefix, String painterPrefix) { String cacheModeString = "AbstractRegionPainter.PaintContext.CacheMode." + style.getCacheMode(); String stateConstant = Utils.statesToConstantName(painterPrefix + "_" + stateKeys); sb.append(String.format( " d.put(\"%s.%sPainter\", new LazyPainter(\"%s.%s\", %s.%s, %s, %s, %b, %s, %s, %s));\n", statePrefix, painterPrefix, packageNamePrefix, fileNamePrefix, fileNamePrefix, stateConstant, canvas.getStretchingInsets().write(false), canvas.getSize().write(false), inverted, cacheModeString, Utils.formatDouble(style.getMaxHozCachedImgScaling()), Utils.formatDouble(style.getMaxVertCachedImgScaling()))); } } class UIStateType { @XmlAttribute private String key; public String getKey() { return key; } @XmlElement private String codeSnippet; public String getCodeSnippet() { return codeSnippet; } }