1 package com.vaadin.contextmenu;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Stack;
25
26 import org.jsoup.nodes.Attributes;
27 import org.jsoup.nodes.Element;
28 import org.jsoup.nodes.Node;
29 import org.jsoup.parser.Tag;
30
31 import com.vaadin.server.PaintException;
32 import com.vaadin.server.PaintTarget;
33 import com.vaadin.server.Resource;
34 import com.vaadin.shared.ui.menubar.MenuBarConstants;
35 import com.vaadin.shared.ui.menubar.MenuBarState;
36 import com.vaadin.ui.AbstractComponent;
37 import com.vaadin.ui.Component.Focusable;
38 import com.vaadin.ui.LegacyComponent;
39 import com.vaadin.ui.declarative.DesignAttributeHandler;
40 import com.vaadin.ui.declarative.DesignContext;
41
42
43
44
45
46
47
48
49 @SuppressWarnings({ "serial", "deprecation" })
50 public class MenuBar extends AbstractComponent
51 implements Menu, LegacyComponent, Focusable {
52
53 private MenuItem moreItem;
54
55 private boolean openRootOnHover;
56
57 @Override
58 protected MenuBarState getState() {
59 return (MenuBarState) super.getState();
60 }
61
62 @Override
63 protected MenuBarState getState(boolean markAsDirty) {
64 return (MenuBarState) super.getState(markAsDirty);
65 }
66
67
68 @Override
69 public void paintContent(PaintTarget target) throws PaintException {
70 target.addAttribute(MenuBarConstants.OPEN_ROOT_MENU_ON_HOWER,
71 openRootOnHover);
72
73 if (isHtmlContentAllowed()) {
74 target.addAttribute(MenuBarConstants.HTML_CONTENT_ALLOWED, true);
75 }
76
77 target.startTag("options");
78
79 if (getWidth() > -1) {
80 target.startTag("moreItem");
81 target.addAttribute("text", moreItem.getText());
82 if (moreItem.getIcon() != null) {
83 target.addAttribute("icon", moreItem.getIcon());
84 }
85 target.endTag("moreItem");
86 }
87
88 target.endTag("options");
89 target.startTag("items");
90
91
92 for (MenuItem item : getItems()) {
93 paintItem(target, item);
94 }
95
96 target.endTag("items");
97 }
98
99 private void paintItem(PaintTarget target, MenuItem item)
100 throws PaintException {
101 if (!item.isVisible()) {
102 return;
103 }
104
105 target.startTag("item");
106
107 target.addAttribute("id", item.getId());
108
109 if (item.getStyleName() != null) {
110 target.addAttribute(MenuBarConstants.ATTRIBUTE_ITEM_STYLE,
111 item.getStyleName());
112 }
113
114 if (item.isSeparator()) {
115 target.addAttribute("separator", true);
116 } else {
117 target.addAttribute("text", item.getText());
118
119 Command command = item.getCommand();
120 if (command != null) {
121 target.addAttribute("command", true);
122 }
123
124 Resource icon = item.getIcon();
125 if (icon != null) {
126 target.addAttribute(MenuBarConstants.ATTRIBUTE_ITEM_ICON, icon);
127 }
128
129 if (!item.isEnabled()) {
130 target.addAttribute(MenuBarConstants.ATTRIBUTE_ITEM_DISABLED,
131 true);
132 }
133
134 String description = item.getDescription();
135 if (description != null && description.length() > 0) {
136 target.addAttribute(MenuBarConstants.ATTRIBUTE_ITEM_DESCRIPTION,
137 description);
138 }
139 if (item.isCheckable()) {
140
141
142 target.addAttribute(MenuBarConstants.ATTRIBUTE_CHECKED,
143 item.isChecked());
144 }
145 if (item.hasChildren()) {
146 for (MenuItem child : item.getChildren()) {
147 paintItem(target, child);
148 }
149 }
150
151 }
152
153 target.endTag("item");
154 }
155
156
157 @Override
158 public void changeVariables(Object source, Map<String, Object> variables) {
159 Stack<MenuItem> items = new Stack<MenuItem>();
160 boolean found = false;
161
162 if (variables.containsKey("clickedId")) {
163
164 Integer clickedId = (Integer) variables.get("clickedId");
165 Iterator<MenuItem> itr = getItems().iterator();
166 while (itr.hasNext()) {
167 items.push(itr.next());
168 }
169
170 MenuItem tmpItem = null;
171
172
173 while (!found && !items.empty()) {
174 tmpItem = items.pop();
175 found = (clickedId.intValue() == tmpItem.getId());
176
177 if (tmpItem.hasChildren()) {
178 itr = tmpItem.getChildren().iterator();
179 while (itr.hasNext()) {
180 items.push(itr.next());
181 }
182 }
183
184 }
185
186
187 if (found && tmpItem.isEnabled()) {
188 if (tmpItem.isCheckable()) {
189 tmpItem.setChecked(!tmpItem.isChecked());
190 }
191 if (null != tmpItem.getCommand()) {
192 tmpItem.getCommand().menuSelected(tmpItem);
193 }
194 }
195 }
196 }
197
198
199
200
201 public MenuBar() {
202 setMoreMenuItem(null);
203 }
204
205 @Override
206 public int getTabIndex() {
207 return getState(false).tabIndex;
208 }
209
210
211
212
213
214
215 @Override
216 public void setTabIndex(int tabIndex) {
217 getState().tabIndex = tabIndex;
218 }
219
220 @Override
221 public void focus() {
222
223 super.focus();
224 }
225
226 @Override
227 public void writeDesign(Element design, DesignContext designContext) {
228 super.writeDesign(design, designContext);
229 for (MenuItem item : getItems()) {
230 design.appendChild(createMenuElement(item, designContext));
231 }
232
233
234 if (getMoreMenuItem() != null
235 && !getMoreMenuItem().getText().isEmpty()) {
236 Element moreMenu = createMenuElement(getMoreMenuItem(),
237 designContext);
238 moreMenu.attr("more", "");
239 design.appendChild(moreMenu);
240 }
241
242 if (!isHtmlContentAllowed()) {
243 design.attr(DESIGN_ATTR_PLAIN_TEXT, "");
244 }
245 }
246
247 protected Element createMenuElement(MenuItem item,
248 DesignContext designContext) {
249 Element menuElement = new Element(Tag.valueOf("menu"), "");
250
251 MenuItem def = new MenuItemImpl("", null, null);
252
253 Attributes attr = menuElement.attributes();
254 DesignAttributeHandler.writeAttribute("icon", attr, item.getIcon(),
255 def.getIcon(), Resource.class, designContext);
256 DesignAttributeHandler.writeAttribute("disabled", attr,
257 !item.isEnabled(), !def.isEnabled(), boolean.class,
258 designContext);
259 DesignAttributeHandler.writeAttribute("visible", attr, item.isVisible(),
260 def.isVisible(), boolean.class, designContext);
261 DesignAttributeHandler.writeAttribute("separator", attr,
262 item.isSeparator(), def.isSeparator(), boolean.class,
263 designContext);
264 DesignAttributeHandler.writeAttribute("checkable", attr,
265 item.isCheckable(), def.isCheckable(), boolean.class,
266 designContext);
267 DesignAttributeHandler.writeAttribute("checked", attr, item.isChecked(),
268 def.isChecked(), boolean.class, designContext);
269 DesignAttributeHandler.writeAttribute("description", attr,
270 item.getDescription(), def.getDescription(), String.class,
271 designContext);
272 DesignAttributeHandler.writeAttribute("style-name", attr,
273 item.getStyleName(), def.getStyleName(), String.class,
274 designContext);
275
276 menuElement.append(item.getText());
277
278 if (item.hasChildren()) {
279 for (MenuItem subMenu : item.getChildren()) {
280 menuElement
281 .appendChild(createMenuElement(subMenu, designContext));
282 }
283 }
284
285 return menuElement;
286 }
287
288 protected MenuItem readMenuElement(Element menuElement, MenuItem parent) {
289 Resource icon = null;
290 if (menuElement.hasAttr("icon")) {
291 icon = DesignAttributeHandler.getFormatter()
292 .parse(menuElement.attr("icon"), Resource.class);
293 }
294
295 String caption = "";
296 List<Element> subMenus = new ArrayList<Element>();
297 for (Node node : menuElement.childNodes()) {
298 if (node instanceof Element
299 && ((Element) node).tagName().equals("menu")) {
300 subMenus.add((Element) node);
301 } else {
302 caption += node.toString();
303 }
304 }
305
306 MenuItemImpl menu = new MenuItemImpl(parent, caption.trim(), icon,
307 null);
308
309 Attributes attr = menuElement.attributes();
310 if (menuElement.hasAttr("icon")) {
311 menu.setIcon(DesignAttributeHandler.readAttribute("icon", attr,
312 Resource.class));
313 }
314 if (menuElement.hasAttr("disabled")) {
315 menu.setEnabled(!DesignAttributeHandler.readAttribute("disabled",
316 attr, boolean.class));
317 }
318 if (menuElement.hasAttr("visible")) {
319 menu.setVisible(DesignAttributeHandler.readAttribute("visible",
320 attr, boolean.class));
321 }
322 if (menuElement.hasAttr("separator")) {
323 menu.setSeparator(DesignAttributeHandler.readAttribute("separator",
324 attr, boolean.class));
325 }
326 if (menuElement.hasAttr("checkable")) {
327 menu.setCheckable(DesignAttributeHandler.readAttribute("checkable",
328 attr, boolean.class));
329 }
330 if (menuElement.hasAttr("checked")) {
331 menu.setChecked(DesignAttributeHandler.readAttribute("checked",
332 attr, boolean.class));
333 }
334 if (menuElement.hasAttr("description")) {
335 menu.setDescription(DesignAttributeHandler
336 .readAttribute("description", attr, String.class));
337 }
338 if (menuElement.hasAttr("style-name")) {
339 menu.setStyleName(DesignAttributeHandler.readAttribute("style-name",
340 attr, String.class));
341 }
342
343 if (!subMenus.isEmpty()) {
344 menu.setChildren(new ArrayList<MenuItem>());
345 }
346
347 for (Element subMenu : subMenus) {
348 MenuItem newItem = readMenuElement(subMenu, menu);
349
350 menu.getChildren().add(newItem);
351 }
352
353 return menu;
354 }
355
356
357
358
359
360
361
362
363
364
365 public void setMoreMenuItem(MenuItem item) {
366 if (item != null) {
367 moreItem = item;
368 } else {
369 moreItem = new MenuItemImpl("", null, null);
370 }
371 markAsDirty();
372 }
373
374
375
376
377
378
379 public MenuItem getMoreMenuItem() {
380 return moreItem;
381 }
382
383
384
385
386
387
388
389
390
391
392
393
394
395 public void setAutoOpen(boolean autoOpenTopLevelMenu) {
396 if (autoOpenTopLevelMenu != openRootOnHover) {
397 openRootOnHover = autoOpenTopLevelMenu;
398 markAsDirty();
399 }
400 }
401
402
403
404
405
406
407
408
409
410 public boolean isAutoOpen() {
411 return openRootOnHover;
412 }
413
414 @Override
415 public void readDesign(Element design, DesignContext designContext) {
416 super.readDesign(design, designContext);
417
418 for (Element itemElement : design.children()) {
419 if (itemElement.tagName().equals("menu")) {
420 MenuItem menuItem = readMenuElement(itemElement, null);
421 if (itemElement.hasAttr("more")) {
422 setMoreMenuItem(menuItem);
423 } else {
424 getItems().add(menuItem);
425 }
426 }
427 }
428
429 setHtmlContentAllowed(!design.hasAttr(DESIGN_ATTR_PLAIN_TEXT));
430 }
431
432 @Override
433 protected Collection<String> getCustomAttributes() {
434 Collection<String> result = super.getCustomAttributes();
435 result.add(DESIGN_ATTR_PLAIN_TEXT);
436 result.add("html-content-allowed");
437 return result;
438 }
439
440
441
442 private Menu menu = new AbstractMenu(this);
443
444 @Override
445 public MenuItem addItem(String caption, Command command) {
446 return menu.addItem(caption, command);
447 }
448
449 @Override
450 public MenuItem addItem(String caption, Resource icon, Command command) {
451 return menu.addItem(caption, icon, command);
452 }
453
454 @Override
455 public MenuItem addItemBefore(String caption, Resource icon,
456 Command command, MenuItem itemToAddBefore) {
457 return menu.addItemBefore(caption, icon, command, itemToAddBefore);
458 }
459
460 @Override
461 public List<MenuItem> getItems() {
462 return menu.getItems();
463 }
464
465 @Override
466 public void removeItem(MenuItem item) {
467 menu.removeItem(item);
468 }
469
470 @Override
471 public void removeItems() {
472 menu.removeItems();
473 }
474
475 @Override
476 public int getSize() {
477 return menu.getSize();
478 }
479
480 @Override
481 public void setHtmlContentAllowed(boolean htmlContentAllowed) {
482 menu.setHtmlContentAllowed(htmlContentAllowed);
483 }
484
485 @Override
486 public boolean isHtmlContentAllowed() {
487 return menu.isHtmlContentAllowed();
488 }
489
490
491
492
493
494
495
496
497
498 }