diff options
author | Mika Murtojarvi <mika@vaadin.com> | 2014-12-11 18:25:40 +0200 |
---|---|---|
committer | Mika Murtojarvi <mika@vaadin.com> | 2014-12-12 16:36:20 +0200 |
commit | 628a2edf50c355e6e43e1da2e32224d32651327d (patch) | |
tree | 9814351d253b08720742237cd1ea84931636d215 /server/src/com/vaadin | |
parent | a025d511bfe4e81993d33fc424a9bed754586a52 (diff) | |
download | vaadin-framework-628a2edf50c355e6e43e1da2e32224d32651327d.tar.gz vaadin-framework-628a2edf50c355e6e43e1da2e32224d32651327d.zip |
Declarative support for split panel (#7749).
Change-Id: I96b7be150c9b6511f9fb701c5ee26afca67f1512
Diffstat (limited to 'server/src/com/vaadin')
-rw-r--r-- | server/src/com/vaadin/server/SizeWithUnit.java | 127 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/AbstractComponent.java | 59 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/AbstractSplitPanel.java | 139 |
3 files changed, 269 insertions, 56 deletions
diff --git a/server/src/com/vaadin/server/SizeWithUnit.java b/server/src/com/vaadin/server/SizeWithUnit.java new file mode 100644 index 0000000000..4c3c51eaec --- /dev/null +++ b/server/src/com/vaadin/server/SizeWithUnit.java @@ -0,0 +1,127 @@ +/* + * 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.server; + +import java.io.Serializable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.vaadin.server.Sizeable.Unit; +import com.vaadin.shared.util.SharedUtil; + +/** + * A class for representing a value-unit pair. Also contains utility methods for + * parsing such pairs from a string. + * + * @since 7.4 + * @author Vaadin Ltd + */ +public class SizeWithUnit implements Serializable { + private float size; + private Unit unit; + private static final Pattern sizePattern = Pattern + .compile(SharedUtil.SIZE_PATTERN); + + /** + * Constructs a new SizeWithUnit object representing the pair (size, unit). + * + * @param size + * a numeric value + * @param unit + * a unit + */ + public SizeWithUnit(float size, Unit unit) { + this.size = size; + this.unit = unit; + } + + /** + * Returns the numeric value stored in this object. + * + * @return the value of this (value, unit) pair + */ + public float getSize() { + return size; + } + + /** + * Returns the unit stored in this object. + * + * @return the unit of this (value, unit) pair + */ + public Unit getUnit() { + return unit; + } + + /** + * Returns an object whose numeric value and unit are taken from the string + * s. If s does not specify a unit and defaultUnit is not null, defaultUnit + * is used as the unit. If defaultUnit is null and s is a nonempty string + * representing a unitless number, an exception is thrown. Null or empty + * string will produce {-1,Unit#PIXELS}. + * + * @param s + * the string to be parsed + * @param defaultUnit + * The unit to be used if s does not contain any unit. Use null + * for no default unit. + * @return an object containing the parsed value and unit + */ + public static SizeWithUnit parseStringSize(String s, Unit defaultUnit) { + if (s == null) { + return null; + } + s = s.trim(); + if ("".equals(s)) { + return null; + } + float size = 0; + Unit unit = null; + Matcher matcher = sizePattern.matcher(s); + if (matcher.find()) { + size = Float.parseFloat(matcher.group(1)); + if (size < 0) { + size = -1; + unit = Unit.PIXELS; + } else { + String symbol = matcher.group(2); + if ((symbol != null && symbol.length() > 0) + || defaultUnit == null) { + unit = Unit.getUnitFromSymbol(symbol); + } else { + unit = defaultUnit; + } + } + } else { + throw new IllegalArgumentException("Invalid size argument: \"" + s + + "\" (should match " + sizePattern.pattern() + ")"); + } + return new SizeWithUnit(size, unit); + } + + /** + * Returns an object whose numeric value and unit are taken from the string + * s. Null or empty string will produce {-1,Unit#PIXELS}. An exception is + * thrown if s specifies a number without a unit. + * + * @param s + * the string to be parsed + * @return an object containing the parsed value and unit + */ + public static SizeWithUnit parseStringSize(String s) { + return parseStringSize(s, null); + } +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java index 18cd1f5fa4..1cda253b01 100644 --- a/server/src/com/vaadin/ui/AbstractComponent.java +++ b/server/src/com/vaadin/ui/AbstractComponent.java @@ -16,7 +16,6 @@ package com.vaadin.ui; -import java.io.Serializable; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; @@ -28,8 +27,6 @@ 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; @@ -46,6 +43,7 @@ import com.vaadin.server.ErrorMessage.ErrorLevel; import com.vaadin.server.Extension; import com.vaadin.server.Resource; import com.vaadin.server.Responsive; +import com.vaadin.server.SizeWithUnit; import com.vaadin.server.Sizeable; import com.vaadin.server.UserError; import com.vaadin.server.VaadinSession; @@ -100,8 +98,6 @@ public abstract class AbstractComponent extends AbstractClientConnector private float height = SIZE_UNDEFINED; private Unit widthUnit = Unit.PIXELS; private Unit heightUnit = Unit.PIXELS; - private static final Pattern sizePattern = Pattern - .compile(SharedUtil.SIZE_PATTERN); /** * Keeps track of the Actions added to this component; the actual @@ -890,7 +886,7 @@ public abstract class AbstractComponent extends AbstractClientConnector */ @Override public void setWidth(String width) { - Size size = parseStringSize(width); + SizeWithUnit size = SizeWithUnit.parseStringSize(width); if (size != null) { setWidth(size.getSize(), size.getUnit()); } else { @@ -905,7 +901,7 @@ public abstract class AbstractComponent extends AbstractClientConnector */ @Override public void setHeight(String height) { - Size size = parseStringSize(height); + SizeWithUnit size = SizeWithUnit.parseStringSize(height); if (size != null) { setHeight(size.getSize(), size.getUnit()); } else { @@ -1251,55 +1247,6 @@ public abstract class AbstractComponent extends AbstractClientConnector } /* - * Returns array with size in index 0 unit in index 1. Null or empty string - * will produce {-1,Unit#PIXELS} - */ - private static Size parseStringSize(String s) { - if (s == null) { - return null; - } - s = s.trim(); - if ("".equals(s)) { - return null; - } - float size = 0; - Unit unit = null; - Matcher matcher = sizePattern.matcher(s); - if (matcher.find()) { - size = Float.parseFloat(matcher.group(1)); - if (size < 0) { - size = -1; - unit = Unit.PIXELS; - } else { - String symbol = matcher.group(2); - unit = Unit.getUnitFromSymbol(symbol); - } - } else { - throw new IllegalArgumentException("Invalid size argument: \"" + s - + "\" (should match " + sizePattern.pattern() + ")"); - } - return new Size(size, unit); - } - - private static class Size implements Serializable { - float size; - Unit unit; - - public Size(float size, Unit unit) { - this.size = size; - this.unit = unit; - } - - public float getSize() { - return size; - } - - public Unit getUnit() { - return unit; - } - } - - /* * Actions */ diff --git a/server/src/com/vaadin/ui/AbstractSplitPanel.java b/server/src/com/vaadin/ui/AbstractSplitPanel.java index 09f881cf46..1400bcf092 100644 --- a/server/src/com/vaadin/ui/AbstractSplitPanel.java +++ b/server/src/com/vaadin/ui/AbstractSplitPanel.java @@ -18,16 +18,23 @@ package com.vaadin.ui; import java.io.Serializable; import java.lang.reflect.Method; +import java.util.Collection; import java.util.Iterator; +import org.jsoup.nodes.Element; + import com.vaadin.event.ConnectorEventListener; import com.vaadin.event.MouseEvents.ClickEvent; +import com.vaadin.server.SizeWithUnit; import com.vaadin.server.Sizeable; import com.vaadin.shared.EventId; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.ui.splitpanel.AbstractSplitPanelRpc; import com.vaadin.shared.ui.splitpanel.AbstractSplitPanelState; import com.vaadin.shared.ui.splitpanel.AbstractSplitPanelState.SplitterState; +import com.vaadin.ui.declarative.DesignAttributeHandler; +import com.vaadin.ui.declarative.DesignContext; +import com.vaadin.ui.declarative.DesignException; import com.vaadin.util.ReflectTools; /** @@ -546,4 +553,136 @@ public abstract class AbstractSplitPanel extends AbstractComponentContainer { private SplitterState getSplitterState(boolean markAsDirty) { return ((AbstractSplitPanelState) super.getState(markAsDirty)).splitterState; } + + /* + * (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) { + // handle default attributes + super.synchronizeFromDesign(design, designContext); + // handle custom attributes, use default values if no explicit value + // set + AbstractSplitPanel def = designContext.getDefaultInstance(this + .getClass()); + // There is no setter for reversed, so it will be handled using + // setSplitPosition. + boolean reversed = DesignAttributeHandler.readAttribute("reversed", + design.attributes(), def.getSplitterState().positionReversed, + Boolean.class); + if (design.hasAttr("split-position")) { + SizeWithUnit splitPosition = SizeWithUnit.parseStringSize( + design.attr("split-position"), def.getSplitPositionUnit()); + setSplitPosition(splitPosition.getSize(), splitPosition.getUnit(), + reversed); + } else { // default value for split position + setSplitPosition(def.getSplitPosition(), + def.getSplitPositionUnit(), reversed); + } + if (design.hasAttr("min-split-position")) { + SizeWithUnit minSplitPosition = SizeWithUnit.parseStringSize( + design.attr("min-split-position"), + def.getMinSplitPositionUnit()); + setMinSplitPosition(minSplitPosition.getSize(), + minSplitPosition.getUnit()); + } else { // default value for min-split-position + setMinSplitPosition(def.getMinSplitPosition(), + def.getMinSplitPositionUnit()); + } + if (design.hasAttr("max-split-position")) { + SizeWithUnit maxSplitPosition = SizeWithUnit.parseStringSize( + design.attr("max-split-position"), + def.getMaxSplitPositionUnit()); + setMaxSplitPosition(maxSplitPosition.getSize(), + maxSplitPosition.getUnit()); + } else { // default value for max-split-position + setMaxSplitPosition(def.getMaxSplitPosition(), + def.getMaxSplitPositionUnit()); + } + // remove current children + removeAllComponents(); + // handle children + if (design.children().size() > 2) { + throw new DesignException( + "A split panel can contain at most two components."); + } + for (Element childElement : design.children()) { + Component childComponent = designContext.createChild(childElement); + if (childElement.hasAttr(":second")) { + setSecondComponent(childComponent); + } else { + addComponent(childComponent); + } + } + } + + @Override + protected Collection<String> getCustomAttributes() { + Collection<String> attributes = super.getCustomAttributes(); + // the setters of the properties do not accept strings such as "20px" + attributes.add("split-position"); + attributes.add("min-split-position"); + attributes.add("max-split-position"); + // no explicit setter for reversed + attributes.add("reversed"); + return attributes; + } + + @Override + public void synchronizeToDesign(Element design, DesignContext designContext) { + // handle default attributes (also clears children and attributes) + super.synchronizeToDesign(design, designContext); + // handle custom attributes (write only if a value is not the + // default value) + AbstractSplitPanel def = designContext.getDefaultInstance(this + .getClass()); + if (getSplitPosition() != def.getSplitPosition() + || !def.getSplitPositionUnit().equals(getSplitPositionUnit())) { + String splitPositionString = asString(getSplitPosition()) + + getSplitPositionUnit(); + design.attr("split-position", splitPositionString); + } + if (getMinSplitPosition() != def.getMinSplitPosition() + || !def.getMinSplitPositionUnit().equals( + getMinSplitPositionUnit())) { + design.attr("min-split-position", asString(getMinSplitPosition()) + + getMinSplitPositionUnit()); + } + if (getMaxSplitPosition() != def.getMaxSplitPosition() + || !def.getMaxSplitPositionUnit().equals( + getMaxSplitPositionUnit())) { + design.attr("max-split-position", asString(getMaxSplitPosition()) + + getMaxSplitPositionUnit()); + } + if (getSplitterState().positionReversed) { + design.attr("reversed", ""); + } + // handle child components + Component firstComponent = getFirstComponent(); + Component secondComponent = getSecondComponent(); + if (firstComponent != null) { + Element childElement = designContext.createNode(firstComponent); + design.appendChild(childElement); + } + if (secondComponent != null) { + Element childElement = designContext.createNode(secondComponent); + if (firstComponent == null) { + childElement.attr(":second", ""); + } + design.appendChild(childElement); + } + } + + private String asString(float number) { + int truncated = (int) number; + if (truncated == number) { + return "" + truncated; + } + return "" + number; + } } |