summaryrefslogtreecommitdiffstats
path: root/server/src/com/vaadin/ui/AbstractComponent.java
diff options
context:
space:
mode:
authorMatti Hosio <mhosio@vaadin.com>2014-12-04 11:19:20 +0200
committerMatti Hosio <mhosio@vaadin.com>2014-12-04 13:00:28 +0200
commit9730b6def11af6f0bcb1e8b0535e0ec081ac84dd (patch)
tree8fc0165a79dc6e8f972bbc3bb6e0961dc19f13c3 /server/src/com/vaadin/ui/AbstractComponent.java
parent405ae14a6bc561fc1fc431929d9b132415a6b3bd (diff)
downloadvaadin-framework-9730b6def11af6f0bcb1e8b0535e0ec081ac84dd.tar.gz
vaadin-framework-9730b6def11af6f0bcb1e8b0535e0ec081ac84dd.zip
Declarative feature improvements (#7749)
Change-Id: Ie04db36ad08f686bf6b173241652836f639d3bd9
Diffstat (limited to 'server/src/com/vaadin/ui/AbstractComponent.java')
-rw-r--r--server/src/com/vaadin/ui/AbstractComponent.java213
1 files changed, 193 insertions, 20 deletions
diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java
index b1927f8580..b5721a0bba 100644
--- a/server/src/com/vaadin/ui/AbstractComponent.java
+++ b/server/src/com/vaadin/ui/AbstractComponent.java
@@ -19,13 +19,19 @@ package com.vaadin.ui;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
+import java.util.Set;
import java.util.StringTokenizer;
+import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;
@@ -38,6 +44,7 @@ import com.vaadin.server.ComponentSizeValidator;
import com.vaadin.server.ErrorMessage;
import com.vaadin.server.ErrorMessage.ErrorLevel;
import com.vaadin.server.Resource;
+import com.vaadin.server.Sizeable;
import com.vaadin.server.UserError;
import com.vaadin.server.VaadinSession;
import com.vaadin.shared.AbstractComponentState;
@@ -922,8 +929,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
DesignAttributeHandler.readAttribute(this, attribute, attr, def);
}
// handle width and height
- DesignAttributeHandler.readWidth(this, attr, def);
- DesignAttributeHandler.readHeight(this, attr, def);
+ readSize(attr, def);
// handle component error
if (attr.hasKey("error")) {
UserError error = new UserError(attr.get("error"),
@@ -932,28 +938,187 @@ public abstract class AbstractComponent extends AbstractClientConnector
} else {
setComponentError(def.getComponentError());
}
+ // check for unsupported attributes
+ Set<String> supported = new HashSet<String>();
+ supported.addAll(getDefaultAttributes());
+ supported.addAll(getCustomAttributes());
+ for (Attribute a : attr) {
+ if (!a.getKey().startsWith(":") && !supported.contains(a.getKey())) {
+ getLogger().info(
+ "Unsupported attribute found when synchronizing from design : "
+ + a.getKey());
+ }
+ }
+ }
+
+ /**
+ * Synchronizes the size of this component from the given design attributes.
+ * If the attributes do not contain relevant size information, defaults is
+ * consulted.
+ *
+ * @param attributes
+ * the design attributes
+ * @param defaultInstance
+ * instance of the class that has default sizing.
+ */
+ private void readSize(Attributes attributes,
+ AbstractComponent defaultInstance) {
+ // read width
+ if (attributes.hasKey("width-auto") || attributes.hasKey("size-auto")) {
+ this.setWidth(null);
+ } else if (attributes.hasKey("width-full")
+ || attributes.hasKey("size-full")) {
+ this.setWidth("100%");
+ } else if (attributes.hasKey("width")) {
+ this.setWidth(attributes.get("width"));
+ } else {
+ this.setWidth(defaultInstance.getWidth(),
+ defaultInstance.getWidthUnits());
+ }
+
+ // read height
+ if (attributes.hasKey("height-auto") || attributes.hasKey("size-auto")) {
+ this.setHeight(null);
+ } else if (attributes.hasKey("height-full")
+ || attributes.hasKey("size-full")) {
+ this.setHeight("100%");
+ } else if (attributes.hasKey("height")) {
+ this.setHeight(attributes.get("height"));
+ } else {
+ this.setHeight(defaultInstance.getHeight(),
+ defaultInstance.getHeightUnits());
+ }
+ }
+
+ /**
+ * Writes the size related attributes for the component if they differ from
+ * the defaults
+ *
+ * @param component
+ * the component
+ * @param attributes
+ * the attribute map where the attribute are written
+ * @param defaultInstance
+ * the default instance of the class for fetching the default
+ * values
+ */
+ private void writeSize(Attributes attributes,
+ DesignSynchronizable defaultInstance) {
+ if (hasEqualSize(defaultInstance)) {
+ // we have default values -> ignore
+ return;
+ }
+ boolean widthFull = getWidth() == 100f
+ && getWidthUnits().equals(Sizeable.Unit.PERCENTAGE);
+ boolean heightFull = getHeight() == 100f
+ && getHeightUnits().equals(Sizeable.Unit.PERCENTAGE);
+ boolean widthAuto = getWidth() == -1;
+ boolean heightAuto = getHeight() == -1;
+
+ // first try the full shorthands
+ if (widthFull && heightFull) {
+ attributes.put("size-full", "true");
+ } else if (widthAuto && heightAuto) {
+ attributes.put("size-auto", "true");
+ } else {
+ // handle width
+ if (!hasEqualWidth(defaultInstance)) {
+ if (widthFull) {
+ attributes.put("width-full", "true");
+ } else if (widthAuto) {
+ attributes.put("width-auto", "true");
+ } else {
+ String widthString = DesignAttributeHandler
+ .formatDesignAttribute(getWidth())
+ + getWidthUnits().getSymbol();
+ attributes.put("width", widthString);
+
+ }
+ }
+ if (!hasEqualHeight(defaultInstance)) {
+ // handle height
+ if (heightFull) {
+ attributes.put("height-full", "true");
+ } else if (heightAuto) {
+ attributes.put("height-auto", "true");
+ } else {
+ String heightString = DesignAttributeHandler
+ .formatDesignAttribute(getHeight())
+ + getHeightUnits().getSymbol();
+ attributes.put("height", heightString);
+ }
+ }
+ }
}
/**
- * Returns the list of attributes that do not require custom handling when
- * synchronizing from design. These are typically attributes of some
+ * Test if the given component has equal width with this instance
+ *
+ * @param component
+ * the component for the width comparison
+ * @return true if the widths are equal
+ */
+ private boolean hasEqualWidth(Component component) {
+ return getWidth() == component.getWidth()
+ && getWidthUnits().equals(component.getWidthUnits());
+ }
+
+ /**
+ * Test if the given component has equal height with this instance
+ *
+ * @param component
+ * the component for the height comparison
+ * @return true if the heights are equal
+ */
+ private boolean hasEqualHeight(Component component) {
+ return getHeight() == component.getHeight()
+ && getHeightUnits().equals(component.getHeightUnits());
+ }
+
+ /**
+ * Test if the given components has equal size with this instance
+ *
+ * @param component
+ * the component for the size comparison
+ * @return true if the sizes are equal
+ */
+ private boolean hasEqualSize(Component component) {
+ return hasEqualWidth(component) && hasEqualHeight(component);
+ }
+
+ /**
+ * Returns a collection 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 a collection of attributes that can be synchronized from design
+ * using the default approach.
+ */
+ private Collection<String> getDefaultAttributes() {
+ Collection<String> attributes = DesignAttributeHandler
+ .getSupportedAttributes(this.getClass());
+ attributes.removeAll(getCustomAttributes());
return attributes;
}
+ /**
+ * Returns a collection of attributes that should not be handled by the
+ * basic implementation of the {@link synhronizeFromDesign} and
+ * {@link synchronizeToDesign} methods. Typically these are handled in a
+ * custom way in the overridden versions of the above methods
+ *
+ * @return the collection of attributes that are not handled by the basic
+ * implementation
+ */
+ protected Collection<String> getCustomAttributes() {
+ return new ArrayList<String>(Arrays.asList(customAttributes));
+ }
+
+ private static final String[] customAttributes = new String[] { "width",
+ "height", "debug-id", "error", "width-auto", "height-auto",
+ "width-full", "height-full", "size-auto", "size-full" };
+
/*
* (non-Javadoc)
*
@@ -963,8 +1128,8 @@ public abstract class AbstractComponent extends AbstractClientConnector
*/
@Override
public void synchronizeToDesign(Element design, DesignContext designContext) {
- // clear node contents
- DesignAttributeHandler.clearNode(design);
+ // clear element contents
+ DesignAttributeHandler.clearElement(design);
AbstractComponent def = designContext.getDefaultInstance(this
.getClass());
Attributes attr = design.attributes();
@@ -973,10 +1138,14 @@ public abstract class AbstractComponent extends AbstractClientConnector
DesignAttributeHandler.writeAttribute(this, attribute, attr, def);
}
// handle size
- DesignAttributeHandler.writeSize(this, attr, def);
+ writeSize(attr, def);
// handle component error
- if (getComponentError() != null) {
- attr.put("error", getComponentError().getFormattedHtmlMessage());
+ String errorMsg = getComponentError() != null ? getComponentError()
+ .getFormattedHtmlMessage() : null;
+ String defErrorMsg = def.getComponentError() != null ? def
+ .getComponentError().getFormattedHtmlMessage() : null;
+ if (!SharedUtil.equals(errorMsg, defErrorMsg)) {
+ attr.put("error", errorMsg);
}
}
@@ -1096,4 +1265,8 @@ public abstract class AbstractComponent extends AbstractClientConnector
}
return false;
}
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(AbstractComponent.class.getName());
+ }
}