1 package com.vaadin.contextmenu.client;
2
3 import info.magnolia.vaadin.addons.contextmenu.shared.MgnlContextMenuClientRpc;
4 import info.magnolia.vaadin.addons.contextmenu.shared.MgnlContextMenuServerRpc;
5
6 import java.util.List;
7 import java.util.logging.Logger;
8
9 import com.google.gwt.core.client.GWT;
10 import com.google.gwt.dom.client.Document;
11 import com.google.gwt.dom.client.SpanElement;
12 import com.google.gwt.event.logical.shared.CloseEvent;
13 import com.google.gwt.user.client.Command;
14 import com.google.gwt.user.client.Event;
15 import com.google.gwt.user.client.Event.NativePreviewEvent;
16 import com.google.gwt.user.client.Event.NativePreviewHandler;
17 import com.google.gwt.user.client.ui.PopupPanel;
18 import com.google.gwt.user.client.ui.Widget;
19 import com.vaadin.client.ApplicationConnection;
20 import com.vaadin.client.ComponentConnector;
21 import com.vaadin.client.ServerConnector;
22 import com.vaadin.client.UIDL;
23 import com.vaadin.client.WidgetUtil;
24 import com.vaadin.client.communication.StateChangeEvent;
25 import com.vaadin.client.extensions.AbstractExtensionConnector;
26 import com.vaadin.client.ui.Icon;
27 import com.vaadin.client.ui.VMenuBar;
28 import com.vaadin.client.ui.VMenuBar.CustomMenuItem;
29 import com.vaadin.contextmenu.ContextMenu;
30 import com.vaadin.contextmenu.client.MenuSharedState.MenuItemState;
31 import com.vaadin.shared.ui.Connect;
32
33 @SuppressWarnings("serial")
34 @Connect(ContextMenu.class)
35 public class ContextMenuConnector extends AbstractExtensionConnector {
36
37
38 private class VMgnlMenuBar extends MyVMenuBar {
39
40 VMgnlMenuBar(boolean subMenu, VMenuBar parentMenu) {
41 super(subMenu, parentMenu);
42 }
43
44 VMgnlMenuBar() {}
45
46 @Override
47 public void showChildMenuAt(CustomMenuItem item, int top, int left) {
48 super.showChildMenuAt(item, top, left);
49 }
50
51 @Override
52 public void onClose(CloseEvent<PopupPanel> event) {
53 super.onClose(event);
54 getRpcProxy(MgnlContextMenuServerRpc.class).contextMenuClosed();
55 }
56
57
58
59
60
61
62 public String buildItemHTML(UIDL item) {
63
64 StringBuffer itemHTML = new StringBuffer();
65 if (item.hasAttribute("separator")) {
66 itemHTML.append("<span>---</span>");
67 } else {
68
69 if (item.getChildCount() > 0) {
70 String bgStyle = "";
71 itemHTML.append("<span class=\"" + getStylePrimaryName()
72 + "-submenu-indicator\"" + bgStyle
73 + ">►</span>");
74 }
75
76 itemHTML.append("<span class=\"" + getStylePrimaryName() + "-menuitem-caption\">");
77
78
79 String itemText = item.getStringAttribute("text");
80 if (!htmlContentAllowed) {
81 itemText = WidgetUtil.escapeHTML(itemText);
82 }
83 itemHTML.append(itemText);
84 itemHTML.append("</span>");
85 }
86 return itemHTML.toString();
87 }
88 }
89
90 protected MgnlContextMenuClientRpc serverToClientRPC = (MgnlContextMenuClientRpc) () -> {
91 Widget clickTargetWidget = ((ComponentConnector) getParent()).getWidget();
92
93 int targetW = clickTargetWidget.getOffsetWidth();
94 int x = clickTargetWidget.getAbsoluteLeft() + targetW;
95 int y = clickTargetWidget.getAbsoluteTop() + clickTargetWidget.getOffsetHeight();
96
97 showMenu(x, y);
98 };
99
100 @SuppressWarnings("unused")
101 private static Logger logger = Logger.getLogger("ContextMenuConnector");
102
103
104 private VMgnlMenuBar dummyRootMenuBar;
105 private VMgnlMenuBar contextMenuWidget;
106
107 @Override
108 public MenuSharedState getState() {
109 return (MenuSharedState) super.getState();
110 }
111
112 @Override
113 public void onStateChanged(StateChangeEvent stateChangeEvent) {
114 super.onStateChanged(stateChangeEvent);
115
116 contextMenuWidget.clearItems();
117 addMenuItemsFromState(contextMenuWidget, getState().menuItems);
118 }
119
120 @Override
121 protected void init() {
122 super.init();
123
124 dummyRootMenuBar = new VMgnlMenuBar();
125
126 VMenuBar.CustomMenuItem item = GWT.create(VMgnlMenuBar.CustomMenuItem.class);
127 dummyRootMenuBar.getItems().add(item);
128
129 contextMenuWidget = new VMgnlMenuBar(true, dummyRootMenuBar);
130 item.setSubMenu(contextMenuWidget);
131
132
133 MyVOverlay.setApplicationConnection(this.getConnection());
134
135 registerRpc(MgnlContextMenuClientRpc.class, serverToClientRPC);
136 registerRpc(ContextMenuClientRpc.class, new ContextMenuClientRpc() {
137 @Override
138 public void showContextMenu(int x, int y) {
139 showMenu(x, y);
140 }
141 });
142
143 Event.addNativePreviewHandler(new NativePreviewHandler() {
144 @Override
145 public void onPreviewNativeEvent(NativePreviewEvent event) {
146 if (event.getTypeInt() == Event.ONKEYDOWN
147 && contextMenuWidget.isPopupShowing()) {
148 boolean handled = contextMenuWidget.handleNavigation(
149 event.getNativeEvent().getKeyCode(),
150 event.getNativeEvent().getCtrlKey(),
151 event.getNativeEvent().getShiftKey());
152
153 if (handled) {
154 event.cancel();
155 }
156 }
157 }
158 });
159 }
160
161 private void addMenuItemsFromState(VMenuBar menuToAddTo,
162 List<MenuItemState> menuItems) {
163 if (menuItems == null)
164 return;
165
166 for (MenuItemState menuItemState : menuItems) {
167 CustomMenuItem newItem = addMenuItemToMenu(menuToAddTo,
168 menuItemState);
169
170 if (menuItemState.childItems != null
171 && menuItemState.childItems.size() > 0) {
172 VMenuBar subMenu = new MyVMenuBar(true, menuToAddTo);
173 addMenuItemsFromState(subMenu, menuItemState.childItems);
174 newItem.setSubMenu(subMenu);
175 }
176 }
177 }
178
179 private CustomMenuItem addMenuItemToMenu(VMenuBar menuToAddTo,
180 final MenuItemState menuItemState) {
181 String itemText = buildItemHTML(menuItemState,
182 getState().htmlContentAllowed, getConnection());
183 CustomMenuItem item = menuToAddTo.addItem(itemText, new Command() {
184 @Override
185 public void execute() {
186 if (contextMenuWidget.isAttached()) {
187 dummyRootMenuBar.hideChildren();
188 itemSelected(menuItemState.id);
189 }
190 }
191 });
192
193 updateMenuItemFromState(item, menuItemState);
194
195 return item;
196 }
197
198 private void updateMenuItemFromState(CustomMenuItem item,
199 MenuItemState state) {
200 item.setEnabled(state.enabled);
201 item.setCheckable(state.checkable);
202 item.setChecked(state.checked);
203 item.setStyleName(state.styleName);
204 if (item instanceof VMenuItem) {
205
206 ((VMenuItem) item).setSeparator(state.separator);
207 ((VMenuItem) item).setDescription(state.description);
208 }
209 }
210
211
212 private static String buildItemHTML(MenuItemState state,
213 boolean htmlContentAllowed, ApplicationConnection connection) {
214
215 StringBuffer itemHTML = new StringBuffer();
216 if (state.separator) {
217 itemHTML.append("<span>---</span>");
218 } else {
219
220 if (state.childItems != null && state.childItems.size() > 0) {
221 itemHTML.append(
222 "<span class=\"v-menubar-submenu-indicator\">►</span>");
223 }
224
225 itemHTML.append("<span class=\"v-menubar-menuitem-caption\">");
226
227 final String iconUrl = state.icon.getURL();
228
229 String ICON_FONT_CODE = "iconfont#";
230 if (iconUrl.startsWith(ICON_FONT_CODE)) {
231 SpanElement iconFont;
232 iconFont = Document.get().createSpanElement();
233 String iconFontCssClass = iconUrl.substring(ICON_FONT_CODE.length());
234 iconFont.setClassName("v-icon " + iconFontCssClass);
235 itemHTML.append(iconFont.getString());
236 }
237 else {
238 Icon icon = connection.getIcon(iconUrl);
239 if (icon != null) {
240 itemHTML.append(icon.getElement().getString());
241 }
242 }
243
244 String itemText = state.text;
245 if (!htmlContentAllowed) {
246 itemText = WidgetUtil.escapeHTML(itemText);
247 }
248 itemHTML.append(itemText);
249 itemHTML.append("</span>");
250 }
251 return itemHTML.toString();
252 }
253
254 protected void itemSelected(int id) {
255 getRpcProxy(ContextMenuServerRpc.class).itemClicked(id, true);
256 }
257
258 private void showMenu(int eventX, int eventY) {
259 CustomMenuItem firstItem = dummyRootMenuBar.getItems().get(0);
260 dummyRootMenuBar.setSelected(firstItem);
261 dummyRootMenuBar.showChildMenuAt(firstItem, eventY, eventX);
262 }
263
264 @Override
265 protected void extend(ServerConnector target) {
266 Logger.getLogger("ContextMenuConnector").info("extend");
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297 }
298 }