View Javadoc
1   package org.vaadin.peter.contextmenu.client;
2   
3   import org.vaadin.peter.contextmenu.client.ContextMenuState.ContextMenuItemState;
4   
5   import com.google.gwt.core.client.GWT;
6   import com.google.gwt.dom.client.Element;
7   import com.google.gwt.event.dom.client.KeyCodes;
8   import com.google.gwt.event.logical.shared.CloseHandler;
9   import com.google.gwt.user.client.DOM;
10  import com.google.gwt.user.client.Event;
11  import com.google.gwt.user.client.Event.NativePreviewEvent;
12  import com.google.gwt.user.client.Event.NativePreviewHandler;
13  import com.google.gwt.user.client.Window;
14  import com.google.gwt.user.client.ui.PopupPanel;
15  import com.google.gwt.user.client.ui.Widget;
16  import com.vaadin.client.extensions.AbstractExtensionConnector;
17  
18  /**
19   * Client side implementation for ContextMenu component
20   * 
21   * @author Peter Lehto / Vaadin Ltd
22   */
23  public class ContextMenuWidget extends Widget {
24  	private final ContextMenuOverlay menuOverlay;
25  
26  	private final NativePreviewHandler nativeEventHandler = new NativePreviewHandler() {
27  
28  		@Override
29  		public void onPreviewNativeEvent(NativePreviewEvent event) {
30  			if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ESCAPE) {
31  				// Always close the context menu on esc, no matter the focus
32  				hide();
33  			}
34  
35  			Event nativeEvent = Event.as(event.getNativeEvent());
36  			boolean targetsContextMenu = eventTargetContextMenu(nativeEvent);
37  
38  			if (!targetsContextMenu) {
39  				int type = nativeEvent.getTypeInt();
40  				switch (type) {
41  				case Event.ONMOUSEDOWN: {
42  					hide();
43  				}
44  				}
45  			}
46  		}
47  	};
48  
49  	public ContextMenuWidget() {
50  		Element element = DOM.createDiv();
51  		setElement(element);
52  
53  		Event.addNativePreviewHandler(nativeEventHandler);
54  
55  		menuOverlay = new ContextMenuOverlay();
56  	}
57  
58  	protected boolean eventTargetContextMenu(Event nativeEvent) {
59  		for (ContextMenuItemWidget item : menuOverlay.getMenuItems()) {
60  			if (item.eventTargetsPopup(nativeEvent)) {
61  				return true;
62  			}
63  		}
64  
65  		return false;
66  	}
67  
68  	protected boolean isShowing() {
69  		return menuOverlay.isShowing();
70  	}
71  
72  	public void hide() {
73  		menuOverlay.hide();
74  	}
75  
76  	/**
77  	 * Adds new item as context menu root item.
78  	 * 
79  	 * @param rootItem
80  	 * @param connector
81  	 */
82  	public void addRootMenuItem(ContextMenuItemState rootItem,
83                                  AbstractExtensionConnector connector) {
84  		ContextMenuItemWidget itemWidget = createEmptyItemWidget(rootItem.id,
85  				rootItem.caption, connector);
86  		itemWidget.setEnabled(rootItem.enabled);
87  		itemWidget.setSeparatorVisible(rootItem.separator);
88  
89  		menuOverlay.addMenuItem(itemWidget);
90  
91  		for (ContextMenuItemState childState : rootItem.getChildren()) {
92  			createSubMenu(itemWidget, childState, connector);
93  		}
94  	}
95  
96  	/**
97  	 * Creates new empty menu item
98  	 * 
99  	 * @param id
100 	 * @param caption
101 	 * @param contextMenuConnector
102 	 * @return
103 	 */
104 	private ContextMenuItemWidget createEmptyItemWidget(String id,
105 			String caption, AbstractExtensionConnector contextMenuConnector) {
106 		ContextMenuItemWidget widget = GWT.create(ContextMenuItemWidget.class);
107 		widget.setId(id);
108 		widget.setCaption(caption);
109 
110 		widget.setIcon(contextMenuConnector.getResourceUrl(id));
111 
112 		ContextMenuItemWidgetHandler handler = new ContextMenuItemWidgetHandler(
113 				widget, contextMenuConnector);
114 		widget.addClickHandler(handler);
115 		widget.addMouseOutHandler(handler);
116 		widget.addMouseOverHandler(handler);
117 		widget.addKeyUpHandler(handler);
118 		widget.setRootComponent(this);
119 
120 		return widget;
121 	}
122 
123 	private void createSubMenu(ContextMenuItemWidget parentWidget,
124 			ContextMenuItemState childState, AbstractExtensionConnector connector) {
125 		ContextMenuItemWidget childWidget = createEmptyItemWidget(
126 				childState.id, childState.caption, connector);
127 		childWidget.setEnabled(childState.enabled);
128 		childWidget.setSeparatorVisible(childState.separator);
129 		parentWidget.addSubMenuItem(childWidget);
130 
131 		for (ContextMenuItemState child : childState.getChildren()) {
132 			createSubMenu(childWidget, child, connector);
133 		}
134 	}
135 
136 	public void clearItems() {
137 		menuOverlay.clearItems();
138 	}
139 
140 	public void showContextMenu(int rootMenuX, int rootMenuY) {
141 		rootMenuX += Window.getScrollLeft();
142 		rootMenuY += Window.getScrollTop();
143 
144 		menuOverlay.showAt(rootMenuX, rootMenuY);
145 	}
146 
147 	public void addCloseHandler(CloseHandler<PopupPanel> popupCloseHandler) {
148 		menuOverlay.addCloseHandler(popupCloseHandler);
149 	}
150 }