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