Browse Source

Declarative support for AbstractField (#7749)

Change-Id: I8eb917186886aa1a9c63939d2dfd1f59df973aa2
tags/7.4.0.beta1
Matti Hosio 9 years ago
parent
commit
5d6271489b

+ 1
- 1
server/src/com/vaadin/ui/AbstractComponent.java View File

@@ -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)

+ 65
- 0
server/src/com/vaadin/ui/AbstractField.java View File

@@ -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());
}
}

+ 64
- 0
server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java View File

@@ -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,
@@ -236,6 +237,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

+ 46
- 0
server/tests/src/com/vaadin/tests/layoutparser/ParseAllSupportedComponentsTest.java View File

@@ -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");
}
}
}

+ 46
- 0
server/tests/src/com/vaadin/tests/layoutparser/all-components.html View File

@@ -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>

+ 1
- 1
server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeFromDesign.java View File

@@ -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
*/

+ 1
- 1
server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeToDesign.java View File

@@ -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
*/

+ 71
- 0
server/tests/src/com/vaadin/tests/server/component/abstractfield/TestSynchronizeFromDesign.java View File

@@ -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;
}
}

+ 77
- 0
server/tests/src/com/vaadin/tests/server/component/abstractfield/TestSynchronizeToDesign.java View File

@@ -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);
}
}

Loading…
Cancel
Save