diff options
author | Miki <miki@vaadin.com> | 2015-02-10 15:04:27 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2015-03-26 13:33:30 +0000 |
commit | ebcf64b94911597a123a599cd758e36b4abfe8bf (patch) | |
tree | ad277b227becfc75f7f7b9a0c47475db9aba0874 | |
parent | bacb87d5e42d6b52bf59f2f6781cca9b3cdc903a (diff) | |
download | vaadin-framework-ebcf64b94911597a123a599cd758e36b4abfe8bf.tar.gz vaadin-framework-ebcf64b94911597a123a599cd758e36b4abfe8bf.zip |
Fix declarative support for MenuBar (#16328)
Change-Id: Icd70a02aa8ffef9d1aca4b833ac23aeff5813771
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 |