| /* |
| * 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; } |
| } |