diff options
Diffstat (limited to 'server')
6 files changed, 355 insertions, 6 deletions
diff --git a/server/src/com/vaadin/ui/AbsoluteLayout.java b/server/src/com/vaadin/ui/AbsoluteLayout.java index afc73f5ecc..c4c0de764f 100644 --- a/server/src/com/vaadin/ui/AbsoluteLayout.java +++ b/server/src/com/vaadin/ui/AbsoluteLayout.java @@ -21,6 +21,10 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; +import org.jsoup.nodes.Attributes; +import org.jsoup.nodes.Element; +import org.jsoup.nodes.Node; + import com.vaadin.event.LayoutEvents.LayoutClickEvent; import com.vaadin.event.LayoutEvents.LayoutClickListener; import com.vaadin.event.LayoutEvents.LayoutClickNotifier; @@ -30,6 +34,8 @@ import com.vaadin.shared.EventId; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.ui.absolutelayout.AbsoluteLayoutServerRpc; import com.vaadin.shared.ui.absolutelayout.AbsoluteLayoutState; +import com.vaadin.ui.declarative.DesignAttributeHandler; +import com.vaadin.ui.declarative.DesignContext; /** * AbsoluteLayout is a layout implementation that mimics html absolute @@ -40,6 +46,13 @@ import com.vaadin.shared.ui.absolutelayout.AbsoluteLayoutState; public class AbsoluteLayout extends AbstractLayout implements LayoutClickNotifier { + // constants for design attributes + private static final String ATTR_TOP = ":top"; + private static final String ATTR_RIGHT = ":right"; + private static final String ATTR_BOTTOM = ":bottom"; + private static final String ATTR_LEFT = ":left"; + private static final String ATTR_Z_INDEX = ":z-index"; + private AbsoluteLayoutServerRpc rpc = new AbsoluteLayoutServerRpc() { @Override @@ -660,4 +673,101 @@ public class AbsoluteLayout extends AbstractLayout implements public void removeListener(LayoutClickListener listener) { removeLayoutClickListener(listener); } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.AbstractComponent#synchronizeFromDesign(org.jsoup.nodes + * .Node, com.vaadin.ui.declarative.DesignContext) + */ + @Override + public void synchronizeFromDesign(Element design, + DesignContext designContext) { + // process default attributes + super.synchronizeFromDesign(design, designContext); + // remove current children + removeAllComponents(); + // handle children + for (Element childComponent : design.children()) { + Attributes attr = childComponent.attributes(); + DesignSynchronizable newChild = designContext + .createChild(childComponent); + StringBuilder css = new StringBuilder(); + if (attr.hasKey(ATTR_TOP)) { + css.append("top:").append(attr.get(ATTR_TOP)).append(";"); + } + if (attr.hasKey(ATTR_RIGHT)) { + css.append("right:").append(attr.get(ATTR_RIGHT)).append(";"); + } + if (attr.hasKey(ATTR_BOTTOM)) { + css.append("bottom:").append(attr.get(ATTR_BOTTOM)).append(";"); + } + if (attr.hasKey(ATTR_LEFT)) { + css.append("left:").append(attr.get(ATTR_LEFT)).append(";"); + } + if (attr.hasKey(ATTR_Z_INDEX)) { + css.append("z-index:").append(attr.get(ATTR_Z_INDEX)) + .append(";"); + } + addComponent(newChild, css.toString()); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.AbstractComponent#synchronizeToDesign(org.jsoup.nodes.Node, + * com.vaadin.ui.declarative.DesignContext) + */ + @Override + public void synchronizeToDesign(Element design, DesignContext designContext) { + super.synchronizeToDesign(design, designContext); + // handle children + Element designElement = design; + for (Component child : this) { + DesignSynchronizable childComponent = (DesignSynchronizable) child; + Element childNode = designContext.createNode(childComponent); + designElement.appendChild(childNode); + childComponent.synchronizeToDesign(childNode, designContext); + // handle position + ComponentPosition position = getPosition(child); + writePositionAttribute(childNode, ATTR_TOP, position.getTopUnits() + .getSymbol(), position.getTopValue()); + writePositionAttribute(childNode, ATTR_RIGHT, position + .getRightUnits().getSymbol(), position.getRightValue()); + writePositionAttribute(childNode, ATTR_BOTTOM, position + .getBottomUnits().getSymbol(), position.getBottomValue()); + writePositionAttribute(childNode, ATTR_LEFT, position + .getLeftUnits().getSymbol(), position.getLeftValue()); + // handle z-index + if (position.getZIndex() >= 0) { + childNode.attr(ATTR_Z_INDEX, String.valueOf(position.zIndex)); + } + } + } + + /** + * Private method for writing position attributes + * + * @since + * @param node + * target node + * @param key + * attribute key + * @param symbol + * value symbol + * @param value + * the value + */ + private void writePositionAttribute(Node node, String key, String symbol, + Float value) { + if (value != null) { + String valueString = DesignAttributeHandler.formatFloat(value + .floatValue()); + node.attr(key, valueString + symbol); + } + } + } diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java index b5721a0bba..8ee3f722ab 100644 --- a/server/src/com/vaadin/ui/AbstractComponent.java +++ b/server/src/com/vaadin/ui/AbstractComponent.java @@ -1029,7 +1029,7 @@ public abstract class AbstractComponent extends AbstractClientConnector attributes.put("width-auto", "true"); } else { String widthString = DesignAttributeHandler - .formatDesignAttribute(getWidth()) + .formatFloat(getWidth()) + getWidthUnits().getSymbol(); attributes.put("width", widthString); @@ -1043,7 +1043,7 @@ public abstract class AbstractComponent extends AbstractClientConnector attributes.put("height-auto", "true"); } else { String heightString = DesignAttributeHandler - .formatDesignAttribute(getHeight()) + .formatFloat(getHeight()) + getHeightUnits().getSymbol(); attributes.put("height", heightString); } diff --git a/server/src/com/vaadin/ui/AbstractOrderedLayout.java b/server/src/com/vaadin/ui/AbstractOrderedLayout.java index bbaaffe789..139a4eb545 100644 --- a/server/src/com/vaadin/ui/AbstractOrderedLayout.java +++ b/server/src/com/vaadin/ui/AbstractOrderedLayout.java @@ -559,8 +559,8 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements if (expandRatio == 1.0f) { childNode.attr(":expand", ""); } else if (expandRatio > 0) { - childNode.attr(":expand", DesignAttributeHandler - .formatDesignAttribute(expandRatio)); + childNode.attr(":expand", + DesignAttributeHandler.formatFloat(expandRatio)); } } } diff --git a/server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java b/server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java index 423b2fb60b..daebb1c09a 100644 --- a/server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java +++ b/server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java @@ -244,12 +244,35 @@ public class DesignAttributeHandler { * the number to be formatted * @return the formatted number */ - public static String formatDesignAttribute(float number) { + public static String formatFloat(float number) { + return getDecimalFormat().format(number); + } + + /** + * Formats the given design attribute value. The method is provided to + * ensure consistent number formatting for design attribute values + * + * @since 7.4 + * @param number + * the number to be formatted + * @return the formatted number + */ + public static String formatDouble(double number) { + return getDecimalFormat().format(number); + } + + /** + * Creates the decimal format used when writing attributes to the design + * + * @since 7.4 + * @return the decimal format + */ + private static DecimalFormat getDecimalFormat() { DecimalFormatSymbols symbols = new DecimalFormatSymbols(new Locale( "en_US")); DecimalFormat fmt = new DecimalFormat("0.###", symbols); fmt.setGroupingUsed(false); - return fmt.format(number); + return fmt; } /** @@ -359,8 +382,13 @@ public class DesignAttributeHandler { "Unknown resource type " + value.getClass().getName()); return null; } + } else if (sourceType == Float.class || sourceType == Float.TYPE) { + return formatFloat(((Float) value).floatValue()); + } else if (sourceType == Double.class || sourceType == Double.TYPE) { + return formatDouble(((Double) value).doubleValue()); } else { return value.toString(); + } } diff --git a/server/tests/src/com/vaadin/tests/server/component/absolutelayout/TestSynchronizeFromDesign.java b/server/tests/src/com/vaadin/tests/server/component/absolutelayout/TestSynchronizeFromDesign.java new file mode 100644 index 0000000000..95dc0ad996 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/absolutelayout/TestSynchronizeFromDesign.java @@ -0,0 +1,111 @@ +/* + * 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.absolutelayout; + +import java.util.Iterator; + +import junit.framework.TestCase; + +import org.jsoup.nodes.Attributes; +import org.jsoup.nodes.Element; +import org.jsoup.parser.Tag; + +import com.vaadin.server.Sizeable; +import com.vaadin.ui.AbsoluteLayout; +import com.vaadin.ui.AbsoluteLayout.ComponentPosition; +import com.vaadin.ui.Component; +import com.vaadin.ui.DesignSynchronizable; +import com.vaadin.ui.declarative.DesignContext; + +/** + * Test case for reading AbsoluteLayout from design + * + * @since + * @author Vaadin Ltd + */ +public class TestSynchronizeFromDesign extends TestCase { + + private AbsoluteLayout root; + + @Override + public void setUp() throws Exception { + super.setUp(); + root = createLayout(); + } + + public void testAttributes() { + assertEquals("test-layout", root.getCaption()); + Iterator<Component> children = root.iterator(); + assertEquals("test-label", children.next().getCaption()); + assertEquals("test-button", children.next().getCaption()); + } + + public void testTopLeftPosition() { + ComponentPosition position = root.getPosition(root.iterator().next()); + assertEquals(Sizeable.Unit.PIXELS, position.getTopUnits()); + assertEquals(100.0f, position.getTopValue()); + assertEquals(Sizeable.Unit.PERCENTAGE, position.getLeftUnits()); + assertEquals(50.0f, position.getLeftValue()); + } + + public void testBottomRightPosition() { + Iterator<Component> children = root.iterator(); + children.next(); + ComponentPosition position = root.getPosition(children.next()); + assertEquals(Sizeable.Unit.PIXELS, position.getBottomUnits()); + assertEquals(100.0f, position.getBottomValue()); + assertEquals(Sizeable.Unit.PERCENTAGE, position.getRightUnits()); + assertEquals(50.0f, position.getRightValue()); + } + + public void testZIndex() { + ComponentPosition position = root.getPosition(root.iterator().next()); + assertEquals(2, position.getZIndex()); + } + + private AbsoluteLayout createLayout() { + DesignContext ctx = new DesignContext(); + Element design = createDesign(); + DesignSynchronizable child = ctx.createChild(design); + return (AbsoluteLayout) child; + } + + private Element createDesign() { + + Attributes rootAttributes = new Attributes(); + rootAttributes.put("caption", "test-layout"); + Element node = new Element(Tag.valueOf("v-absolute-layout"), "", + rootAttributes); + + Attributes firstChildAttributes = new Attributes(); + firstChildAttributes.put("caption", "test-label"); + firstChildAttributes.put(":top", "100px"); + firstChildAttributes.put(":left", "50%"); + firstChildAttributes.put(":z-index", "2"); + Element firstChild = new Element(Tag.valueOf("v-label"), "", + firstChildAttributes); + node.appendChild(firstChild); + + Attributes secondChildAttributes = new Attributes(); + secondChildAttributes.put("caption", "test-button"); + secondChildAttributes.put(":bottom", "100px"); + secondChildAttributes.put(":right", "50%"); + Element secondChild = new Element(Tag.valueOf("v-button"), "", + secondChildAttributes); + node.appendChild(secondChild); + return node; + } +} diff --git a/server/tests/src/com/vaadin/tests/server/component/absolutelayout/TestSynchronizeToDesign.java b/server/tests/src/com/vaadin/tests/server/component/absolutelayout/TestSynchronizeToDesign.java new file mode 100644 index 0000000000..eb61d13684 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/absolutelayout/TestSynchronizeToDesign.java @@ -0,0 +1,100 @@ +/* + * 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.absolutelayout; + +import junit.framework.TestCase; + +import org.jsoup.nodes.Attributes; +import org.jsoup.nodes.Element; +import org.jsoup.parser.Tag; + +import com.vaadin.ui.AbsoluteLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.declarative.DesignContext; + +/** + * Test case for writing AbsoluteLayout to design + * + * @since + * @author Vaadin Ltd + */ +public class TestSynchronizeToDesign extends TestCase { + + public void testSynchronizeEmptyLayout() { + AbsoluteLayout layout = createTestLayout(); + layout.removeAllComponents(); + Element design = createDesign(); + layout.synchronizeToDesign(design, createDesignContext()); + assertEquals(0, design.childNodes().size()); + assertEquals("changed-caption", design.attr("caption")); + } + + public void testSynchronizeLayoutWithChildren() { + AbsoluteLayout layout = createTestLayout(); + Element design = createDesign(); + layout.synchronizeToDesign(design, createDesignContext()); + assertEquals(2, design.childNodes().size()); + assertEquals("v-label", ((Element) design.childNode(0)).tagName()); + assertEquals("v-label", ((Element) design.childNode(1)).tagName()); + } + + public void testSynchronizePosition() { + AbsoluteLayout layout = createTestLayout(); + Element design = createDesign(); + layout.synchronizeToDesign(design, createDesignContext()); + Attributes attributes = design.childNode(0).attributes(); + assertEquals("50px", attributes.get(":top")); + assertEquals("50%", attributes.get(":left")); + assertEquals("2", attributes.get(":z-index")); + attributes = design.childNode(1).attributes(); + assertEquals("50px", attributes.get(":bottom")); + assertEquals("50%", attributes.get(":right")); + } + + private AbsoluteLayout createTestLayout() { + AbsoluteLayout layout = new AbsoluteLayout(); + layout.setCaption("changed-caption"); + layout.addComponent(new Label("test-label"), + "top:50px;left:50%;z-index:2"); + layout.addComponent(new Label("test-label-2"), + "bottom:50px;right:50%;z-index:3"); + return layout; + } + + private Element createDesign() { + // make sure that the design node has old content that should be removed + Attributes rootAttributes = new Attributes(); + rootAttributes.put("caption", "test-layout"); + Element node = new Element(Tag.valueOf("v-absolute-layout"), "", + rootAttributes); + Attributes firstChildAttributes = new Attributes(); + firstChildAttributes.put("caption", "test-label"); + Element firstChild = new Element(Tag.valueOf("v-label"), "", + firstChildAttributes); + node.appendChild(firstChild); + + Attributes secondChildAttributes = new Attributes(); + secondChildAttributes.put("caption", "test-button"); + Element secondChild = new Element(Tag.valueOf("v-button"), "", + secondChildAttributes); + node.appendChild(secondChild); + return node; + } + + private DesignContext createDesignContext() { + return new DesignContext(); + } +} |