1 package com.vaadin.contextmenu;
2
3 import info.magnolia.vaadin.addons.contextmenu.shared.MgnlContextMenuClientRpc;
4 import info.magnolia.vaadin.addons.contextmenu.shared.MgnlContextMenuServerRpc;
5
6 import java.io.Serializable;
7 import java.lang.reflect.Method;
8 import java.util.ArrayList;
9 import java.util.EventListener;
10 import java.util.EventObject;
11 import java.util.List;
12
13 import com.vaadin.contextmenu.ContextMenu.ContextMenuOpenListener.ContextMenuOpenEvent;
14 import com.vaadin.contextmenu.client.ContextMenuClientRpc;
15 import com.vaadin.contextmenu.client.ContextMenuServerRpc;
16 import com.vaadin.contextmenu.client.MenuSharedState;
17 import com.vaadin.contextmenu.client.MenuSharedState.MenuItemState;
18 import com.vaadin.event.ContextClickEvent;
19 import com.vaadin.event.ContextClickEvent.ContextClickListener;
20 import com.vaadin.event.ContextClickEvent.ContextClickNotifier;
21 import com.vaadin.server.AbstractExtension;
22 import com.vaadin.server.Resource;
23 import com.vaadin.server.ResourceReference;
24 import com.vaadin.ui.AbstractComponent;
25 import com.vaadin.ui.Component;
26 import com.vaadin.util.ReflectTools;
27
28 @SuppressWarnings("serial")
29 public class ContextMenu extends AbstractExtension implements Menu {
30
31 private AbstractMenu menu = new AbstractMenu();
32
33 private ContextClickListener contextClickListener = new ContextClickListener() {
34 @Override
35 public void contextClick(ContextClickEvent event) {
36 fireEvent(new ContextMenuOpenEvent(ContextMenu.this, event));
37
38 open(event.getClientX(), event.getClientY());
39 }
40 };
41
42
43
44
45
46 public interface ContextMenuClosedListener extends EventListener {
47 Method MENU_CLOSED = ReflectTools
48 .findMethod(ContextMenuClosedListener.class,
49 "onContextMenuClosed",
50 ContextMenuClosedEvent.class);
51
52
53
54
55
56 void onContextMenuClosed(ContextMenuClosedEvent event);
57 }
58
59
60
61
62
63
64 public static class ContextMenuClosedEvent extends EventObject {
65 private static final long serialVersionUID = -5705205542849351984L;
66
67 private ContextMenu contextMenu;
68
69 public ContextMenuClosedEvent(ContextMenu contextMenu) {
70 super(contextMenu);
71 this.contextMenu = contextMenu;
72 }
73
74 public ContextMenu getContextMenu() {
75 return contextMenu;
76 }
77 }
78
79
80
81
82
83
84 public void addContextMenuCloseListener(
85 ContextMenuClosedListener contextMenuClosedListener) {
86 addListener(
87 ContextMenuClosedEvent.class,
88 contextMenuClosedListener,
89 ContextMenuClosedListener.MENU_CLOSED);
90 }
91
92 public void open() {
93 getRpcProxy(MgnlContextMenuClientRpc.class).showContextMenu();
94 }
95
96
97
98
99
100
101
102
103 public ContextMenu(AbstractComponent parentComponent,
104 boolean setAsMenuForParentComponent) {
105 extend(parentComponent);
106
107 registerRpc((MgnlContextMenuServerRpc) () -> fireEvent(new ContextMenuClosedEvent(ContextMenu.this)));
108 registerRpc(new ContextMenuServerRpc() {
109 @Override
110 public void itemClicked(int itemId, boolean menuClosed) {
111 menu.itemClicked(itemId);
112 }
113 });
114
115 if (setAsMenuForParentComponent) {
116 setAsContextMenuOf(parentComponent);
117 }
118 }
119
120
121
122
123
124
125
126
127 public void setAsContextMenuOf(ContextClickNotifier component) {
128 component.addContextClickListener(contextClickListener);
129 }
130
131 public void addContextMenuOpenListener(
132 ContextMenuOpenListener contextMenuComponentListener) {
133 addListener(ContextMenuOpenEvent.class, contextMenuComponentListener,
134 ContextMenuOpenListener.MENU_OPENED);
135 }
136
137 @Override
138 public void beforeClientResponse(boolean initial) {
139 super.beforeClientResponse(initial);
140
141
142
143
144
145
146
147
148 MenuSharedState menuSharedState = getState();
149 menuSharedState.htmlContentAllowed = isHtmlContentAllowed();
150 menuSharedState.menuItems = convertItemsToState(getItems());
151 }
152
153 public void open(int x, int y) {
154 getRpcProxy(ContextMenuClientRpc.class).showContextMenu(x, y);
155 }
156
157 private List<MenuItemState> convertItemsToState(List<MenuItem> items) {
158 if (items == null || items.size() == 0) {
159 return null;
160 }
161
162 List<MenuItemState> state = new ArrayList<>();
163
164 for (MenuItem item : items) {
165 MenuItemState menuItemState = new MenuItemState();
166
167 if (!item.isVisible()) {
168 continue;
169 }
170
171 menuItemState.id = item.getId();
172 menuItemState.text = item.getText();
173 menuItemState.checkable = item.isCheckable();
174 menuItemState.checked = item.isChecked();
175 menuItemState.description = item.getDescription();
176 menuItemState.enabled = item.isEnabled();
177 menuItemState.separator = item.isSeparator();
178 menuItemState.icon = ResourceReference.create(item.getIcon(), this,
179 "");
180 menuItemState.styleName = item.getStyleName();
181
182 menuItemState.childItems = convertItemsToState(item.getChildren());
183
184 state.add(menuItemState);
185 }
186
187 return state;
188 }
189
190 @Override
191 protected MenuSharedState getState() {
192 return (MenuSharedState) super.getState();
193 }
194
195 protected ContextClickListener getContextClickListener() {
196 return contextClickListener;
197 }
198
199
200
201 public MenuItem addSeparator() {
202
203 MenuItemImpl item = (MenuItemImpl) addItem("", null);
204 item.setSeparator(true);
205 return item;
206 }
207
208 public MenuItem addSeparatorBefore(MenuItem itemToAddBefore) {
209
210 MenuItemImpl item = (MenuItemImpl) addItemBefore("", null, null,
211 itemToAddBefore);
212 item.setSeparator(true);
213 return item;
214 }
215
216
217
218 @Override
219 public MenuItem addItem(String caption, Command command) {
220 return menu.addItem(caption, command);
221 }
222
223 @Override
224 public MenuItem addItem(String caption, Resource icon, Command command) {
225 return menu.addItem(caption, icon, command);
226 }
227
228 @Override
229 public MenuItem addItemBefore(String caption, Resource icon,
230 Command command, MenuItem itemToAddBefore) {
231 return menu.addItemBefore(caption, icon, command, itemToAddBefore);
232 }
233
234 @Override
235 public List<MenuItem> getItems() {
236 return menu.getItems();
237 }
238
239 @Override
240 public void removeItem(MenuItem item) {
241 menu.removeItem(item);
242 }
243
244 @Override
245 public void removeItems() {
246 menu.removeItems();
247 }
248
249 @Override
250 public int getSize() {
251 return menu.getSize();
252 }
253
254 @Override
255 public void setHtmlContentAllowed(boolean htmlContentAllowed) {
256 menu.setHtmlContentAllowed(htmlContentAllowed);
257 }
258
259 @Override
260 public boolean isHtmlContentAllowed() {
261 return menu.isHtmlContentAllowed();
262 }
263
264
265
266 public interface ContextMenuOpenListener
267 extends EventListener, Serializable {
268
269 public static final Method MENU_OPENED = ReflectTools.findMethod(
270 ContextMenuOpenListener.class, "onContextMenuOpen",
271 ContextMenuOpenEvent.class);
272
273 public void onContextMenuOpen(ContextMenuOpenEvent event);
274
275 public static class ContextMenuOpenEvent extends EventObject {
276 private final ContextMenu contextMenu;
277
278 private final int x;
279 private final int y;
280
281 private ContextClickEvent contextClickEvent;
282
283 public ContextMenuOpenEvent(ContextMenu contextMenu,
284 ContextClickEvent contextClickEvent) {
285 super(contextClickEvent.getComponent());
286
287 this.contextMenu = contextMenu;
288 this.contextClickEvent = contextClickEvent;
289 x = contextClickEvent.getClientX();
290 y = contextClickEvent.getClientY();
291 }
292
293
294
295
296 public ContextMenu getContextMenu() {
297 return contextMenu;
298 }
299
300
301
302
303 public Component getSourceComponent() {
304 return (Component) getSource();
305 }
306
307
308
309
310 public int getX() {
311 return x;
312 }
313
314
315
316
317 public int getY() {
318 return y;
319 }
320
321 public ContextClickEvent getContextClickEvent() {
322 return contextClickEvent;
323 }
324 }
325 }
326 }