package org.vaadin.peter.contextmenu.client.ui; import java.util.Iterator; import org.vaadin.peter.contextmenu.client.ui.VMenu.VMenuItem; import com.google.gwt.dom.client.Element; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.UIDL; /** * Client side implementation for ContextMenu component * * @author Peter Lehto / IT Mill Oy Ltd */ public class VContextMenu extends Widget implements Paintable { protected String paintableId; protected ApplicationConnection client; private int rootX; private int rootY; private Integer width; private String rootLocationId; private VMenu rootMenu; private boolean openToRight; public VContextMenu() { Element element = DOM.createDiv(); setElement(element); } @Override public void setWidth(String width) { if (width == null || width.equals("")) { return; } this.width = Integer.parseInt(width.substring(0, width.lastIndexOf("px"))); } @Override public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { if (client.updateComponent(this, uidl, true)) { return; } this.client = client; paintableId = uidl.getId(); UIDL rootUidl = uidl.getChildByTagName("items"); if (rootMenu != null) { rootMenu.hide(); } this.rootMenu = createMenuHierarchy(rootUidl, null); if (this.getStyleName() != null && !this.getStyleName().equals("")) { this.rootMenu.addStyleName(this.getStyleName()); } // Show root menu if (uidl.hasAttribute("show")) { if (uidl.getBooleanAttribute("show") == true) { openToRight = false; this.rootLocationId = uidl .getStringAttribute("component_locator"); if (this.rootLocationId.equals("")) { rootX = uidl.getIntAttribute("left"); rootY = uidl.getIntAttribute("top"); rootX += Window.getScrollLeft(); rootY += Window.getScrollTop(); } else { Element positionElement = DOM .getElementById(this.rootLocationId); int left = positionElement.getAbsoluteRight() + 10; this.rootX = left; this.rootY = positionElement.getAbsoluteTop(); } this.positionAndShowMenu(this.rootMenu, rootX, rootY); } } } private VMenu createMenuHierarchy(UIDL contents, VMenu parentMenu) { Iterator<Object> childIterator = contents.getChildIterator(); VMenu menu = new VMenu(this, parentMenu); while (childIterator.hasNext()) { UIDL child = (UIDL) childIterator.next(); Integer id = child.getIntAttribute("id"); String name = child.getStringAttribute("name"); boolean enabled = child.getBooleanAttribute("enabled"); boolean separator = child.getBooleanAttribute("separator"); String styleName = null; if (child.hasAttribute("style")) { styleName = child.getStringAttribute("style"); } String iconUri = null; if (child.hasAttribute("icon")) { iconUri = this.client.translateVaadinUri(child .getStringAttribute("icon")); } VMenuItem item = menu.addMenuItem(id, name, styleName, enabled, iconUri, separator); if (child.getChildByTagName("items") != null) { VMenu subMenu = createMenuHierarchy( child.getChildByTagName("items"), menu); item.setSubMenu(subMenu); } } return menu; } private void positionAndShowMenu(VMenu menu, int left, int top) { int windowWidth = Window.getClientWidth(); menu.show(); if (left > windowWidth - menu.getOffsetWidth() || openToRight) { if (menu.hasParent()) { VMenu parentMenu = menu.getParentMenu(); left = parentMenu.getAbsoluteLeft(); left -= menu.getOffsetWidth(); } else { left = windowWidth - menu.getOffsetWidth(); } // if menu is opened leftwards, open sub menus leftwards too openToRight = true; } int menuHeight = menu.getNumberOfItems() * 20; if (top + menuHeight > Window.getClientHeight()) { top -= menuHeight; } menu.setPopupPosition(left, top); } /** * Called when menu item is clicked. If clicked menu item has a sub menu it * will be opened. * * @param parent * @param id * @param top */ public void itemClicked(VMenuItem item) { VMenu ownerMenu = item.getOwener(); if (item.hasSubMenu()) { for (VMenu siblingSubMenu : item.getSiblingSubMenus()) { siblingSubMenu.hide(); } this.positionAndShowMenu(item.getSubMenu(), ownerMenu.getAbsoluteLeft() + ownerMenu.getOffsetWidth(), item.getAbsoluteTop()); } else { this.rootMenu.hide(); } this.client.updateVariable(paintableId, "itemId", item.getItemId(), true); } public Integer getDefinedWidth() { return this.width; } public boolean hasDefinedWidth() { return this.width != null; } }