diff options
author | Johannes Dahlström <johannesd@vaadin.com> | 2015-04-24 15:54:23 +0300 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2015-05-06 10:02:54 +0000 |
commit | 49ded4acd2682cc7dc888fb5d57b8afe47dc30d5 (patch) | |
tree | 1c92fe96e8064a7f57cd91206eec7a9be4b71315 /server/src | |
parent | 0fcac7054158ec6dbd8e8707854ee2700be72439 (diff) | |
download | vaadin-framework-49ded4acd2682cc7dc888fb5d57b8afe47dc30d5.tar.gz vaadin-framework-49ded4acd2682cc7dc888fb5d57b8afe47dc30d5.zip |
Fix for declarative FontIcon support (#17275)
Change-Id: I5d61ed7003811f95bba4ded71937bb08742936c5
Diffstat (limited to 'server/src')
5 files changed, 334 insertions, 31 deletions
diff --git a/server/src/com/vaadin/server/FontAwesome.java b/server/src/com/vaadin/server/FontAwesome.java index f226e0c320..4c60b90233 100644 --- a/server/src/com/vaadin/server/FontAwesome.java +++ b/server/src/com/vaadin/server/FontAwesome.java @@ -538,7 +538,7 @@ public enum FontAwesome implements FontIcon { YOUTUBE_PLAY(0XF16A), // YOUTUBE_SQUARE(0XF166); - private static final String fontFamily = "FontAwesome"; + public static final String FONT_FAMILY = "FontAwesome"; private int codepoint; FontAwesome(int codepoint) { @@ -563,7 +563,7 @@ public enum FontAwesome implements FontIcon { */ @Override public String getFontFamily() { - return fontFamily; + return FontAwesome.FONT_FAMILY; } /* @@ -578,8 +578,25 @@ public enum FontAwesome implements FontIcon { @Override public String getHtml() { - return "<span class=\"v-icon\" style=\"font-family: " + fontFamily - + ";\">&#x" + Integer.toHexString(codepoint) + ";</span>"; + return GenericFontIcon.getHtml(FontAwesome.FONT_FAMILY, codepoint); + } + + /** + * Finds an instance of FontAwesome with given codepoint + * + * @since 7.5 + * @param codepoint + * @return FontAwesome instance with a specific codepoint or null if there + * isn't any + */ + public static FontAwesome fromCodepoint(final int codepoint) { + for (FontAwesome f : values()) { + if (f.getCodepoint() == codepoint) { + return f; + } + } + throw new IllegalArgumentException("Codepoint " + codepoint + + " not found in FontAwesome"); } } diff --git a/server/src/com/vaadin/server/GenericFontIcon.java b/server/src/com/vaadin/server/GenericFontIcon.java new file mode 100644 index 0000000000..ba61390fb0 --- /dev/null +++ b/server/src/com/vaadin/server/GenericFontIcon.java @@ -0,0 +1,144 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed 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 com.vaadin.server; + +/** + * A generic implementation of {@link FontIcon} interface + * + * @since + * @author Vaadin Ltd + */ +@SuppressWarnings("serial") +public class GenericFontIcon implements FontIcon { + private final String fontFamily; + private final int codePoint; + + /** + * Creates a new instance of GenericFontIcon with given font family and + * codepoint + * + * @param fontFamily + * Name of the type face that is used to display icons + * @param codepoint + * Numerical code point in the font + */ + public GenericFontIcon(String fontFamily, int codepoint) { + this.fontFamily = fontFamily; + codePoint = codepoint; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.server.FontIcon#getFontFamily() + */ + @Override + public String getFontFamily() { + return fontFamily; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.server.Resource#getMIMEType() + */ + @Override + public String getMIMEType() { + throw new UnsupportedOperationException(FontIcon.class.getSimpleName() + + " should not be used where a MIME type is needed."); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.server.FontIcon#getCodepoint() + */ + @Override + public int getCodepoint() { + return codePoint; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.server.FontIcon#getHtml() + */ + @Override + public String getHtml() { + return getHtml(fontFamily, codePoint); + } + + /** + * Utility method for generating HTML that displays an icon from specific + * fontFamiliy with a given codePoint in the font + * + * @since 7.5 + * @param fontFamily + * Name of the font family + * @param codePoint + * Icon's character code point in the font + * @return + */ + public static String getHtml(String fontFamily, int codePoint) { + return "<span class=\"v-icon\" style=\"font-family: " + fontFamily + + ";\">&#x" + Integer.toHexString(codePoint) + ";</span>"; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + codePoint; + result = prime * result + + ((fontFamily == null) ? 0 : fontFamily.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof GenericFontIcon)) { + return false; + } + GenericFontIcon other = (GenericFontIcon) obj; + if (codePoint != other.codePoint) { + return false; + } + if (fontFamily == null) { + if (other.fontFamily != null) { + return false; + } + } else if (!fontFamily.equals(other.fontFamily)) { + return false; + } + return true; + } +}
\ No newline at end of file diff --git a/server/src/com/vaadin/server/ResourceReference.java b/server/src/com/vaadin/server/ResourceReference.java index 31dfa41ef9..aeb06394b7 100644 --- a/server/src/com/vaadin/server/ResourceReference.java +++ b/server/src/com/vaadin/server/ResourceReference.java @@ -64,7 +64,7 @@ public class ResourceReference extends URLReference { String uri = getConnectorResourceBase(prefix, connector); return uri; } else if (resource instanceof ThemeResource) { - final String uri = "theme://" + final String uri = ApplicationConstants.THEME_PROTOCOL_PREFIX + ((ThemeResource) resource).getResourceId(); return uri; } else if (resource instanceof FontIcon) { diff --git a/server/src/com/vaadin/ui/declarative/DesignFormatter.java b/server/src/com/vaadin/ui/declarative/DesignFormatter.java index 728b3d1077..b1d2520631 100644 --- a/server/src/com/vaadin/ui/declarative/DesignFormatter.java +++ b/server/src/com/vaadin/ui/declarative/DesignFormatter.java @@ -325,9 +325,8 @@ public class DesignFormatter implements Serializable { // component. return (Converter<String, T>) stringObjectConverter; } - if (sourceType.isEnum()) { - return (Converter<String, T>) stringEnumConverter; - } else if (converterMap.containsKey(sourceType)) { + + if (converterMap.containsKey(sourceType)) { return ((Converter<String, T>) converterMap.get(sourceType)); } else if (!strict) { for (Class<?> supported : converterMap.keySet()) { @@ -336,6 +335,10 @@ public class DesignFormatter implements Serializable { } } } + + if (sourceType.isEnum()) { + return (Converter<String, T>) stringEnumConverter; + } return null; } diff --git a/server/src/com/vaadin/ui/declarative/converters/DesignResourceConverter.java b/server/src/com/vaadin/ui/declarative/converters/DesignResourceConverter.java index 21f20e6403..ff73b61eb2 100644 --- a/server/src/com/vaadin/ui/declarative/converters/DesignResourceConverter.java +++ b/server/src/com/vaadin/ui/declarative/converters/DesignResourceConverter.java @@ -16,14 +16,20 @@ package com.vaadin.ui.declarative.converters; import java.io.File; +import java.io.Serializable; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import com.vaadin.data.util.converter.Converter; import com.vaadin.server.ExternalResource; import com.vaadin.server.FileResource; import com.vaadin.server.FontAwesome; +import com.vaadin.server.FontIcon; +import com.vaadin.server.GenericFontIcon; import com.vaadin.server.Resource; import com.vaadin.server.ThemeResource; +import com.vaadin.shared.ApplicationConstants; import com.vaadin.ui.declarative.DesignAttributeHandler; /** @@ -33,21 +39,28 @@ import com.vaadin.ui.declarative.DesignAttributeHandler; * @since 7.4 * @author Vaadin Ltd */ +@SuppressWarnings("serial") public class DesignResourceConverter implements Converter<String, Resource> { @Override public Resource convertToModel(String value, Class<? extends Resource> targetType, Locale locale) throws Converter.ConversionException { - if (value.startsWith("http://") || value.startsWith("https://") - || value.startsWith("ftp://") || value.startsWith("ftps://")) { - return new ExternalResource(value); - } else if (value.startsWith("theme://")) { - return new ThemeResource(value.substring(8)); - } else if (value.startsWith("font://")) { - return FontAwesome.valueOf(value.substring(7)); - } else { - return new FileResource(new File(value)); + if (!value.contains("://")) { + // assume it'is "file://" protocol, one that is used to access a + // file on a given path on the server, this will later be striped + // out anyway + value = "file://" + value; + } + + String protocol = value.split("://")[0]; + try { + ResourceConverterByProtocol converter = ResourceConverterByProtocol + .valueOf(protocol.toUpperCase(Locale.ENGLISH)); + return converter.parse(value); + } catch (IllegalArgumentException iae) { + throw new ConversionException("Unrecognized protocol: " + protocol, + iae); } } @@ -55,20 +68,10 @@ public class DesignResourceConverter implements Converter<String, Resource> { public String convertToPresentation(Resource value, Class<? extends String> targetType, Locale locale) throws Converter.ConversionException { - if (value instanceof ExternalResource) { - return ((ExternalResource) value).getURL(); - } else if (value instanceof ThemeResource) { - return "theme://" + ((ThemeResource) value).getResourceId(); - } else if (value instanceof FontAwesome) { - return "font://" + ((FontAwesome) value).name(); - } else if (value instanceof FileResource) { - String path = ((FileResource) value).getSourceFile().getPath(); - if (File.separatorChar != '/') { - // make sure we use '/' as file separator in templates - return path.replace(File.separatorChar, '/'); - } else { - return path; - } + ResourceConverterByProtocol byType = ResourceConverterByProtocol + .byType(value.getClass()); + if (byType != null) { + return byType.format(value); } else { throw new Converter.ConversionException("unknown Resource type - " + value.getClass().getName()); @@ -85,4 +88,140 @@ public class DesignResourceConverter implements Converter<String, Resource> { return String.class; } + private static interface ProtocolResourceConverter extends Serializable { + public String format(Resource value); + + public Resource parse(String value); + } + + private static enum ResourceConverterByProtocol implements + ProtocolResourceConverter { + + HTTP, HTTPS, FTP, FTPS, THEME { + + @Override + public Resource parse(String value) { + // strip "theme://" from the url, use the rest as the resource + // id + return new ThemeResource(value.substring(8)); + } + + @Override + public String format(Resource value) + throws Converter.ConversionException { + return ApplicationConstants.THEME_PROTOCOL_PREFIX + + ((ThemeResource) value).getResourceId(); + } + }, + FONTICON { + @Override + public Resource parse(String value) { + final String address = (value.split("://", 2))[1]; + final String[] familyAndCode = address.split("/", 2); + final int codepoint = Integer.valueOf( + familyAndCode[1].substring(2), 16); + + if (FontAwesome.FONT_FAMILY.equals(familyAndCode[0])) { + try { + return FontAwesome.fromCodepoint(codepoint); + } catch (IllegalArgumentException iae) { + throw new ConversionException( + "Unknown codepoint in FontAwesome: " + + codepoint, iae); + } + } + + FontIcon generic = new GenericFontIcon(familyAndCode[0], + codepoint); + return generic; + + } + + @Override + public String format(Resource value) + throws Converter.ConversionException { + FontIcon icon = (FontIcon) value; + return ApplicationConstants.FONTICON_PROTOCOL_PREFIX + + icon.getFontFamily() + "/0x" + + Integer.toHexString(icon.getCodepoint()); + } + }, + @Deprecated + FONT { + @Override + public Resource parse(String value) { + // Deprecated, 7.4 syntax is + // font://"+FontAwesome.valueOf(foo) eg. "font://AMBULANCE" + final String iconName = (value.split("://", 2))[1]; + + try { + return FontAwesome.valueOf(iconName); + } catch (IllegalArgumentException iae) { + throw new ConversionException("Unknown FontIcon constant: " + + iconName, iae); + } + } + + @Override + public String format(Resource value) + throws Converter.ConversionException { + throw new UnsupportedOperationException("Use " + + ResourceConverterByProtocol.FONTICON.toString() + + " instead"); + } + }, + FILE { + @Override + public Resource parse(String value) { + return new FileResource(new File(value.split("://")[1])); + } + + @Override + public String format(Resource value) + throws Converter.ConversionException { + String path = ((FileResource) value).getSourceFile().getPath(); + if (File.separatorChar != '/') { + // make sure we use '/' as file separator in templates + return path.replace(File.separatorChar, '/'); + } else { + return path; + } + } + + }; + + @Override + public Resource parse(String value) { + // default behavior for HTTP, HTTPS, FTP and FTPS + return new ExternalResource(value); + } + + @Override + public String format(Resource value) + throws Converter.ConversionException { + // default behavior for HTTP, HTTPS, FTP and FTPS + return ((ExternalResource) value).getURL(); + } + + private static Map<Class<? extends Resource>, ResourceConverterByProtocol> typeToConverter = new HashMap<Class<? extends Resource>, ResourceConverterByProtocol>(); + static { + typeToConverter.put(ExternalResource.class, HTTP); + // ^ any of non-specialized would actually work + typeToConverter.put(ThemeResource.class, THEME); + typeToConverter.put(FontIcon.class, FONTICON); + typeToConverter.put(FileResource.class, FILE); + + } + + public static ResourceConverterByProtocol byType( + Class<? extends Resource> resourceType) { + for (Class<?> type : typeToConverter.keySet()) { + if (type.isAssignableFrom(resourceType)) { + return typeToConverter.get(type); + } + } + return null; + } + } + } |