diff options
author | Johannes Dahlström <johannesd@vaadin.com> | 2015-03-31 15:41:46 +0300 |
---|---|---|
committer | Johannes Dahlström <johannesd@vaadin.com> | 2015-04-07 15:21:50 +0300 |
commit | 8664c97c7bb6fb36b2ebbe3849b51ec00e052e24 (patch) | |
tree | 31451d8bf956cb2bfb686857f27f12e54703f67d /server/src/com/vaadin | |
parent | 0f1dcd23a0bffae76fc312d95d7b64bf7861df88 (diff) | |
download | vaadin-framework-8664c97c7bb6fb36b2ebbe3849b51ec00e052e24.tar.gz vaadin-framework-8664c97c7bb6fb36b2ebbe3849b51ec00e052e24.zip |
Fix declarative support for Window (#17314)
Change-Id: If89a46a4c08ec1491eb00a2f2b8580fb3ef785fc
Diffstat (limited to 'server/src/com/vaadin')
3 files changed, 174 insertions, 30 deletions
diff --git a/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java b/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java index 244feb3bb9..767ae66515 100644 --- a/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java +++ b/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java @@ -19,6 +19,7 @@ import java.util.Collections; import java.util.Iterator; import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; import com.vaadin.server.ComponentSizeValidator; import com.vaadin.server.VaadinService; @@ -288,17 +289,33 @@ public abstract class AbstractSingleComponentContainer extends public void readDesign(Element design, DesignContext designContext) { // process default attributes super.readDesign(design, designContext); - // handle child element, checking that the design specifies at most one - // child - int childCount = design.children().size(); - if (childCount > 1) { + readDesignChildren(design.children(), designContext); + } + + /** + * Reads the content component from the list of child elements of a design. + * The list must be empty or contain a single element; if the design + * contains multiple child elements, a DesignException is thrown. This + * method should be overridden by subclasses whose design may contain + * non-content child elements. + * + * @param children + * the child elements of the design that is being read + * @param context + * the DesignContext instance used to parse the design + * + * @throws DesignException + * if there are multiple child elements + * @throws DesignException + * if a child element could not be parsed as a Component + */ + protected void readDesignChildren(Elements children, DesignContext context) { + if (children.size() > 1) { throw new DesignException("The container of type " + getClass().toString() + " can have only one child component."); - } else if (childCount == 1) { - Element childElement = design.children().get(0); - Component newChild = designContext.readDesign(childElement); - setContent(newChild); + } else if (children.size() == 1) { + setContent(context.readDesign(children.first())); } } diff --git a/server/src/com/vaadin/ui/Window.java b/server/src/com/vaadin/ui/Window.java index 653b620746..e7764ffd8d 100644 --- a/server/src/com/vaadin/ui/Window.java +++ b/server/src/com/vaadin/ui/Window.java @@ -18,11 +18,18 @@ 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.Collections; +import java.util.Iterator; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + import com.vaadin.event.FieldEvents.BlurEvent; import com.vaadin.event.FieldEvents.BlurListener; import com.vaadin.event.FieldEvents.BlurNotifier; @@ -42,6 +49,9 @@ import com.vaadin.shared.ui.window.WindowMode; import com.vaadin.shared.ui.window.WindowRole; import com.vaadin.shared.ui.window.WindowServerRpc; import com.vaadin.shared.ui.window.WindowState; +import com.vaadin.ui.declarative.DesignAttributeHandler; +import com.vaadin.ui.declarative.DesignContext; +import com.vaadin.ui.declarative.DesignException; import com.vaadin.util.ReflectTools; /** @@ -1283,4 +1293,116 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, public String getTabStopBottomAssistiveText() { return getState(false).assistiveTabStopBottomText; } + + @Override + public void readDesign(Element design, DesignContext context) { + super.readDesign(design, context); + + if (design.hasAttr("center")) { + center(); + } + if (design.hasAttr("position")) { + String[] position = design.attr("position").split(","); + setPositionX(Integer.parseInt(position[0])); + setPositionY(Integer.parseInt(position[1])); + } + if (design.hasAttr("close-shortcut")) { + ShortcutAction shortcut = DesignAttributeHandler + .readAttribute("close-shortcut", design.attributes(), + ShortcutAction.class); + setCloseShortcut(shortcut.getKeyCode(), shortcut.getModifiers()); + } + } + + /** + * Reads the content and possible assistive descriptions from the list of + * child elements of a design. If an element has an + * {@code :assistive-description} attribute, adds the parsed component to + * the list of components used as the assistive description of this Window. + * Otherwise, sets the component as the content of this Window. If there are + * multiple non-description elements, throws a DesignException. + * + * @param children + * child elements in a design + * @param context + * the DesignContext instance used to parse the design + * + * @throws DesignException + * if there are multiple non-description child elements + * @throws DesignException + * if a child element could not be parsed as a Component + * + * @see #setContent(Component) + * @see #setAssistiveDescription(Component...) + */ + @Override + protected void readDesignChildren(Elements children, DesignContext context) { + List<Component> descriptions = new ArrayList<Component>(); + Elements content = new Elements(); + + for (Element child : children) { + if (child.hasAttr(":assistive-description")) { + descriptions.add(context.readDesign(child)); + } else { + content.add(child); + } + } + super.readDesignChildren(content, context); + setAssistiveDescription(descriptions.toArray(new Component[0])); + } + + @Override + public void writeDesign(Element design, DesignContext context) { + super.writeDesign(design, context); + + Window def = context.getDefaultInstance(this); + + if (getState().centered) { + design.attr("center", ""); + } + + DesignAttributeHandler.writeAttribute("position", design.attributes(), + getPosition(), def.getPosition(), String.class); + + CloseShortcut shortcut = getCloseShortcut(); + if (shortcut != null) { + // TODO What if several close shortcuts?? + + CloseShortcut defShortcut = def.getCloseShortcut(); + if (defShortcut == null + || shortcut.getKeyCode() != defShortcut.getKeyCode() + || !Arrays.equals(shortcut.getModifiers(), + defShortcut.getModifiers())) { + DesignAttributeHandler.writeAttribute("close-shortcut", + design.attributes(), shortcut, null, + CloseShortcut.class); + } + } + + for (Component c : getAssistiveDescription()) { + Element child = context.createElement(c).attr( + ":assistive-description", ""); + design.appendChild(child); + } + } + + private String getPosition() { + return getPositionX() + "," + getPositionY(); + } + + private CloseShortcut getCloseShortcut() { + Iterator<CloseShortcut> i = getCloseShortcuts().iterator(); + return i.hasNext() ? i.next() : null; + } + + @Override + protected Collection<String> getCustomAttributes() { + Collection<String> result = super.getCustomAttributes(); + result.add("center"); + result.add("position"); + result.add("position-y"); + result.add("position-x"); + result.add("close-shortcut"); + return result; + } } diff --git a/server/src/com/vaadin/ui/declarative/converters/DesignShortcutActionConverter.java b/server/src/com/vaadin/ui/declarative/converters/DesignShortcutActionConverter.java index e2b6ed8e14..d6f2f65938 100644 --- a/server/src/com/vaadin/ui/declarative/converters/DesignShortcutActionConverter.java +++ b/server/src/com/vaadin/ui/declarative/converters/DesignShortcutActionConverter.java @@ -126,32 +126,37 @@ public class DesignShortcutActionConverter implements if (value.length() == 0) { return null; } - String[] data = value.split(" ", 2); + String[] data = value.split(" ", 2); String[] parts = data[0].split("-"); - // handle keycode - String keyCodePart = parts[parts.length - 1]; - int keyCode = getKeycodeForString(keyCodePart); - if (keyCode < 0) { - throw new IllegalArgumentException("Invalid shortcut definition " - + value); - } - // handle modifiers - int[] modifiers = null; - if (parts.length > 1) { - modifiers = new int[parts.length - 1]; - } - for (int i = 0; i < parts.length - 1; i++) { - int modifier = getKeycodeForString(parts[i]); - if (modifier > 0) { - modifiers[i] = modifier; - } else { - throw new IllegalArgumentException( - "Invalid shortcut definition " + value); + + try { + // handle keycode + String keyCodePart = parts[parts.length - 1]; + int keyCode = getKeycodeForString(keyCodePart); + if (keyCode < 0) { + throw new IllegalArgumentException("Invalid key '" + + keyCodePart + "'"); + } + // handle modifiers + int[] modifiers = null; + if (parts.length > 1) { + modifiers = new int[parts.length - 1]; + } + for (int i = 0; i < parts.length - 1; i++) { + int modifier = getKeycodeForString(parts[i]); + if (modifier > 0) { + modifiers[i] = modifier; + } else { + throw new IllegalArgumentException("Invalid modifier '" + + parts[i] + "'"); + } } + return new ShortcutAction(data.length == 2 ? data[1] : null, + keyCode, modifiers); + } catch (Exception e) { + throw new ConversionException("Invalid shortcut '" + value + "'", e); } - return new ShortcutAction(data.length == 2 ? data[1] : null, keyCode, - modifiers); } @Override |