aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiki <miki@vaadin.com>2015-02-10 15:04:27 +0200
committerVaadin Code Review <review@vaadin.com>2015-03-26 13:33:30 +0000
commitebcf64b94911597a123a599cd758e36b4abfe8bf (patch)
treead277b227becfc75f7f7b9a0c47475db9aba0874
parentbacb87d5e42d6b52bf59f2f6781cca9b3cdc903a (diff)
downloadvaadin-framework-ebcf64b94911597a123a599cd758e36b4abfe8bf.tar.gz
vaadin-framework-ebcf64b94911597a123a599cd758e36b4abfe8bf.zip
Fix declarative support for MenuBar (#16328)
Change-Id: Icd70a02aa8ffef9d1aca4b833ac23aeff5813771
-rw-r--r--server/src/com/vaadin/ui/MenuBar.java153
-rw-r--r--server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java5
-rw-r--r--server/tests/src/com/vaadin/tests/components/menubar/MenuBarDeclarativeTest.java139
3 files changed, 293 insertions, 4 deletions
diff --git a/server/src/com/vaadin/ui/MenuBar.java b/server/src/com/vaadin/ui/MenuBar.java
index 6b6555c0a2..747ce42727 100644
--- a/server/src/com/vaadin/ui/MenuBar.java
+++ b/server/src/com/vaadin/ui/MenuBar.java
@@ -17,17 +17,25 @@ package com.vaadin.ui;
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
+import org.jsoup.nodes.Attributes;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
+import org.jsoup.parser.Tag;
+
import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import com.vaadin.server.Resource;
import com.vaadin.shared.ui.menubar.MenuBarConstants;
import com.vaadin.shared.ui.menubar.MenuBarState;
import com.vaadin.ui.Component.Focusable;
+import com.vaadin.ui.declarative.DesignAttributeHandler;
+import com.vaadin.ui.declarative.DesignContext;
/**
* <p>
@@ -932,7 +940,150 @@ public class MenuBar extends AbstractComponent implements LegacyComponent,
this.checked = checked;
markAsDirty();
}
-
}// class MenuItem
+ @Override
+ public void writeDesign(Element design, DesignContext designContext) {
+ super.writeDesign(design, designContext);
+ for (MenuItem item : getItems()) {
+ design.appendChild(createMenuElement(item));
+ }
+
+ // in many cases there seems to be an empty more menu item
+ if (getMoreMenuItem() != null && !getMoreMenuItem().getText().isEmpty()) {
+ Element moreMenu = createMenuElement(getMoreMenuItem());
+ moreMenu.attr("more", "");
+ design.appendChild(moreMenu);
+ }
+
+ if (!htmlContentAllowed) {
+ design.attr(DESIGN_ATTR_PLAIN_TEXT, "");
+ }
+ }
+
+ protected Element createMenuElement(MenuItem item) {
+ Element menuElement = new Element(Tag.valueOf("menu"), "");
+ // Defaults
+ MenuItem def = new MenuItem("", null, null);
+
+ Attributes attr = menuElement.attributes();
+ DesignAttributeHandler.writeAttribute("icon", attr, item.getIcon(),
+ def.getIcon(), Resource.class);
+ DesignAttributeHandler.writeAttribute("disabled", attr,
+ !item.isEnabled(), !def.isEnabled(), boolean.class);
+ DesignAttributeHandler.writeAttribute("visible", attr,
+ item.isVisible(), def.isVisible(), boolean.class);
+ DesignAttributeHandler.writeAttribute("separator", attr,
+ item.isSeparator(), def.isSeparator(), boolean.class);
+ DesignAttributeHandler.writeAttribute("checkable", attr,
+ item.isCheckable(), def.isCheckable(), boolean.class);
+ DesignAttributeHandler.writeAttribute("checked", attr,
+ item.isChecked(), def.isChecked(), boolean.class);
+ DesignAttributeHandler.writeAttribute("description", attr,
+ item.getDescription(), def.getDescription(), String.class);
+ DesignAttributeHandler.writeAttribute("style-name", attr,
+ item.getStyleName(), def.getStyleName(), String.class);
+
+ menuElement.append(item.getText());
+
+ if (item.hasChildren()) {
+ for (MenuItem subMenu : item.getChildren()) {
+ menuElement.appendChild(createMenuElement(subMenu));
+ }
+ }
+
+ return menuElement;
+ }
+
+ protected MenuItem readMenuElement(Element menuElement) {
+ Resource icon = null;
+ if (menuElement.hasAttr("icon")) {
+ icon = DesignAttributeHandler.getFormatter().parse(
+ menuElement.attr("icon"), Resource.class);
+ }
+
+ String caption = "";
+ List<Element> subMenus = new ArrayList<Element>();
+ for (Node node : menuElement.childNodes()) {
+ if (node instanceof Element
+ && ((Element) node).tagName().equals("menu")) {
+ subMenus.add((Element) node);
+ }
+ caption += node.toString();
+ }
+ MenuItem menu = new MenuItem(caption.trim(), icon, null);
+
+ Attributes attr = menuElement.attributes();
+ if (menuElement.hasAttr("icon")) {
+ menu.setIcon(DesignAttributeHandler.readAttribute("icon", attr,
+ Resource.class));
+ }
+ if (menuElement.hasAttr("disabled")) {
+ menu.setEnabled(!DesignAttributeHandler.readAttribute("disabled",
+ attr, boolean.class));
+ }
+ if (menuElement.hasAttr("visible")) {
+ menu.setVisible(DesignAttributeHandler.readAttribute("visible",
+ attr, boolean.class));
+ }
+ if (menuElement.hasAttr("separator")) {
+ menu.setSeparator(DesignAttributeHandler.readAttribute("separator",
+ attr, boolean.class));
+ }
+ if (menuElement.hasAttr("checkable")) {
+ menu.setCheckable(DesignAttributeHandler.readAttribute("checkable",
+ attr, boolean.class));
+ }
+ if (menuElement.hasAttr("checked")) {
+ menu.setChecked(DesignAttributeHandler.readAttribute("checked",
+ attr, boolean.class));
+ }
+ if (menuElement.hasAttr("description")) {
+ menu.setDescription(DesignAttributeHandler.readAttribute(
+ "description", attr, String.class));
+ }
+ if (menuElement.hasAttr("style-name")) {
+ menu.setStyleName(DesignAttributeHandler.readAttribute(
+ "style-name", attr, String.class));
+ }
+
+ if (!subMenus.isEmpty()) {
+ menu.itsChildren = new ArrayList<MenuItem>();
+ }
+
+ for (Element subMenu : subMenus) {
+ MenuItem newItem = readMenuElement(subMenu);
+
+ newItem.setParent(menu);
+ menu.itsChildren.add(newItem);
+ }
+
+ return menu;
+ }
+
+ @Override
+ public void readDesign(Element design, DesignContext designContext) {
+ super.readDesign(design, designContext);
+
+ for (Element itemElement : design.children()) {
+ if (itemElement.tagName().equals("menu")) {
+ MenuItem menuItem = readMenuElement(itemElement);
+ if (itemElement.hasAttr("more")) {
+ setMoreMenuItem(menuItem);
+ } else {
+ menuItems.add(menuItem);
+ }
+ }
+ }
+
+ setHtmlContentAllowed(!design.hasAttr(DESIGN_ATTR_PLAIN_TEXT));
+ }
+
+ @Override
+ protected Collection<String> getCustomAttributes() {
+ Collection<String> result = super.getCustomAttributes();
+ result.add(DESIGN_ATTR_PLAIN_TEXT);
+ result.add("html-content-allowed");
+ return result;
+ }
}// class MenuBar
diff --git a/server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java b/server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java
index 215afd5041..2b446bda0e 100644
--- a/server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java
+++ b/server/src/com/vaadin/ui/declarative/DesignAttributeHandler.java
@@ -38,7 +38,6 @@ import org.jsoup.nodes.Node;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.shared.util.SharedUtil;
-import com.vaadin.ui.Component;
/**
* Default attribute handler implementation used when parsing designs to
@@ -192,8 +191,8 @@ public class DesignAttributeHandler implements Serializable {
* @param defaultInstance
* the default instance for comparing default values
*/
- public static void writeAttribute(Component component, String attribute,
- Attributes attr, Component defaultInstance) {
+ public static void writeAttribute(Object component, String attribute,
+ Attributes attr, Object defaultInstance) {
Method getter = findGetterForAttribute(component.getClass(), attribute);
if (getter == null) {
getLogger().warning(
diff --git a/server/tests/src/com/vaadin/tests/components/menubar/MenuBarDeclarativeTest.java b/server/tests/src/com/vaadin/tests/components/menubar/MenuBarDeclarativeTest.java
new file mode 100644
index 0000000000..e6dee44812
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/components/menubar/MenuBarDeclarativeTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.components.menubar;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
+import com.vaadin.server.ExternalResource;
+import com.vaadin.server.ThemeResource;
+import com.vaadin.tests.design.DeclarativeTestBase;
+import com.vaadin.ui.MenuBar;
+import com.vaadin.ui.MenuBar.MenuItem;
+
+/**
+ * Tests declarative support for menu bars.
+ *
+ * @since 7.4
+ * @author Vaadin Ltd
+ */
+public class MenuBarDeclarativeTest extends DeclarativeTestBase<MenuBar> {
+
+ @Test
+ // #16328
+ public void testReadWrite() throws IOException {
+ String design = "<v-menu-bar auto-open='true' tabindex=5>"
+ + "<menu checkable='true'>Save</menu>"
+ + "<menu description='Open a file'>Open</menu>"
+ + "<menu disabled='true'>Close</menu>"
+ + "<menu icon='http://foo.bar/ico.png'>Help</menu>"
+ + "<menu visible='false'>About</menu>"
+ + "<menu>Sub<menu>Item</menu></menu>"
+ + "<menu more>WTF?!</menu>" + "</v-menu-bar>";
+ MenuBar bar = new MenuBar();
+ bar.setAutoOpen(true);
+ bar.setHtmlContentAllowed(true);
+ bar.setTabIndex(5);
+
+ bar.addItem("Save", null).setCheckable(true);
+ bar.addItem("Open", null).setDescription("Open a file");
+ bar.addItem("Close", null).setEnabled(false);
+ bar.addItem("Help", null).setIcon(
+ new ExternalResource("http://foo.bar/ico.png"));
+ bar.addItem("About", null).setVisible(false);
+
+ bar.addItem("Sub", null).addItem("Item", null);
+
+ bar.setMoreMenuItem(bar.new MenuItem("WTF?!", null, null));
+
+ testWrite(design, bar);
+ testRead(design, bar);
+ }
+
+ @Test
+ // #16328
+ public void testTicketSpec1() throws IOException {
+ String design = "<v-menu-bar auto-open='true' plain-text tabindex=5> "
+ + "<menu>File"
+ + "<menu>Save</menu>"
+ + "<menu icon=\"theme://../runo/icons/16/folder.png\">Open</menu>"
+ + "<menu separator='true' />"
+ + "<menu disabled='true'>Exit</menu>"
+ + "<menu visible='false'>Not for everybody</menu>"
+ + "</menu>"
+ + "<menu description=\"This contains many items in sub menus\">Other"
+ + "<menu style-name=\"fancy\">Sub"
+ + "<menu checkable='true' checked='true'>Option 1 - no <b>html</b></menu>"
+ + "<menu checkable='true'>Option 2</menu>"
+ + "<menu checkable='true'>Option 3</menu>" //
+ + "</menu>" //
+ + "</menu>" //
+ + "<menu more icon=\"theme://icon.png\">foo</menu>"
+ + "</v-menu-bar>";
+ // for one reason or another, no component has a correct .equals
+ // implementation, which makes tests a bit annoying
+ MenuBar menuBar = new MenuBar();
+ menuBar.setHtmlContentAllowed(false);
+ menuBar.setTabIndex(5);
+ menuBar.setAutoOpen(true);
+ // File menu
+ MenuItem fileMenu = menuBar.addItem("File", null);
+ fileMenu.addItem("Save", null);
+ fileMenu.addItem("Open", new ThemeResource(
+ "../runo/icons/16/folder.png"), null);
+ fileMenu.addSeparator();
+ fileMenu.addItem("Exit", null).setEnabled(false);
+ fileMenu.addItem("Not for everybody", null).setVisible(false);
+ MenuItem otherMenu = menuBar.addItem("Other", null);
+ otherMenu.setDescription("This contains many items in sub menus");
+ MenuItem subMenu = otherMenu.addItem("Sub", null);
+ subMenu.setStyleName("fancy");
+ MenuItem option1 = subMenu.addItem("Option 1 - no <b>html</b>", null);
+ option1.setCheckable(true);
+ option1.setChecked(true);
+ subMenu.addItem("Option 2", null).setCheckable(true);
+ subMenu.addItem("Option 3", null).setCheckable(true);
+ menuBar.setMoreMenuItem(null);
+ MenuItem moreMenu = menuBar.getMoreMenuItem();
+ moreMenu.setIcon(new ThemeResource("icon.png"));
+ moreMenu.setText("foo");
+ testRead(design, menuBar);
+ testWrite(design, menuBar);
+ }
+
+ @Test
+ // #16328
+ public void testTicketSpec2() throws IOException {
+ String design = "<v-menu-bar>"
+ + "<menu><b>File</b>"
+ + "<menu><font style=\"color: red\">Save</font></menu>"
+ + "<menu icon=\"theme://../runo/icons/16/folder.png\">Open</menu>"
+ + "<menu separator='true' />"
+ + "<menu disabled='true'>Exit</menu>" //
+ + "</menu></v-menu-bar>";
+ MenuBar menuBar = new MenuBar();
+ menuBar.setHtmlContentAllowed(true);
+ MenuItem fileMenu = menuBar.addItem("<b>File</b>", null);
+ fileMenu.addItem("<font style='color: red'>Save</font>", null);
+ fileMenu.addItem("Open", new ThemeResource(
+ "../runo/icons/16/folder.png"), null);
+ fileMenu.addSeparator();
+ fileMenu.addItem("Exit", null).setEnabled(false);
+ testRead(design, menuBar);
+ testWrite(design, menuBar);
+ }
+} \ No newline at end of file