Selaa lähdekoodia

Declarative support for Button and NativeButton (#7749)

Change-Id: I2a72e5001dbee4b6396344a0286ea4aa042e15aa
tags/7.4.0.beta1
Matti Hosio 9 vuotta sitten
vanhempi
commit
7a73e9bd3b

+ 42
- 0
server/src/com/vaadin/ui/Button.java Näytä tiedosto

@@ -20,6 +20,7 @@ import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collection;

import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;

import com.vaadin.event.Action;
@@ -38,6 +39,7 @@ import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.button.ButtonServerRpc;
import com.vaadin.shared.ui.button.ButtonState;
import com.vaadin.ui.Component.Focusable;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
import com.vaadin.util.ReflectTools;

@@ -675,8 +677,25 @@ public class Button extends AbstractComponent implements
public void synchronizeFromDesign(Element design,
DesignContext designContext) {
super.synchronizeFromDesign(design, designContext);
Button def = designContext.getDefaultInstance(this.getClass());
Attributes attr = design.attributes();
String content = design.html();
setCaption(content);
// tabindex
setTabIndex(DesignAttributeHandler.readAttribute("tabindex", attr,
def.getTabIndex(), Integer.class));
// plain-text (default is html)
setHtmlContentAllowed(!DesignAttributeHandler.readAttribute(
"plain-text", attr, false, Boolean.class));
setIconAlternateText(DesignAttributeHandler.readAttribute("icon-alt",
attr, def.getIconAlternateText(), String.class));
// click-shortcut
removeClickShortcut();
ShortcutAction action = DesignAttributeHandler.readAttribute(
"click-shortcut", attr, null, ShortcutAction.class);
if (action != null) {
setClickShortcut(action.getKeyCode(), action.getModifiers());
}
}

/*
@@ -687,7 +706,12 @@ public class Button extends AbstractComponent implements
@Override
protected Collection<String> getCustomAttributes() {
Collection<String> result = super.getCustomAttributes();
result.add("tabindex");
result.add("plain-text");
result.add("caption");
result.add("icon-alt");
result.add("click-shortcut");
result.add("html-content-allowed");
return result;
}

@@ -701,9 +725,27 @@ public class Button extends AbstractComponent implements
@Override
public void synchronizeToDesign(Element design, DesignContext designContext) {
super.synchronizeToDesign(design, designContext);
Attributes attr = design.attributes();
Button def = designContext.getDefaultInstance(this.getClass());
String content = getCaption();
if (content != null) {
design.html(content);
}
// tabindex
DesignAttributeHandler.writeAttribute("tabindex", attr, getTabIndex(),
def.getTabIndex(), Integer.class);
// plain-text (default is html)
if (!isHtmlContentAllowed()) {
design.attr("plain-text", "");
}
// icon-alt
DesignAttributeHandler.writeAttribute("icon-alt", attr,
getIconAlternateText(), def.getIconAlternateText(),
String.class);
// click-shortcut
if (clickShortcut != null) {
DesignAttributeHandler.writeAttribute("click-shortcut", attr,
clickShortcut, null, ShortcutAction.class);
}
}
}

+ 168
- 3
server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java Näytä tiedosto

@@ -40,6 +40,9 @@ import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;

import com.vaadin.event.ShortcutAction;
import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutAction.ModifierKey;
import com.vaadin.server.ExternalResource;
import com.vaadin.server.FileResource;
import com.vaadin.server.FontAwesome;
@@ -316,7 +319,6 @@ public class DesignAttributeHandler implements Serializable {
* 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
@@ -325,6 +327,64 @@ public class DesignAttributeHandler implements Serializable {
return getDecimalFormat().format(number);
}

/**
* Convert ShortcutAction to attribute string presentation
*
* @param shortcut
* the shortcut action
* @return the action as attribute string presentation
*/
private static String formatShortcutAction(ShortcutAction shortcut) {
StringBuilder sb = new StringBuilder();
// handle modifiers
if (shortcut.getModifiers() != null) {
for (int modifier : shortcut.getModifiers()) {
sb.append(ShortcutKeyMapper.getStringForKeycode(modifier))
.append("-");
}
}
// handle keycode
sb.append(ShortcutKeyMapper.getStringForKeycode(shortcut.getKeyCode()));
return sb.toString();
}

/**
* Reads shortcut action from attribute presentation
*
* @param attributeValue
* attribute presentation of shortcut action
* @return shortcut action with keycode and modifier keys from attribute
* value
*/
private static ShortcutAction readShortcutAction(String attributeValue) {
if (attributeValue.length() == 0) {
return null;
}
String[] parts = attributeValue.split("-");
// handle keycode
String keyCodePart = parts[parts.length - 1];
int keyCode = ShortcutKeyMapper.getKeycodeForString(keyCodePart);
if (keyCode < 0) {
throw new IllegalArgumentException("Invalid shortcut definition "
+ attributeValue);
}
// 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 = ShortcutKeyMapper.getKeycodeForString(parts[i]);
if (modifier > 0) {
modifiers[i] = modifier;
} else {
throw new IllegalArgumentException(
"Invalid shortcut definition " + attributeValue);
}
}
return new ShortcutAction(null, keyCode, modifiers);
}

/**
* Creates the decimal format used when writing attributes to the design
*
@@ -407,6 +467,9 @@ public class DesignAttributeHandler implements Serializable {
return Enum.valueOf((Class<? extends Enum>) targetType,
value.toUpperCase());
}
if (targetType == ShortcutAction.class) {
return readShortcutAction(value);
}
return null;
}

@@ -449,9 +512,10 @@ public class DesignAttributeHandler implements Serializable {
return formatFloat(((Float) value).floatValue());
} else if (sourceType == Double.class || sourceType == Double.TYPE) {
return formatDouble(((Double) value).doubleValue());
} else if (sourceType == ShortcutAction.class) {
return formatShortcutAction((ShortcutAction) value);
} else {
return value.toString();

}
}

@@ -510,7 +574,8 @@ public class DesignAttributeHandler implements Serializable {
private static final List<Class<?>> supportedClasses = Arrays
.asList(new Class<?>[] { String.class, Boolean.class,
Integer.class, Byte.class, Short.class, Long.class,
Character.class, Float.class, Double.class, Resource.class });
Character.class, Float.class, Double.class, Resource.class,
ShortcutAction.class });

/**
* Returns true if the specified value type is supported by this class.
@@ -562,4 +627,104 @@ public class DesignAttributeHandler implements Serializable {
}
}

/**
* Provides mappings between shortcut keycodes and their representation in
* design attributes
*
* @since 7.4
* @author Vaadin Ltd
*/
private static class ShortcutKeyMapper implements Serializable {

private static Map<Integer, String> keyCodeMap = Collections
.synchronizedMap(new HashMap<Integer, String>());
private static Map<String, Integer> presentationMap = Collections
.synchronizedMap(new HashMap<String, Integer>());

static {
// map modifiers
mapKey(ModifierKey.ALT, "alt");
mapKey(ModifierKey.CTRL, "ctrl");
mapKey(ModifierKey.META, "meta");
mapKey(ModifierKey.SHIFT, "shift");
// map keys
mapKey(KeyCode.ENTER, "enter");
mapKey(KeyCode.ESCAPE, "escape");
mapKey(KeyCode.PAGE_UP, "pageup");
mapKey(KeyCode.PAGE_DOWN, "pagedown");
mapKey(KeyCode.TAB, "tab");
mapKey(KeyCode.ARROW_LEFT, "left");
mapKey(KeyCode.ARROW_UP, "up");
mapKey(KeyCode.ARROW_RIGHT, "right");
mapKey(KeyCode.ARROW_DOWN, "down");
mapKey(KeyCode.BACKSPACE, "backspace");
mapKey(KeyCode.DELETE, "delete");
mapKey(KeyCode.INSERT, "insert");
mapKey(KeyCode.END, "end");
mapKey(KeyCode.HOME, "home");
mapKey(KeyCode.F1, "f1");
mapKey(KeyCode.F2, "f2");
mapKey(KeyCode.F3, "f3");
mapKey(KeyCode.F4, "f4");
mapKey(KeyCode.F5, "f5");
mapKey(KeyCode.F6, "f6");
mapKey(KeyCode.F7, "f7");
mapKey(KeyCode.F8, "f8");
mapKey(KeyCode.F9, "f9");
mapKey(KeyCode.F10, "f10");
mapKey(KeyCode.F11, "f11");
mapKey(KeyCode.F12, "f12");
mapKey(KeyCode.NUM0, "0");
mapKey(KeyCode.NUM1, "1");
mapKey(KeyCode.NUM2, "2");
mapKey(KeyCode.NUM3, "3");
mapKey(KeyCode.NUM4, "4");
mapKey(KeyCode.NUM5, "5");
mapKey(KeyCode.NUM6, "6");
mapKey(KeyCode.NUM7, "7");
mapKey(KeyCode.NUM8, "8");
mapKey(KeyCode.NUM9, "9");
mapKey(KeyCode.SPACEBAR, "spacebar");
mapKey(KeyCode.A, "a");
mapKey(KeyCode.B, "b");
mapKey(KeyCode.C, "c");
mapKey(KeyCode.D, "d");
mapKey(KeyCode.E, "e");
mapKey(KeyCode.F, "f");
mapKey(KeyCode.G, "g");
mapKey(KeyCode.H, "h");
mapKey(KeyCode.I, "i");
mapKey(KeyCode.J, "j");
mapKey(KeyCode.K, "k");
mapKey(KeyCode.L, "l");
mapKey(KeyCode.M, "m");
mapKey(KeyCode.N, "n");
mapKey(KeyCode.O, "o");
mapKey(KeyCode.P, "p");
mapKey(KeyCode.Q, "q");
mapKey(KeyCode.R, "r");
mapKey(KeyCode.S, "s");
mapKey(KeyCode.T, "t");
mapKey(KeyCode.U, "u");
mapKey(KeyCode.V, "v");
mapKey(KeyCode.X, "x");
mapKey(KeyCode.Y, "y");
mapKey(KeyCode.Z, "z");
}

private static void mapKey(int keyCode, String presentation) {
keyCodeMap.put(keyCode, presentation);
presentationMap.put(presentation, keyCode);
}

private static int getKeycodeForString(String attributePresentation) {
Integer code = presentationMap.get(attributePresentation);
return code != null ? code.intValue() : -1;
}

private static String getStringForKeycode(int keyCode) {
return keyCodeMap.get(keyCode);
}
}

}

+ 4
- 0
server/tests/src/com/vaadin/tests/layoutparser/all-components.html Näytä tiedosto

@@ -46,6 +46,10 @@
<v-password-field null-representation="" null-setting-allowed maxlength=10 columns=5 input-prompt="Please enter a value" text-change-event-mode="eager" text-change-timeout=2 value="foo" />
<!-- text area -->
<v-text-area rows=5 wordwrap=false >test value</v-text-area>
<!-- button -->
<v-button click-shortcut="ctrl-shift-o" disable-on-click tabindex=1 icon="http://vaadin.com/image.png" icon-alt="ok" plain-text>OK</v-button>
<!-- native button -->
<v-button click-shortcut="ctrl-shift-o" disable-on-click tabindex=1 icon="http://vaadin.com/image.png" icon-alt="ok" plain-text>OK</v-button>
<!-- tabsheet -->
<v-tab-sheet tabindex=5>

+ 3
- 1
server/tests/src/com/vaadin/tests/server/component/abstractcomponent/TestSynchronizeToDesign.java Näytä tiedosto

@@ -246,7 +246,9 @@ public class TestSynchronizeToDesign extends TestCase {
}

private AbstractComponent getComponent() {
return new Button();
Button button = new Button();
button.setHtmlContentAllowed(true);
return button;
}

private AbstractComponent getPanel() {

+ 30
- 0
server/tests/src/com/vaadin/tests/server/component/button/TestSynchronizeFromDesign.java Näytä tiedosto

@@ -15,6 +15,8 @@
*/
package com.vaadin.tests.server.component.button;

import java.lang.reflect.Field;

import junit.framework.TestCase;

import org.jsoup.nodes.Attributes;
@@ -22,7 +24,10 @@ import org.jsoup.nodes.Element;
import org.jsoup.parser.Tag;
import org.junit.Test;

import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutAction.ModifierKey;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickShortcut;
import com.vaadin.ui.NativeButton;
import com.vaadin.ui.declarative.DesignContext;

@@ -62,6 +67,27 @@ public class TestSynchronizeFromDesign extends TestCase {
createAndTestButtons(null, "Click me");
}

@Test
public void testAttributes() throws IllegalArgumentException,
SecurityException, IllegalAccessException, NoSuchFieldException {
Attributes attributes = new Attributes();
attributes.put("tabindex", "3");
attributes.put("plain-text", "");
attributes.put("icon-alt", "OK");
attributes.put("click-shortcut", "ctrl-shift-o");
Button button = (Button) ctx
.createChild(createButtonWithAttributes(attributes));
assertEquals(3, button.getTabIndex());
assertEquals(false, button.isHtmlContentAllowed());
assertEquals("OK", button.getIconAlternateText());
Field field = Button.class.getDeclaredField("clickShortcut");
field.setAccessible(true);
ClickShortcut value = (ClickShortcut) field.get(button);
assertEquals(KeyCode.O, value.getKeyCode());
assertEquals(ModifierKey.CTRL, value.getModifiers()[0]);
assertEquals(ModifierKey.SHIFT, value.getModifiers()[1]);
}

/*
* Test both Button and NativeButton. Caption should always be ignored. If
* content is null, the created button should have empty content.
@@ -84,6 +110,10 @@ public class TestSynchronizeFromDesign extends TestCase {
}
}

private Element createButtonWithAttributes(Attributes attributes) {
return new Element(Tag.valueOf("v-button"), "", attributes);
}

private Element createElement(String elementName, String content,
String caption) {
Attributes attributes = new Attributes();

+ 22
- 0
server/tests/src/com/vaadin/tests/server/component/button/TestSynchronizeToDesign.java Näytä tiedosto

@@ -17,9 +17,13 @@ package com.vaadin.tests.server.component.button;

import junit.framework.TestCase;

import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Tag;
import org.junit.Test;

import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutAction.ModifierKey;
import com.vaadin.ui.Button;
import com.vaadin.ui.NativeButton;
import com.vaadin.ui.declarative.DesignContext;
@@ -48,8 +52,25 @@ public class TestSynchronizeToDesign extends TestCase {
createAndTestButtons("<b>Click</b>");
}

@Test
public void testAttributes() {
Button button = new Button();
button.setTabIndex(3);
button.setIconAlternateText("OK");
button.setClickShortcut(KeyCode.O, ModifierKey.CTRL, ModifierKey.SHIFT);
Element e = new Element(Tag.valueOf("v-button"), "", new Attributes());
button.synchronizeToDesign(e, ctx);
assertEquals("3", e.attr("tabindex"));
assertTrue("Button is plain text by default", e.hasAttr("plain-text"));
assertEquals("OK", e.attr("icon-alt"));
assertEquals("ctrl-shift-o", e.attr("click-shortcut"));
}

private void createAndTestButtons(String content) {
Button b1 = new Button(content);
// we need to set this on, since the plain-text attribute will appear
// otherwise
b1.setHtmlContentAllowed(true);
Element e1 = ctx.createNode(b1);
assertEquals("Wrong tag name for button.", "v-button", e1.tagName());
assertEquals("Unexpected content in the v-button element.", content,
@@ -57,6 +78,7 @@ public class TestSynchronizeToDesign extends TestCase {
assertTrue("The v-button element should not have attributes.", e1
.attributes().size() == 0);
NativeButton b2 = new NativeButton(content);
b2.setHtmlContentAllowed(true);
Element e2 = ctx.createNode(b2);
assertEquals("Wrong tag name for button.", "v-native-button",
e2.tagName());

Loading…
Peruuta
Tallenna