@@ -26,6 +26,9 @@ import java.util.StringTokenizer; | |||
import java.util.regex.Matcher; | |||
import java.util.regex.Pattern; | |||
import org.jsoup.nodes.Attributes; | |||
import org.jsoup.nodes.Node; | |||
import com.vaadin.event.ActionManager; | |||
import com.vaadin.event.ConnectorActionManager; | |||
import com.vaadin.event.ShortcutListener; | |||
@@ -39,6 +42,8 @@ import com.vaadin.shared.ComponentConstants; | |||
import com.vaadin.shared.ui.ComponentStateUtil; | |||
import com.vaadin.shared.util.SharedUtil; | |||
import com.vaadin.ui.Field.ValueChangeEvent; | |||
import com.vaadin.ui.declarative.DesignAttributeHandler; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.util.ReflectTools; | |||
/** | |||
@@ -52,7 +57,7 @@ import com.vaadin.util.ReflectTools; | |||
*/ | |||
@SuppressWarnings("serial") | |||
public abstract class AbstractComponent extends AbstractClientConnector | |||
implements Component { | |||
implements Component, DesignSynchronizable { | |||
/* Private members */ | |||
@@ -896,6 +901,65 @@ public abstract class AbstractComponent extends AbstractClientConnector | |||
} | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see | |||
* com.vaadin.ui.DesignSynchronizable#synchronizeFromDesign(org.jsoup.nodes | |||
* .Node, com.vaadin.ui.declarative.DesignContext) | |||
*/ | |||
@Override | |||
public void synchronizeFromDesign(Node design, DesignContext designContext) { | |||
Attributes attr = design.attributes(); | |||
DesignSynchronizable def = designContext.getDefaultInstance(this | |||
.getClass()); | |||
// handle default attributes | |||
for (String property : getDefaultAttributes()) { | |||
String value = null; | |||
if (attr.hasKey(property)) { | |||
value = attr.get(property); | |||
} | |||
DesignAttributeHandler.assignAttribute(this, property, value, def); | |||
} | |||
// handle width and height | |||
DesignAttributeHandler.assignWidth(this, attr, def); | |||
DesignAttributeHandler.assignHeight(this, attr, def); | |||
} | |||
/** | |||
* Returns the list of attributes that do not require custom handling when | |||
* synchronizing from design. These are typically attributes of some | |||
* primitive type. The default implementation searches setters with | |||
* primitive values | |||
* | |||
* @since 7.4 | |||
* @return the list of attributes that can be synchronized from design using | |||
* the default approach. | |||
*/ | |||
protected List<String> getDefaultAttributes() { | |||
List<String> attributes = DesignAttributeHandler | |||
.findSupportedAttributes(this.getClass()); | |||
// we want to handle width and height in a custom way | |||
attributes.remove("width"); | |||
attributes.remove("height"); | |||
attributes.remove("debug-id"); | |||
return attributes; | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see | |||
* com.vaadin.ui.DesignSynchronizable#synchronizeToDesign(org.jsoup.nodes | |||
* .Node, com.vaadin.ui.declarative.DesignContext) | |||
*/ | |||
@Override | |||
public void synchronizeToDesign(Node design, DesignContext designContext) { | |||
AbstractComponent def = designContext.getDefaultInstance(this | |||
.getClass()); | |||
} | |||
/* | |||
* Returns array with size in index 0 unit in index 1. Null or empty string | |||
* will produce {-1,Unit#PIXELS} |
@@ -0,0 +1,63 @@ | |||
/* | |||
* 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.ui; | |||
import org.jsoup.nodes.Node; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
/** | |||
* Interface to be implemented by all the components that can be read from or | |||
* written to HTML design representation. TODO: add reference to VisualDesigner | |||
* | |||
* @since 7.4 | |||
* | |||
* @author Vaadin Ltd | |||
*/ | |||
public interface DesignSynchronizable extends Component { | |||
/** | |||
* Update the component state based on the given design. The component is | |||
* responsible not only for updating itself but also ensuring that its | |||
* children update their state based on the design. | |||
* <p> | |||
* This method must not modify the design. | |||
* | |||
* @since 7.4 | |||
* @param design | |||
* The design as HTML to obtain the state from | |||
* @param designContext | |||
* The DesignContext instance used for parsing the design | |||
*/ | |||
public void synchronizeFromDesign(Node design, DesignContext designContext); | |||
/** | |||
* Update the given design based on the component state. The component is | |||
* responsible not only for updating itself but also for ensuring its | |||
* children update themselves in the correct position in the design. The | |||
* caller of this method should not assume that contents of the | |||
* <code>design</code> parameter are presented. | |||
* <p> | |||
* This method must not modify the component state. | |||
* | |||
* @since 7.4 | |||
* @param design | |||
* The design as HTML to update with the current state | |||
* @param designContext | |||
*/ | |||
public void synchronizeToDesign(Node design, DesignContext designContext); | |||
} |
@@ -0,0 +1,373 @@ | |||
/* | |||
* 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.ui.declarative; | |||
import java.io.File; | |||
import java.lang.reflect.Method; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.Locale; | |||
import java.util.logging.Level; | |||
import java.util.logging.Logger; | |||
import org.jsoup.nodes.Attributes; | |||
import com.vaadin.server.ExternalResource; | |||
import com.vaadin.server.FileResource; | |||
import com.vaadin.server.FontAwesome; | |||
import com.vaadin.server.Resource; | |||
import com.vaadin.server.ThemeResource; | |||
import com.vaadin.ui.DesignSynchronizable; | |||
/** | |||
* Default attribute handler implementation used when parsing designs to | |||
* component trees. Handles all the component attributes that do require custom | |||
* handling. | |||
* | |||
* @since 7.4 | |||
* @author Vaadin Ltd | |||
*/ | |||
public class DesignAttributeHandler { | |||
protected static Logger getLogger() { | |||
return Logger.getLogger(DesignAttributeHandler.class.getName()); | |||
} | |||
/** | |||
* Returns the design attribute name corresponding the given method name. | |||
* For example given a method name <code>setPrimaryStyleName</code> the | |||
* return value would be <code>primary-style-name</code> | |||
* | |||
* @since 7.4 | |||
* @param methodName | |||
* the method name | |||
* @return the design attribute name corresponding the given method name | |||
*/ | |||
private static String toAttributeName(String methodName) { | |||
String[] words = methodName.split("(?<!^)(?=[A-Z])"); | |||
StringBuilder builder = new StringBuilder(); | |||
// ignore first toget ("set") | |||
for (int i = 1; i < words.length; i++) { | |||
if (builder.length() > 0) { | |||
builder.append("-"); | |||
} | |||
builder.append(words[i].toLowerCase()); | |||
} | |||
return builder.toString(); | |||
} | |||
/** | |||
* Returns the setter method name corresponding the given design attribute | |||
* name. For example given a attribute name <code>primary-style-name</code> | |||
* the return value would be <code>setPrimaryStyleName</code>. | |||
* | |||
* @since 7.4 | |||
* @param designAttributeName | |||
* the design attribute name | |||
* @return the setter method name corresponding the given design attribute | |||
* name | |||
*/ | |||
private static String toSetterName(String designAttributeName) { | |||
String[] parts = designAttributeName.split("-"); | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append("set"); | |||
for (String part : parts) { | |||
builder.append(part.substring(0, 1).toUpperCase()); | |||
builder.append(part.substring(1)); | |||
} | |||
return builder.toString(); | |||
} | |||
/** | |||
* Parses the given attribute value to specified target type | |||
* | |||
* @since 7.4 | |||
* @param targetType | |||
* the target type for the value | |||
* @param value | |||
* the parsed value | |||
* @return the object of specified target type | |||
*/ | |||
private static Object parseAttributeValue(Class<?> targetType, String value) { | |||
if (targetType == String.class) { | |||
return value; | |||
} | |||
// special handling for boolean type. The attribute evaluates to true if | |||
// it is present and the value is not "false" or "FALSE". Thus empty | |||
// value evaluates to true. | |||
if (targetType == Boolean.TYPE || targetType == Boolean.class) { | |||
return value == null || !value.equalsIgnoreCase("false"); | |||
} | |||
if (targetType == Integer.TYPE || targetType == Integer.class) { | |||
return Integer.valueOf(value); | |||
} | |||
if (targetType == Byte.TYPE || targetType == Byte.class) { | |||
return Byte.valueOf(value); | |||
} | |||
if (targetType == Short.TYPE || targetType == Short.class) { | |||
return Short.valueOf(value); | |||
} | |||
if (targetType == Long.TYPE || targetType == Long.class) { | |||
return Long.valueOf(value); | |||
} | |||
if (targetType == Character.TYPE || targetType == Character.class) { | |||
return value.charAt(0); | |||
} | |||
if (targetType == Float.TYPE || targetType == Float.class) { | |||
return Float.valueOf(value); | |||
} | |||
if (targetType == Double.TYPE || targetType == Double.class) { | |||
return Double.valueOf(value); | |||
} | |||
if (targetType == Locale.class) { | |||
return new Locale(value); | |||
} | |||
if (targetType == Resource.class) { | |||
return parseResource(value); | |||
} | |||
return null; | |||
} | |||
private static Resource parseResource(String value) { | |||
if (value.startsWith("http://")) { | |||
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)); | |||
} | |||
} | |||
/** | |||
* Finds a corresponding getter method for the given setter method | |||
* | |||
* @since 7.4 | |||
* @param clazz | |||
* the class to search methods from | |||
* @param setter | |||
* the setter that is used to find the matching getter | |||
* @return the matching getter or null if not found | |||
*/ | |||
private static Method findGetter(Class<?> clazz, Method setter) { | |||
String propertyName = setter.getName().substring(3); | |||
Class<?> returnType = setter.getParameterTypes()[0]; | |||
for (Method method : clazz.getMethods()) { | |||
if (isGetterForProperty(method, propertyName) | |||
&& method.getParameterTypes().length == 0 | |||
&& method.getReturnType().equals(returnType)) { | |||
return method; | |||
} | |||
} | |||
getLogger().warning("Could not find getter for " + setter.getName()); | |||
return null; | |||
} | |||
private static boolean isGetterForProperty(Method method, String property) { | |||
String methodName = method.getName(); | |||
return methodName.equals("get" + property) | |||
|| methodName.equals("is" + property) | |||
|| methodName.equals("has" + property); | |||
} | |||
/** | |||
* Returns a setter that can be used for assigning the given design | |||
* attribute to the class | |||
* | |||
* @since 7.4 | |||
* @param clazz | |||
* the class that is scanned for setters | |||
* @param attribute | |||
* the design attribute to find setter for | |||
* @return the setter method or null if not found | |||
*/ | |||
private static Method findSetterForAttribute(Class<?> clazz, | |||
String attribute) { | |||
String methodName = toSetterName(attribute); | |||
for (Method method : clazz.getMethods()) { | |||
if (method.getName().equals(methodName) | |||
&& method.getParameterTypes().length == 1 | |||
&& isSupported(method.getParameterTypes()[0])) { | |||
return method; | |||
} | |||
} | |||
getLogger().warning( | |||
"Could not find setter with supported type for property " | |||
+ attribute); | |||
return null; | |||
} | |||
private static final List<Class<?>> supportedClasses = Arrays | |||
.asList(new Class<?>[] { String.class, Boolean.class, | |||
Integer.class, Byte.class, Short.class, Long.class, | |||
Character.class, Float.class, Double.class, Locale.class, | |||
Resource.class }); | |||
/** | |||
* Returns true if the specified value type is supported by this class. | |||
* Currently the handler supports primitives, {@link Locale.class} and | |||
* {@link Resource.class}. | |||
* | |||
* @since 7.4 | |||
* @param valueType | |||
* the value type to be tested | |||
* @return true if the value type is supported, otherwise false | |||
*/ | |||
private static boolean isSupported(Class<?> valueType) { | |||
return valueType != null | |||
&& (valueType.isPrimitive() || supportedClasses | |||
.contains(valueType)); | |||
} | |||
/** | |||
* Searches for supported setter types from the specified class and returns | |||
* the list of corresponding design attributes | |||
* | |||
* @since 7.4 | |||
* @param clazz | |||
* the class scanned for setters | |||
* @return the list of supported design attributes | |||
*/ | |||
public static List<String> findSupportedAttributes(Class<?> clazz) { | |||
List<String> attributes = new ArrayList<String>(); | |||
// TODO: should we check that we have the corresponding getter too? | |||
// Otherwise we can not revert to default value. On the other hand, do | |||
// we want that leaving the getter out will prevent reading the | |||
// attribute from the design? | |||
for (Method method : clazz.getMethods()) { | |||
if (method.getName().startsWith("set") | |||
&& method.getParameterTypes().length == 1 | |||
&& isSupported(method.getParameterTypes()[0])) { | |||
attributes.add(toAttributeName(method.getName())); | |||
} | |||
} | |||
return attributes; | |||
} | |||
/** | |||
* Assigns the specified design attribute to the given component. If the | |||
* attribute is not present, (value is null) the corresponding property is | |||
* got from the <code>defaultInstance</code> | |||
* | |||
* @since 7.4 | |||
* @param component | |||
* the component to which the attribute should be set | |||
* @param attribute | |||
* the attribute to be set | |||
* @param value | |||
* the value for the attribute. If null, the corresponding | |||
* property is got from the <code> defaultInstance</code> | |||
* @param defaultInstance | |||
* the default instance of the class for fetching the default | |||
* values | |||
*/ | |||
public static boolean assignAttribute(DesignSynchronizable component, | |||
String attribute, String value, DesignSynchronizable defaultInstance) { | |||
getLogger().info("Assigning attribute " + attribute + " -> " + value); | |||
// find setter for the property | |||
boolean success = false; | |||
try { | |||
Method setter = findSetterForAttribute(component.getClass(), | |||
attribute); | |||
if (setter == null) { | |||
// if we don't have the setter, there is no point in continuing | |||
success = false; | |||
} else if (value != null) { | |||
// we have a value from design attributes, let's use that | |||
getLogger().info("Setting the value from attributes"); | |||
Object param = parseAttributeValue( | |||
setter.getParameterTypes()[0], value); | |||
setter.invoke(component, param); | |||
success = true; | |||
} else { | |||
// otherwise find the getter for the property | |||
Method getter = findGetter(component.getClass(), setter); | |||
if (getter != null) { | |||
// read the default value from defaults | |||
getLogger().info("Setting the default value"); | |||
Object defaultValue = getter.invoke(defaultInstance); | |||
setter.invoke(component, defaultValue); | |||
success = true; | |||
} | |||
} | |||
} catch (Exception e) { | |||
getLogger().log(Level.WARNING, | |||
"Failed to set attribute " + attribute, e); | |||
} | |||
if (!success) { | |||
getLogger().info( | |||
"property " + attribute | |||
+ " ignored by default attribute handler"); | |||
} | |||
return success; | |||
} | |||
/** | |||
* Assigns the width for the component based on the design attributes | |||
* | |||
* @since 7.4 | |||
* @param component | |||
* the component to assign the width | |||
* @param attributes | |||
* the attributes to be used for determining the width | |||
* @param defaultInstance | |||
* the default instance of the class for fetching the default | |||
* value | |||
*/ | |||
public static void assignWidth(DesignSynchronizable component, | |||
Attributes attributes, DesignSynchronizable defaultInstance) { | |||
if (attributes.hasKey("width-auto") || attributes.hasKey("size-auto")) { | |||
component.setWidth(null); | |||
} else if (attributes.hasKey("width-full") | |||
|| attributes.hasKey("size-full")) { | |||
component.setWidth("100%"); | |||
} else if (attributes.hasKey("width")) { | |||
component.setWidth(attributes.get("width")); | |||
} else { | |||
component.setWidth(defaultInstance.getWidth(), | |||
defaultInstance.getWidthUnits()); | |||
} | |||
} | |||
/** | |||
* Assigns the height for the component based on the design attributes | |||
* | |||
* @since 7.4 | |||
* @param component | |||
* the component to assign the height | |||
* @param attributes | |||
* the attributes to be used for determining the height | |||
* @param defaultInstance | |||
* the default instance of the class for fetching the default | |||
* value | |||
*/ | |||
public static void assignHeight(DesignSynchronizable component, | |||
Attributes attributes, DesignSynchronizable defaultInstance) { | |||
if (attributes.hasKey("height-auto") || attributes.hasKey("size-auto")) { | |||
component.setHeight(null); | |||
} else if (attributes.hasKey("height-full") | |||
|| attributes.hasKey("size-full")) { | |||
component.setHeight("100%"); | |||
} else if (attributes.hasKey("height")) { | |||
component.setHeight(attributes.get("height")); | |||
} else { | |||
component.setHeight(defaultInstance.getHeight(), | |||
defaultInstance.getHeightUnits()); | |||
} | |||
} | |||
} |
@@ -0,0 +1,57 @@ | |||
/* | |||
* 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.ui.declarative; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
/** | |||
* This class contains contextual information that is collected when a component | |||
* tree is constructed based on HTML design template | |||
* | |||
* @since 7.4 | |||
* @author Vaadin Ltd | |||
*/ | |||
public class DesignContext { | |||
// cache for object instances | |||
private static Map<Class<?>, Object> instanceCache = Collections | |||
.synchronizedMap(new HashMap<Class<?>, Object>()); | |||
/** | |||
* Returns the default instance for the given class. The instance must not | |||
* be modified by the caller. | |||
* | |||
* @since | |||
* @param instanceClass | |||
* @return | |||
*/ | |||
public <T> T getDefaultInstance(Class<T> instanceClass) { | |||
T instance = (T) instanceCache.get(instanceClass); | |||
if (instance == null) { | |||
try { | |||
instance = instanceClass.newInstance(); | |||
} catch (InstantiationException e) { | |||
e.printStackTrace(); | |||
} catch (IllegalAccessException e) { | |||
e.printStackTrace(); | |||
} | |||
instanceCache.put(instanceClass, instance); | |||
} | |||
return instance; | |||
} | |||
} |
@@ -0,0 +1,187 @@ | |||
/* | |||
* 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.tests.server.component.abstractcomponent; | |||
import junit.framework.TestCase; | |||
import org.jsoup.nodes.Attributes; | |||
import org.jsoup.nodes.Element; | |||
import org.jsoup.nodes.Node; | |||
import org.jsoup.parser.Tag; | |||
import com.vaadin.server.ExternalResource; | |||
import com.vaadin.server.FileResource; | |||
import com.vaadin.server.ThemeResource; | |||
import com.vaadin.ui.AbstractComponent; | |||
import com.vaadin.ui.Label; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
/** | |||
* Test case for the properties of the abstract component | |||
* | |||
* @since | |||
* @author Vaadin Ltd | |||
*/ | |||
public class TestSynchronizeFromDesign extends TestCase { | |||
private DesignContext ctx; | |||
@Override | |||
protected void setUp() throws Exception { | |||
super.setUp(); | |||
ctx = new DesignContext(); | |||
} | |||
public void testSynchronizeId() { | |||
Node design = createDesign("id", "testId"); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals("testId", component.getId()); | |||
} | |||
public void testSynchronizePrimaryStyleName() { | |||
Node design = createDesign("primary-style-name", "test-style"); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals("test-style", component.getPrimaryStyleName()); | |||
} | |||
public void testSynchronizeCaption() { | |||
Node design = createDesign("caption", "test-caption"); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals("test-caption", component.getCaption()); | |||
} | |||
public void testSynchronizeLocale() { | |||
Node design = createDesign("locale", "fi"); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals("fi", component.getLocale().getLanguage()); | |||
} | |||
public void testSynchronizeExternalIcon() { | |||
Node design = createDesign("icon", "http://example.com/example.gif"); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertTrue("Incorrect resource type returned", component.getIcon() | |||
.getClass().isAssignableFrom(ExternalResource.class)); | |||
} | |||
public void testSynchronizeThemeIcon() { | |||
Node design = createDesign("icon", "theme://example.gif"); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertTrue("Incorrect resource type returned", component.getIcon() | |||
.getClass().isAssignableFrom(ThemeResource.class)); | |||
} | |||
public void testSynchronizeFileResource() { | |||
Node design = createDesign("icon", "img/example.gif"); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertTrue("Incorrect resource type returned", component.getIcon() | |||
.getClass().isAssignableFrom(FileResource.class)); | |||
} | |||
public void testSynchronizeImmediate() { | |||
Node design = createDesign("immediate", "true"); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals(true, component.isImmediate()); | |||
} | |||
public void testSynchronizeDescription() { | |||
Node design = createDesign("description", "test-description"); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals("test-description", component.getDescription()); | |||
} | |||
public void testSynchronizeSizeFull() { | |||
Node design = createDesign("size-full", ""); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals(100, component.getWidth(), 0.1f); | |||
assertEquals(100, component.getHeight(), 0.1f); | |||
} | |||
public void testSynchronizeSizeAuto() { | |||
Node design = createDesign("size-auto", ""); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals(-1, component.getWidth(), 0.1f); | |||
assertEquals(-1, component.getHeight(), 0.1f); | |||
} | |||
public void testSynchronizeHeightFull() { | |||
Node design = createDesign("height-full", ""); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals(100, component.getHeight(), 0.1f); | |||
} | |||
public void testSynchronizeHeightAuto() { | |||
Node design = createDesign("height-auto", ""); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals(-1, component.getHeight(), 0.1f); | |||
} | |||
public void testSynchronizeWidthFull() { | |||
Node design = createDesign("width-full", ""); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals(100, component.getWidth(), 0.1f); | |||
} | |||
public void testSynchronizeWidthAuto() { | |||
Node design = createDesign("width-auto", ""); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals(-1, component.getWidth(), 0.1f); | |||
} | |||
public void testSynchronizeWidth() { | |||
Node design = createDesign("width", "12px"); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals(12, component.getWidth(), 0.1f); | |||
assertEquals(com.vaadin.server.Sizeable.Unit.PIXELS, | |||
component.getWidthUnits()); | |||
} | |||
public void testSynchronizeHeight() { | |||
Node design = createDesign("height", "12px"); | |||
AbstractComponent component = getComponent(); | |||
component.synchronizeFromDesign(design, ctx); | |||
assertEquals(12, component.getHeight(), 0.1f); | |||
assertEquals(com.vaadin.server.Sizeable.Unit.PIXELS, | |||
component.getHeightUnits()); | |||
} | |||
private AbstractComponent getComponent() { | |||
return new Label(); | |||
} | |||
private Node createDesign(String key, String value) { | |||
Attributes attributes = new Attributes(); | |||
attributes.put(key, value); | |||
Element node = new Element(Tag.valueOf("v-label"), "", attributes); | |||
return node; | |||
} | |||
} |