diff options
11 files changed, 625 insertions, 1 deletions
diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/ContextMenuClientRpc.java b/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/ContextMenuClientRpc.java new file mode 100644 index 0000000000..319695686c --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/ContextMenuClientRpc.java @@ -0,0 +1,13 @@ +package com.vaadin.tests.widgetset.client.contextmenu; + +import com.vaadin.shared.communication.ClientRpc; + +public interface ContextMenuClientRpc extends ClientRpc { + /** + * Sends request to client widget to open context menu to given position. + * + * @param x + * @param y + */ + public void showContextMenu(int x, int y); +} diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/ContextMenuConnector.java b/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/ContextMenuConnector.java new file mode 100644 index 0000000000..b6514011d5 --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/ContextMenuConnector.java @@ -0,0 +1,120 @@ +package com.vaadin.tests.widgetset.client.contextmenu; + +import java.util.logging.Logger; + +import com.vaadin.client.ServerConnector; +import com.vaadin.client.communication.StateChangeEvent; +import com.vaadin.client.extensions.AbstractExtensionConnector; +import com.vaadin.client.ui.VMenuBar.CustomMenuItem; +import com.vaadin.client.ui.menubar.MenuBarConnector; +import com.vaadin.shared.ui.Connect; +import com.vaadin.tests.widgetset.contextmenu.ContextMenu; + +@SuppressWarnings("serial") +@Connect(ContextMenu.class) +public class ContextMenuConnector extends AbstractExtensionConnector { + @SuppressWarnings("unused") + private static Logger logger = Logger.getLogger("ContextMenuConnector"); + + private MenuBarConnector innerConnector = new MenuBarConnector() { + @Override + public VContextMenuBar getWidget() { + // todo another class? + return (VContextMenuBar) super.getWidget(); + } + }; + private VContextMenuBar contextMenuWidget = (VContextMenuBar) innerConnector + .getWidget(); + + @Override + public ContextMenuState getState() { + return (ContextMenuState) super.getState(); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + innerConnector.onStateChanged(stateChangeEvent); + } + + @Override + protected void init() { + super.init(); + innerConnector.doInit(getConnectorId(), getConnection()); + contextMenuWidget.setPixelSize(0, 0); + /* + * CustomMenuItem item = GWT.create(CustomMenuItem.class); + * dummyRootMenuBar.getItems().add(item); + * + * contextMenuWidget = new MyVMenuBar(true, dummyRootMenuBar); + * contextMenuWidget.setConnection(getConnection()); + * item.setSubMenu(contextMenuWidget); + */ + + registerRpc(ContextMenuClientRpc.class, new ContextMenuClientRpc() { + @Override + public void showContextMenu(int x, int y) { + showMenu(x, y); + } + }); + + /* + * Event.addNativePreviewHandler(new NativePreviewHandler() { + * + * @Override public void onPreviewNativeEvent(NativePreviewEvent event) + * { if (event.getTypeInt() == Event.ONKEYDOWN && + * contextMenuWidget.isPopupShowing()) { boolean handled = + * contextMenuWidget.handleNavigation( + * event.getNativeEvent().getKeyCode(), + * event.getNativeEvent().getCtrlKey(), + * event.getNativeEvent().getShiftKey()); + * + * if (handled) { event.cancel(); } } } }); + */ + } + + private void showMenu(int eventX, int eventY) { + + if (contextMenuWidget.getItems().size() == 0) { + return; + } + CustomMenuItem firstItem = innerConnector.getWidget().getItems().get(0); + contextMenuWidget.setSelected(firstItem); + contextMenuWidget.showChildMenuAt(firstItem, eventY, eventX); + } + + @Override + protected void extend(ServerConnector target) { + Logger.getLogger("ContextMenuConnector").info("extend"); + + // Widget widget = ((AbstractComponentConnector) target).getWidget(); + + // widget.addDomHandler(new ContextMenuHandler() { + // + // @Override + // public void onContextMenu(ContextMenuEvent event) { + // event.stopPropagation(); + // event.preventDefault(); + // + // showMenu(event.getNativeEvent().getClientX(), event + // .getNativeEvent().getClientY()); + // } + // }, ContextMenuEvent.getType()); + + // widget.addDomHandler(new KeyDownHandler() { + // @Override + // public void onKeyDown(KeyDownEvent event) { + // // FIXME: check if menu is shown or handleNavigation will do it? + // + // boolean handled = contextMenuWidget.handleNavigation(event + // .getNativeEvent().getKeyCode(), event.getNativeEvent() + // .getCtrlKey(), event.getNativeEvent().getShiftKey()); + // + // if (handled) { + // event.stopPropagation(); + // event.preventDefault(); + // } + // } + // }, KeyDownEvent.getType()); + } +} diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/ContextMenuServerRpc.java b/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/ContextMenuServerRpc.java new file mode 100644 index 0000000000..94edcf7442 --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/ContextMenuServerRpc.java @@ -0,0 +1,7 @@ +package com.vaadin.tests.widgetset.client.contextmenu; + +import com.vaadin.shared.communication.ServerRpc; + +public interface ContextMenuServerRpc extends ServerRpc { + void itemClicked(int itemId, boolean menuClosed); +} diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/ContextMenuState.java b/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/ContextMenuState.java new file mode 100644 index 0000000000..9fc93bea43 --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/ContextMenuState.java @@ -0,0 +1,9 @@ +package com.vaadin.tests.widgetset.client.contextmenu; + +import com.vaadin.shared.ui.menubar.MenuBarState; + +public class ContextMenuState extends MenuBarState { + { + primaryStyleName = "v-contextmenu"; + } +} diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/VContextMenuBar.java b/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/VContextMenuBar.java new file mode 100644 index 0000000000..a98f265cc2 --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/client/contextmenu/VContextMenuBar.java @@ -0,0 +1,15 @@ +package com.vaadin.tests.widgetset.client.contextmenu; + +import com.vaadin.client.ui.VMenuBar; + +public class VContextMenuBar extends VMenuBar { + public VContextMenuBar() { + setPixelSize(0, 0); + setVisible(false); + } + + @Override + public void showChildMenuAt(CustomMenuItem item, int top, int left) { + super.showChildMenuAt(item, top, left); + } +} diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/ContextMenu.java b/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/ContextMenu.java index 4bb3f17693..586ac9c4b3 100644 --- a/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/ContextMenu.java +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/ContextMenu.java @@ -1,4 +1,165 @@ package com.vaadin.tests.widgetset.contextmenu; -public class ContextMenu { +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.EventListener; +import java.util.EventObject; +import java.util.List; + +import com.vaadin.event.ContextClickEvent; +import com.vaadin.server.AbstractExtension; +import com.vaadin.server.Resource; +import com.vaadin.shared.Registration; +import com.vaadin.ui.AbstractComponent; +import com.vaadin.ui.Component; +import com.vaadin.ui.MenuBar; +import com.vaadin.ui.MenuBar.Command; +import com.vaadin.ui.MenuBar.MenuItem; +import com.vaadin.util.ReflectTools; + +public class ContextMenu extends AbstractExtension { + + private final MenuItem rootItem; + private final MenuBar innerMenubar; + + public ContextMenu(AbstractComponent parentComponent, + boolean setAsMenuForParentComponent) { + + innerMenubar = new MenuBar(); + rootItem = innerMenubar.addItem(""); + // todo + extend(parentComponent); + + // todo enable registerRpc(new ContextMenuServerRpc() { + // @Override + // public void itemClicked(int itemId, boolean menuClosed) { + // menu.itemClicked(itemId); + // } + // }); + // + // todo enable if (setAsMenuForParentComponent) { + // setAsContextMenuOf(parentComponent); + // } + } + + public void setAsContextMenuOf( + ContextClickEvent.ContextClickNotifier component) { + // todo + } + + // Should these also be in MenuInterface and then throw exception for + // MenuBar? + public MenuItem addSeparator() { + return rootItem.addSeparator(); + } + + public MenuItem addSeparatorBefore(MenuItem itemToAddBefore) { + return rootItem.addSeparatorBefore(itemToAddBefore); + } + + public MenuItem addItem(String caption, Command command) { + return rootItem.addItem(caption, command); + } + + public MenuItem addItem(String caption, Resource icon, Command command) { + return rootItem.addItem(caption, icon, command); + } + + public MenuItem addItemBefore(String caption, Resource icon, + Command command, MenuItem itemToAddBefore) { + return rootItem.addItemBefore(caption, icon, command, itemToAddBefore); + } + + public List<MenuItem> getItems() { + return rootItem.getChildren(); + } + + public void removeItem(MenuItem item) { + rootItem.removeChild(item); + + } + + public void removeItems() { + rootItem.removeChildren(); + } + + public int getSize() { + return rootItem.getSize(); + } + + public boolean isHtmlContentAllowed() { + return innerMenubar.isHtmlContentAllowed(); + } + + public void setHtmlContentAllowed(boolean htmlContentAllowed) { + innerMenubar.setHtmlContentAllowed(true); + } + + public Registration addContextMenuOpenListener( + ContextMenuOpenListener contextMenuOpenListener) { + // todo + return null; + + } + + public interface ContextMenuOpenListener + extends EventListener, Serializable { + + public static final Method MENU_OPENED = ReflectTools.findMethod( + ContextMenuOpenListener.class, "onContextMenuOpen", + ContextMenuOpenEvent.class); + + public void onContextMenuOpen(ContextMenuOpenEvent event); + + public static class ContextMenuOpenEvent extends EventObject { + private final ContextMenu contextMenu; + + private final int x; + private final int y; + + private ContextClickEvent contextClickEvent; + + public ContextMenuOpenEvent(ContextMenu contextMenu, + ContextClickEvent contextClickEvent) { + super(contextClickEvent.getComponent()); + + this.contextMenu = contextMenu; + this.contextClickEvent = contextClickEvent; + x = contextClickEvent.getClientX(); + y = contextClickEvent.getClientY(); + } + + /** + * @return ContextMenu that was opened. + */ + public ContextMenu getContextMenu() { + return contextMenu; + } + + /** + * @return Component which initiated the context menu open request. + */ + public Component getSourceComponent() { + return (Component) getSource(); + } + + /** + * @return x-coordinate of open position. + */ + public int getX() { + return x; + } + + /** + * @return y-coordinate of open position. + */ + public int getY() { + return y; + } + + public ContextClickEvent getContextClickEvent() { + return contextClickEvent; + } + } + } } diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/ContextmenuUI.java b/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/ContextmenuUI.java deleted file mode 100644 index e69de29bb2..0000000000 --- a/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/ContextmenuUI.java +++ /dev/null diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/GridContextMenu.java b/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/GridContextMenu.java new file mode 100644 index 0000000000..66442ab48d --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/GridContextMenu.java @@ -0,0 +1,95 @@ +package com.vaadin.tests.widgetset.contextmenu; + +import java.io.Serializable; +import java.util.EventListener; + +import com.vaadin.shared.ui.grid.GridConstants.Section; +import com.vaadin.tests.widgetset.contextmenu.ContextMenu.ContextMenuOpenListener.ContextMenuOpenEvent; +import com.vaadin.tests.widgetset.contextmenu.GridContextMenu.GridContextMenuOpenListener.GridContextMenuOpenEvent; +import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.Column; +import com.vaadin.ui.Grid.GridContextClickEvent; + +@SuppressWarnings("serial") +public class GridContextMenu<T> extends ContextMenu { + + public GridContextMenu(Grid<T> parentComponent) { + super(parentComponent, true); + } + + private void addGridSectionContextMenuListener(final Section section, + final GridContextMenuOpenListener<T> listener) { + addContextMenuOpenListener((final ContextMenuOpenEvent event) -> { + if (event.getContextClickEvent() instanceof GridContextClickEvent) { + @SuppressWarnings("unchecked") + GridContextClickEvent<T> gridEvent = (GridContextClickEvent<T>) event + .getContextClickEvent(); + if (gridEvent.getSection() == section) { + listener.onContextMenuOpen(new GridContextMenuOpenEvent<>( + GridContextMenu.this, gridEvent)); + } + } + }); + } + + public void addGridHeaderContextMenuListener( + GridContextMenuOpenListener<T> listener) { + addGridSectionContextMenuListener(Section.HEADER, listener); + } + + public void addGridFooterContextMenuListener( + GridContextMenuOpenListener<T> listener) { + addGridSectionContextMenuListener(Section.FOOTER, listener); + } + + public void addGridBodyContextMenuListener( + GridContextMenuOpenListener<T> listener) { + addGridSectionContextMenuListener(Section.BODY, listener); + } + + public interface GridContextMenuOpenListener<T> + extends EventListener, Serializable { + + public void onContextMenuOpen(GridContextMenuOpenEvent<T> event); + + public static class GridContextMenuOpenEvent<T> + extends ContextMenuOpenEvent { + + private final T item; + private final Grid<T> component; + private final int rowIndex; + private final Column<T, ?> column; + private final Section section; + + public GridContextMenuOpenEvent(ContextMenu contextMenu, + GridContextClickEvent<T> contextClickEvent) { + super(contextMenu, contextClickEvent); + item = contextClickEvent.getItem(); + component = contextClickEvent.getComponent(); + rowIndex = contextClickEvent.getRowIndex(); + column = contextClickEvent.getColumn(); + section = contextClickEvent.getSection(); + } + + public T getItem() { + return item; + } + + public Grid<T> getComponent() { + return component; + } + + public int getRowIndex() { + return rowIndex; + } + + public Column<T, ?> getColumn() { + return column; + } + + public Section getSection() { + return section; + } + } + } +} diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/demo/ContextmenuUI.java b/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/demo/ContextmenuUI.java new file mode 100644 index 0000000000..d614b4ff82 --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/demo/ContextmenuUI.java @@ -0,0 +1,99 @@ +package com.vaadin.tests.widgetset.contextmenu.demo; + +import com.vaadin.annotations.Theme; +import com.vaadin.annotations.Widgetset; +import com.vaadin.icons.VaadinIcons; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.tests.widgetset.TestingWidgetSet; +import com.vaadin.tests.widgetset.contextmenu.ContextMenu; +import com.vaadin.ui.Button; +import com.vaadin.ui.MenuBar; +import com.vaadin.ui.Notification; +import com.vaadin.ui.VerticalLayout; + +@SuppressWarnings({ "serial", "unchecked" }) +@Theme("contextmenu") +@Widgetset(TestingWidgetSet.NAME) + +public class ContextmenuUI extends AbstractTestUI { + Button but3 = new Button("remove Tooltip"); + + @Override + protected void setup(VaadinRequest request) { + + final VerticalLayout layout = new VerticalLayout(); + layout.setMargin(true); + setContent(layout); + + Button button = new Button("Button 1"); + layout.addComponent(button); + + Button button2 = new Button("Button 2"); + layout.addComponent(button2); + + ContextMenu contextMenu = new ContextMenu(this, false); + fillMenu(contextMenu); + + contextMenu.setAsContextMenuOf(button); + contextMenu.setAsContextMenuOf(button2); + + contextMenu.addContextMenuOpenListener( + new ContextMenu.ContextMenuOpenListener() { + @Override + public void onContextMenuOpen(ContextMenuOpenEvent event) { + Notification.show("Context menu on" + + event.getSourceComponent().getCaption()); + } + }); + + layout.addComponent(new GridWithGenericListener()); + layout.addComponent(new GridWithGridListener()); + layout.addComponent(but3); + layout.addComponent(new Button("Remove items from context menu", e -> { + contextMenu.removeItems(); + })); + } + + private void fillMenu(ContextMenu menu) { + final MenuBar.MenuItem item = menu.addItem("Checkable", e -> { + Notification.show("checked: " + e.isChecked()); + }); + item.setCheckable(true); + item.setChecked(true); + + MenuBar.MenuItem item2 = menu.addItem("Disabled", e -> { + Notification.show("disabled"); + }); + item2.setDescription("Disabled item"); + item2.setEnabled(false); + + MenuBar.MenuItem item3 = menu.addItem("Invisible", e -> { + Notification.show("invisible"); + }); + item3.setVisible(false); + + if (menu instanceof ContextMenu) { + ((ContextMenu) menu).addSeparator(); + } + + MenuBar.MenuItem item4 = menu + .addItem("Icon + Description + <b>HTML</b>", e -> { + Notification.show("icon"); + }); + item4.setIcon(VaadinIcons.ADJUST); + item4.setDescription("Test tooltip"); + but3.addClickListener(e -> item4.setDescription("")); + MenuBar.MenuItem item5 = menu.addItem("Custom stylename", e -> { + Notification.show("stylename"); + }); + item5.setStyleName("teststyle"); + + MenuBar.MenuItem item6 = menu.addItem("Submenu", e -> { + }); + item6.addItem("Subitem", e -> Notification.show("SubItem")); + item6.addSeparator(); + item6.addItem("Subitem", e -> Notification.show("SubItem")) + .setDescription("Test"); + } +} diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/demo/GridWithGenericListener.java b/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/demo/GridWithGenericListener.java new file mode 100644 index 0000000000..6f087d57ab --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/demo/GridWithGenericListener.java @@ -0,0 +1,52 @@ +package com.vaadin.tests.widgetset.contextmenu.demo; + +import java.util.Collections; + +import com.vaadin.data.provider.ListDataProvider; +import com.vaadin.tests.widgetset.contextmenu.ContextMenu; +import com.vaadin.ui.Grid; +import com.vaadin.ui.Notification; + +public class GridWithGenericListener extends Grid<String[]> { + + private static final String FIRST_NAME = "First name"; + private static final String LAST_NAME = "Last name"; + private static final String SHOE_SIZE = "Shoe size"; + + public GridWithGenericListener() { + setCaption("Grid with generic listener"); + + ContextMenu contextMenu2 = new ContextMenu(this, true); + setHeightByRows(3); + addColumn(arr -> arr[0]).setCaption(FIRST_NAME); + addColumn(arr -> arr[1]).setCaption(LAST_NAME); + addColumn(arr -> arr[2]).setCaption(SHOE_SIZE); + + ListDataProvider<String[]> ds = new ListDataProvider<>(Collections + .singletonList(new String[] { "John", "Doe", "57" })); + setDataProvider(ds); + contextMenu2.addContextMenuOpenListener(this::onGenericContextMenu); + } + + private void onGenericContextMenu( + ContextMenu.ContextMenuOpenListener.ContextMenuOpenEvent event) { + GridContextClickEvent<String[]> gridE = (GridContextClickEvent<String[]>) event + .getContextClickEvent(); + ContextMenu menu = event.getContextMenu(); + menu.removeItems(); + if (gridE.getColumn() != null) { + menu.addItem( + "Called from column " + gridE.getColumn().getCaption() + + " on row " + gridE.getRowIndex(), + f -> Notification.show("did something")); + } else if (gridE.getRowIndex() >= 0) { + menu.addItem("Called on row " + gridE.getRowIndex(), + f -> Notification.show("did something")); + } else { + menu.addItem("Called on background", + f -> Notification.show("did something")); + + } + } + +} diff --git a/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/demo/GridWithGridListener.java b/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/demo/GridWithGridListener.java new file mode 100644 index 0000000000..fdae470f07 --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/widgetset/contextmenu/demo/GridWithGridListener.java @@ -0,0 +1,53 @@ +package com.vaadin.tests.widgetset.contextmenu.demo; + +import java.util.Collections; + +import com.vaadin.data.provider.ListDataProvider; +import com.vaadin.tests.widgetset.contextmenu.GridContextMenu; +import com.vaadin.ui.Grid; + +public class GridWithGridListener extends Grid<String[]> { + + public GridWithGridListener() { + setCaption("Grid with Grid specific listener"); + setHeightByRows(3); + final GridContextMenu<String[]> gridContextMenu = new GridContextMenu<>( + this); + + addColumn(arr -> arr[0]).setCaption("Column 1(right-click here)"); + addColumn(arr -> arr[1]).setCaption("Column 2(right-click here)"); + + final ListDataProvider<String[]> dataSource = new ListDataProvider<>( + Collections.singletonList(new String[] { "foo", "bar" })); + setDataProvider(dataSource); + gridContextMenu.addGridHeaderContextMenuListener(e -> { + gridContextMenu.removeItems(); + gridContextMenu.addItem(getText(e), null); + }); + + gridContextMenu.addGridBodyContextMenuListener(e -> { + gridContextMenu.removeItems(); + gridContextMenu.addItem(getText(e), null); + }); + + } + + private static String getText( + final GridContextMenu.GridContextMenuOpenListener.GridContextMenuOpenEvent<String[]> e) { + + final Column<String[], ?> column = e.getColumn(); + final String columnText; + if (column != null) { + columnText = "'" + column.getCaption() + "'"; + } else { + columnText = "'?'"; + } + final String gridCaption = e.getComponent() == null ? "(NULL)" + : e.getComponent().getCaption(); + + return "Context menu for " + e.getSection() + ", column: " + columnText + + ", gridCaption: " + gridCaption; + + } + +} |