aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatti Hosio <mhosio@vaadin.com>2014-12-10 09:56:12 +0200
committerMatti Hosio <mhosio@vaadin.com>2014-12-10 16:00:51 +0200
commit5d6271489b2ce52f3c4eb3ce40cc1148c1092501 (patch)
tree885ecf2046b336b704b8b840c2a9c207e5db3d63
parent409727ec617bfc092f584769997417c05259614d (diff)
downloadvaadin-framework-5d6271489b2ce52f3c4eb3ce40cc1148c1092501.tar.gz
vaadin-framework-5d6271489b2ce52f3c4eb3ce40cc1148c1092501.zip
Declarative support for AbstractField (#7749)
Change-Id: I8eb917186886aa1a9c63939d2dfd1f59df973aa2
-rw-r--r--server/src/com/vaadin/ui/AbstractComponent.java2
-rw-r--r--server/src/com/vaadin/ui/AbstractField.java65
-rw-r--r--server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java64
-rw-r--r--server/tests/src/com/vaadin/tests/layoutparser/ParseAllSupportedComponentsTest.java46
-rw-r--r--server/tests/src/com/vaadin/tests/layoutparser/all-components.html46
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeFromDesign.java2
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeToDesign.java2
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/abstractfield/TestSynchronizeFromDesign.java71
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/abstractfield/TestSynchronizeToDesign.java77
9 files changed, 372 insertions, 3 deletions
diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java
index 1b7eeadd87..434fb114df 100644
--- a/server/src/com/vaadin/ui/AbstractComponent.java
+++ b/server/src/com/vaadin/ui/AbstractComponent.java
@@ -1206,7 +1206,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
private static final String[] customAttributes = new String[] { "width",
"height", "debug-id", "error", "width-auto", "height-auto",
"width-full", "height-full", "size-auto", "size-full",
- "responsive", "immediate", "locale" };
+ "responsive", "immediate", "locale", "read-only" };
/*
* (non-Javadoc)
diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java
index 369ad1253c..3728696233 100644
--- a/server/src/com/vaadin/ui/AbstractField.java
+++ b/server/src/com/vaadin/ui/AbstractField.java
@@ -25,6 +25,10 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
+import java.util.logging.Logger;
+
+import org.jsoup.nodes.Attributes;
+import org.jsoup.nodes.Element;
import com.vaadin.data.Buffered;
import com.vaadin.data.Property;
@@ -43,6 +47,8 @@ import com.vaadin.server.CompositeErrorMessage;
import com.vaadin.server.ErrorMessage;
import com.vaadin.shared.AbstractFieldState;
import com.vaadin.shared.util.SharedUtil;
+import com.vaadin.ui.declarative.DesignAttributeHandler;
+import com.vaadin.ui.declarative.DesignContext;
/**
* <p>
@@ -1751,4 +1757,63 @@ public abstract class AbstractField<T> extends AbstractComponent implements
isListeningToPropertyEvents = false;
}
}
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.ui.AbstractComponent#synchronizeFromDesign(org.jsoup.nodes
+ * .Element, com.vaadin.ui.declarative.DesignContext)
+ */
+ @Override
+ public void synchronizeFromDesign(Element design,
+ DesignContext designContext) {
+ super.synchronizeFromDesign(design, designContext);
+ AbstractField def = designContext.getDefaultInstance(this.getClass());
+ Attributes attr = design.attributes();
+ boolean readOnly = DesignAttributeHandler.readAttribute("readonly",
+ attr, def.isReadOnly(), Boolean.class);
+ setReadOnly(readOnly);
+ // tabindex
+ int tabIndex = DesignAttributeHandler.readAttribute("tabindex", attr,
+ def.getTabIndex(), Integer.class);
+ setTabIndex(tabIndex);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.AbstractComponent#getCustomAttributes()
+ */
+ @Override
+ protected Collection<String> getCustomAttributes() {
+ Collection<String> attributes = super.getCustomAttributes();
+ attributes.add("readonly");
+ attributes.add("tabindex");
+ return attributes;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.ui.AbstractComponent#synchronizeToDesign(org.jsoup.nodes.Element
+ * , com.vaadin.ui.declarative.DesignContext)
+ */
+ @Override
+ public void synchronizeToDesign(Element design, DesignContext designContext) {
+ super.synchronizeToDesign(design, designContext);
+ AbstractField def = designContext.getDefaultInstance(this.getClass());
+ Attributes attr = design.attributes();
+ // handle readonly
+ DesignAttributeHandler.writeAttribute("readonly", attr,
+ super.isReadOnly(), def.isReadOnly(), Boolean.class);
+ // handle tab index
+ DesignAttributeHandler.writeAttribute("tabindex", attr, getTabIndex(),
+ def.getTabIndex(), Integer.class);
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(AbstractField.class.getName());
+ }
}
diff --git a/server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java b/server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java
index f71b36f66c..1beddf57de 100644
--- a/server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java
+++ b/server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java
@@ -99,6 +99,7 @@ public class DesignAttributeHandler implements Serializable {
* @param defaultInstance
* the default instance of the class for fetching the default
* values
+ * @return true on success
*/
public static boolean readAttribute(DesignSynchronizable component,
String attribute, Attributes attributes,
@@ -237,6 +238,69 @@ public class DesignAttributeHandler implements Serializable {
}
/**
+ * Reads the given attribute from attributes. If the attribute is not found,
+ * the provided default value is returned
+ *
+ * @param attribute
+ * the attribute key
+ * @param attributes
+ * the set of attributes to read from
+ * @param defaultValue
+ * the default value that is returned if the attribute is not
+ * found
+ * @param outputType
+ * the output type for the attribute
+ * @return the attribute value or the default value if the attribute is not
+ * found
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T readAttribute(String attribute, Attributes attributes,
+ T defaultValue, Class<T> outputType) {
+ if (!isSupported(outputType)) {
+ throw new IllegalArgumentException("output type: "
+ + outputType.getName() + " not supported");
+ }
+ if (!attributes.hasKey(attribute)) {
+ return defaultValue;
+ } else {
+ try {
+ String value = attributes.get(attribute);
+ return (T) fromAttributeValue(outputType, value);
+ } catch (Exception e) {
+ throw new DesignException("Failed to read attribute "
+ + attribute, e);
+ }
+ }
+ }
+
+ /**
+ * Writes the given attribute value to attributes if it differs from the
+ * default attribute value
+ *
+ * @param attribute
+ * the attribute key
+ * @param attributes
+ * the set of attributes where the new attribute is written
+ * @param value
+ * the attribute value
+ * @param defaultValue
+ * the default attribute value
+ * @param the
+ * type of the input value
+ */
+ public static <T> void writeAttribute(String attribute,
+ Attributes attributes, T value, T defaultValue, Class<T> inputType) {
+ if (!isSupported(inputType)) {
+ throw new IllegalArgumentException("input type: "
+ + inputType.getName() + " not supported");
+ }
+ if (!SharedUtil.equals(value, defaultValue)) {
+ String attributeValue = toAttributeValue(value.getClass(), value);
+ attributes.put(attribute, attributeValue);
+ }
+ }
+
+ /**
* Formats the given design attribute value. The method is provided to
* ensure consistent number formatting for design attribute values
*
diff --git a/server/tests/src/com/vaadin/tests/layoutparser/ParseAllSupportedComponentsTest.java b/server/tests/src/com/vaadin/tests/layoutparser/ParseAllSupportedComponentsTest.java
new file mode 100644
index 0000000000..c3d1b36320
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/layoutparser/ParseAllSupportedComponentsTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.layoutparser;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+import junit.framework.TestCase;
+
+import com.vaadin.ui.declarative.DesignContext;
+import com.vaadin.ui.declarative.LayoutHandler;
+
+/**
+ * Just top level test case that contains all synchronizable components
+ *
+ * @author Vaadin Ltd
+ */
+public class ParseAllSupportedComponentsTest extends TestCase {
+
+ public void testParsing() {
+ try {
+ DesignContext ctx = LayoutHandler
+ .parse(new FileInputStream(
+ "server/tests/src/com/vaadin/tests/layoutparser/all-components.html"));
+ assertNotNull("The returned design context can not be null", ctx);
+ assertNotNull("the component root can not be null",
+ ctx.getComponentRoot());
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ fail("Template parsing threw exception");
+ }
+ }
+}
diff --git a/server/tests/src/com/vaadin/tests/layoutparser/all-components.html b/server/tests/src/com/vaadin/tests/layoutparser/all-components.html
new file mode 100644
index 0000000000..99e516ff55
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/layoutparser/all-components.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="package-mapping" content="my:com.addon.mypackage"/>
+ </head>
+ <body>
+ <v-vertical-layout>
+ <!-- abstract component -->
+ <v-button primary-style-name="button" id="foo" style-name="red" caption="Some caption" icon="vaadin://themes/runo/icons/16/ok.png" description="My tooltip" error="Something went wrong" locale="en_US"></v-button>
+
+ <!-- absolute layout -->
+ <v-absolute-layout>
+ <v-button :top="100px" :left="0px" :z-index=21>OK</v-button>
+ <v-button :bottom="0px" :right="0px">Cancel</v-button>
+ </v-absolute-layout>
+
+ <!-- vertical layout -->
+ <v-vertical-layout spacing margin>
+ <v-button :top>OK</v-button>
+ <v-table size-full :expand=1 />
+ </v-vertical-layout>
+
+ <!-- horizontal layout -->
+ <v-horizontal-layout spacing margin>
+ <v-button :top>OK</v-button>
+ <v-table size-full :expand=1 />
+ </v-horizontal-layout>
+
+ <!-- form layout -->
+ <v-form-layout spacing margin>
+ <v-button :top>OK</v-button>
+ <v-table size-full :expand=1 />
+ </v-form-layout>
+
+ <!-- css layout -->
+ <v-css-layout>
+ <v-button>OK</v-button>
+ <v-table size-full />
+ </v-css-layout>
+
+ <!-- abstract field -->
+ <v-text-field buffered validation-visible=false invalid-committed invalid-allowed=false required required-error="This is a required field" conversion-error="Input {0} cannot be parsed" tabindex=3 readonly/>
+
+ </v-vertical-layout>
+ </body>
+</html> \ No newline at end of file
diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeFromDesign.java b/server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeFromDesign.java
index 06fc59a2f3..5153d92706 100644
--- a/server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeFromDesign.java
+++ b/server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeFromDesign.java
@@ -32,7 +32,7 @@ import com.vaadin.ui.Label;
import com.vaadin.ui.declarative.DesignContext;
/**
- * Test case for reading the attributes of the abstract component from design
+ * Test case for reading the attributes of the AbstractComponent from design
*
* @author Vaadin Ltd
*/
diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeToDesign.java b/server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeToDesign.java
index cb3892f6da..d3bcc919ce 100644
--- a/server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeToDesign.java
+++ b/server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeToDesign.java
@@ -37,7 +37,7 @@ import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.declarative.DesignContext;
/**
- * Test case for reading the attributes of the abstract component from design
+ * Test case for writing the attributes of the AbstractComponent to design
*
* @author Vaadin Ltd
*/
diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractfield/TestSynchronizeFromDesign.java b/server/tests/src/com/vaadin/tests/server/component/abstractfield/TestSynchronizeFromDesign.java
new file mode 100644
index 0000000000..6a2c194978
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/component/abstractfield/TestSynchronizeFromDesign.java
@@ -0,0 +1,71 @@
+/*
+ * 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.abstractfield;
+
+import junit.framework.TestCase;
+
+import org.jsoup.nodes.Attributes;
+import org.jsoup.nodes.Element;
+import org.jsoup.parser.Tag;
+
+import com.vaadin.ui.AbstractField;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.declarative.DesignContext;
+
+/**
+ *
+ * Test case for reading the attributes of the AbstractField from design
+ *
+ * @author Vaadin Ltd
+ */
+public class TestSynchronizeFromDesign extends TestCase {
+
+ private DesignContext ctx;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ ctx = new DesignContext();
+ }
+
+ public void testSynchronizeReadOnly() {
+ Element design = createDesign("readonly", "");
+ AbstractField component = getComponent();
+ component.synchronizeFromDesign(design, ctx);
+ assertEquals(true, component.isReadOnly());
+ design = createDesign("readonly", "false");
+ component.synchronizeFromDesign(design, ctx);
+ assertEquals(false, component.isReadOnly());
+ }
+
+ public void testSynchronizeTabIndex() {
+ Element design = createDesign("tabindex", "2");
+ AbstractField component = getComponent();
+ component.synchronizeFromDesign(design, ctx);
+ assertEquals("Tab index must be 2", 2, component.getTabIndex());
+ }
+
+ private AbstractField getComponent() {
+ return new TextField();
+ }
+
+ private Element createDesign(String key, String value) {
+ Attributes attributes = new Attributes();
+ attributes.put(key, value);
+ Element node = new Element(Tag.valueOf("v-text-field"), "", attributes);
+ return node;
+ }
+}
diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractfield/TestSynchronizeToDesign.java b/server/tests/src/com/vaadin/tests/server/component/abstractfield/TestSynchronizeToDesign.java
new file mode 100644
index 0000000000..26f64f9199
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/component/abstractfield/TestSynchronizeToDesign.java
@@ -0,0 +1,77 @@
+/*
+ * 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.abstractfield;
+
+import junit.framework.TestCase;
+
+import org.jsoup.nodes.Attributes;
+import org.jsoup.nodes.Element;
+import org.jsoup.parser.Tag;
+
+import com.vaadin.data.util.ObjectProperty;
+import com.vaadin.ui.AbstractField;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.declarative.DesignContext;
+
+/**
+ * Test case for writing the attributes of the AbstractField to design
+ *
+ * @author Vaadin Ltd
+ */
+public class TestSynchronizeToDesign extends TestCase {
+
+ private DesignContext ctx;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ ctx = new DesignContext();
+ }
+
+ public void testSynchronizeReadOnly() {
+ Element design = createDesign();
+ AbstractField component = getComponent();
+ component.setReadOnly(true);
+ component.synchronizeToDesign(design, ctx);
+ // we only changed one of the attributes, others are at default values
+ assertEquals(1, design.attributes().size());
+ assertTrue("Design must contain readonly", design.hasAttr("readonly"));
+ assertTrue("Readonly must be true", design.attr("readonly").equals("")
+ || design.attr("readonly").equals("true"));
+ }
+
+ public void testSynchronizeModelReadOnly() {
+ Element design = createDesign();
+ AbstractField component = getComponent();
+ ObjectProperty property = new ObjectProperty<String>("test");
+ property.setReadOnly(true);
+ component.setPropertyDataSource(property);
+ component.synchronizeToDesign(design, ctx);
+ // make sure that property readonly is not written to design
+ assertFalse("Design must not contain readonly",
+ design.hasAttr("readonly"));
+ }
+
+ private AbstractField getComponent() {
+ return new TextField();
+ }
+
+ private Element createDesign() {
+ Attributes attr = new Attributes();
+ attr.put("should_be_removed", "foo");
+ return new Element(Tag.valueOf("v-text-field"), "", attr);
+ }
+}