Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

MenuBar.java 34KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.ui;
  17. import java.io.Serializable;
  18. import java.util.ArrayList;
  19. import java.util.Collection;
  20. import java.util.Iterator;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.Stack;
  24. import org.jsoup.nodes.Attributes;
  25. import org.jsoup.nodes.Element;
  26. import org.jsoup.nodes.Node;
  27. import org.jsoup.parser.Tag;
  28. import com.vaadin.server.PaintException;
  29. import com.vaadin.server.PaintTarget;
  30. import com.vaadin.server.Resource;
  31. import com.vaadin.shared.ui.menubar.MenuBarConstants;
  32. import com.vaadin.shared.ui.menubar.MenuBarState;
  33. import com.vaadin.ui.Component.Focusable;
  34. import com.vaadin.ui.declarative.DesignAttributeHandler;
  35. import com.vaadin.ui.declarative.DesignContext;
  36. /**
  37. * <p>
  38. * A class representing a horizontal menu bar. The menu can contain MenuItem
  39. * objects, which in turn can contain more MenuBars. These sub-level MenuBars
  40. * are represented as vertical menu.
  41. * </p>
  42. */
  43. @SuppressWarnings("serial")
  44. public class MenuBar extends AbstractComponent
  45. implements LegacyComponent, Focusable {
  46. // Items of the top-level menu
  47. private final List<MenuItem> menuItems;
  48. // Number of items in this menu
  49. private int numberOfItems = 0;
  50. private MenuItem moreItem;
  51. private boolean openRootOnHover;
  52. private boolean htmlContentAllowed;
  53. @Override
  54. protected MenuBarState getState() {
  55. return (MenuBarState) super.getState();
  56. }
  57. @Override
  58. protected MenuBarState getState(boolean markAsDirty) {
  59. return (MenuBarState) super.getState(markAsDirty);
  60. }
  61. /** Paint (serialise) the component for the client. */
  62. @Override
  63. public void paintContent(PaintTarget target) throws PaintException {
  64. target.addAttribute(MenuBarConstants.OPEN_ROOT_MENU_ON_HOWER,
  65. openRootOnHover);
  66. if (isHtmlContentAllowed()) {
  67. target.addAttribute(MenuBarConstants.HTML_CONTENT_ALLOWED, true);
  68. }
  69. target.startTag("options");
  70. if (getWidth() > -1) {
  71. target.startTag("moreItem");
  72. target.addAttribute("text", moreItem.getText());
  73. if (moreItem.getIcon() != null) {
  74. target.addAttribute("icon", moreItem.getIcon());
  75. }
  76. target.endTag("moreItem");
  77. }
  78. target.endTag("options");
  79. target.startTag("items");
  80. // This generates the tree from the contents of the menu
  81. for (MenuItem item : menuItems) {
  82. paintItem(target, item);
  83. }
  84. target.endTag("items");
  85. }
  86. private void paintItem(PaintTarget target, MenuItem item)
  87. throws PaintException {
  88. if (!item.isVisible()) {
  89. return;
  90. }
  91. target.startTag("item");
  92. target.addAttribute("id", item.getId());
  93. if (item.getStyleName() != null) {
  94. target.addAttribute(MenuBarConstants.ATTRIBUTE_ITEM_STYLE,
  95. item.getStyleName());
  96. }
  97. if (item.isSeparator()) {
  98. target.addAttribute("separator", true);
  99. } else {
  100. target.addAttribute("text", item.getText());
  101. Command command = item.getCommand();
  102. if (command != null) {
  103. target.addAttribute("command", true);
  104. }
  105. Resource icon = item.getIcon();
  106. if (icon != null) {
  107. target.addAttribute(MenuBarConstants.ATTRIBUTE_ITEM_ICON, icon);
  108. }
  109. if (!item.isEnabled()) {
  110. target.addAttribute(MenuBarConstants.ATTRIBUTE_ITEM_DISABLED,
  111. true);
  112. }
  113. String description = item.getDescription();
  114. if (description != null && description.length() > 0) {
  115. target.addAttribute(MenuBarConstants.ATTRIBUTE_ITEM_DESCRIPTION,
  116. description);
  117. }
  118. if (item.isCheckable()) {
  119. // if the "checked" attribute is present (either true or false),
  120. // the item is checkable
  121. target.addAttribute(MenuBarConstants.ATTRIBUTE_CHECKED,
  122. item.isChecked());
  123. }
  124. if (item.hasChildren()) {
  125. for (MenuItem child : item.getChildren()) {
  126. paintItem(target, child);
  127. }
  128. }
  129. }
  130. target.endTag("item");
  131. }
  132. /** Deserialize changes received from client. */
  133. @Override
  134. public void changeVariables(Object source, Map<String, Object> variables) {
  135. Stack<MenuItem> items = new Stack<MenuItem>();
  136. boolean found = false;
  137. if (variables.containsKey("clickedId")) {
  138. Integer clickedId = (Integer) variables.get("clickedId");
  139. Iterator<MenuItem> itr = getItems().iterator();
  140. while (itr.hasNext()) {
  141. items.push(itr.next());
  142. }
  143. MenuItem tmpItem = null;
  144. // Go through all the items in the menu
  145. while (!found && !items.empty()) {
  146. tmpItem = items.pop();
  147. found = (clickedId.intValue() == tmpItem.getId());
  148. if (tmpItem.hasChildren()) {
  149. itr = tmpItem.getChildren().iterator();
  150. while (itr.hasNext()) {
  151. items.push(itr.next());
  152. }
  153. }
  154. } // while
  155. // If we got the clicked item, launch the command.
  156. if (found && tmpItem.isEnabled()) {
  157. if (tmpItem.isCheckable()) {
  158. tmpItem.setChecked(!tmpItem.isChecked());
  159. }
  160. if (null != tmpItem.getCommand()) {
  161. tmpItem.getCommand().menuSelected(tmpItem);
  162. }
  163. }
  164. } // if
  165. }// changeVariables
  166. /**
  167. * Constructs an empty, horizontal menu
  168. */
  169. public MenuBar() {
  170. menuItems = new ArrayList<MenuItem>();
  171. setMoreMenuItem(null);
  172. }
  173. /**
  174. * Add a new item to the menu bar. Command can be null, but a caption must
  175. * be given.
  176. *
  177. * @param caption
  178. * the text for the menu item
  179. * @param command
  180. * the command for the menu item
  181. * @throws IllegalArgumentException
  182. */
  183. public MenuBar.MenuItem addItem(String caption, MenuBar.Command command) {
  184. return addItem(caption, null, command);
  185. }
  186. /**
  187. * Add a new item to the menu bar. Icon and command can be null, but a
  188. * caption must be given.
  189. *
  190. * @param caption
  191. * the text for the menu item
  192. * @param icon
  193. * the icon for the menu item
  194. * @param command
  195. * the command for the menu item
  196. * @throws IllegalArgumentException
  197. */
  198. public MenuBar.MenuItem addItem(String caption, Resource icon,
  199. MenuBar.Command command) {
  200. if (caption == null) {
  201. throw new IllegalArgumentException("caption cannot be null");
  202. }
  203. MenuItem newItem = new MenuItem(caption, icon, command);
  204. menuItems.add(newItem);
  205. markAsDirty();
  206. return newItem;
  207. }
  208. /**
  209. * Add an item before some item. If the given item does not exist the item
  210. * is added at the end of the menu. Icon and command can be null, but a
  211. * caption must be given.
  212. *
  213. * @param caption
  214. * the text for the menu item
  215. * @param icon
  216. * the icon for the menu item
  217. * @param command
  218. * the command for the menu item
  219. * @param itemToAddBefore
  220. * the item that will be after the new item
  221. * @throws IllegalArgumentException
  222. */
  223. public MenuBar.MenuItem addItemBefore(String caption, Resource icon,
  224. MenuBar.Command command, MenuBar.MenuItem itemToAddBefore) {
  225. if (caption == null) {
  226. throw new IllegalArgumentException("caption cannot be null");
  227. }
  228. MenuItem newItem = new MenuItem(caption, icon, command);
  229. if (menuItems.contains(itemToAddBefore)) {
  230. int index = menuItems.indexOf(itemToAddBefore);
  231. menuItems.add(index, newItem);
  232. } else {
  233. menuItems.add(newItem);
  234. }
  235. markAsDirty();
  236. return newItem;
  237. }
  238. /**
  239. * Returns a list with all the MenuItem objects in the menu bar
  240. *
  241. * @return a list containing the MenuItem objects in the menu bar
  242. */
  243. public List<MenuItem> getItems() {
  244. return menuItems;
  245. }
  246. /**
  247. * Remove first occurrence the specified item from the main menu
  248. *
  249. * @param item
  250. * The item to be removed
  251. */
  252. public void removeItem(MenuBar.MenuItem item) {
  253. if (item != null) {
  254. menuItems.remove(item);
  255. }
  256. markAsDirty();
  257. }
  258. /**
  259. * Empty the menu bar
  260. */
  261. public void removeItems() {
  262. menuItems.clear();
  263. markAsDirty();
  264. }
  265. /**
  266. * Returns the size of the menu.
  267. *
  268. * @return The size of the menu
  269. */
  270. public int getSize() {
  271. return menuItems.size();
  272. }
  273. /**
  274. * Set the item that is used when collapsing the top level menu. All
  275. * "overflowing" items will be added below this. The item command will be
  276. * ignored. If set to null, the default item with a downwards arrow is used.
  277. *
  278. * The item command (if specified) is ignored.
  279. *
  280. * @param item
  281. */
  282. public void setMoreMenuItem(MenuItem item) {
  283. if (item != null) {
  284. moreItem = item;
  285. } else {
  286. moreItem = new MenuItem("", null, null);
  287. }
  288. markAsDirty();
  289. }
  290. /**
  291. * Get the MenuItem used as the collapse menu item.
  292. *
  293. * @return
  294. */
  295. public MenuItem getMoreMenuItem() {
  296. return moreItem;
  297. }
  298. /**
  299. * Using this method menubar can be put into a special mode where top level
  300. * menus opens without clicking on the menu, but automatically when mouse
  301. * cursor is moved over the menu. In this mode the menu also closes itself
  302. * if the mouse is moved out of the opened menu.
  303. * <p>
  304. * Note, that on touch devices the menu still opens on a click event.
  305. *
  306. * @param autoOpenTopLevelMenu
  307. * true if menus should be opened without click, the default is
  308. * false
  309. */
  310. public void setAutoOpen(boolean autoOpenTopLevelMenu) {
  311. if (autoOpenTopLevelMenu != openRootOnHover) {
  312. openRootOnHover = autoOpenTopLevelMenu;
  313. markAsDirty();
  314. }
  315. }
  316. /**
  317. * Detects whether the menubar is in a mode where top level menus are
  318. * automatically opened when the mouse cursor is moved over the menu.
  319. * Normally root menu opens only by clicking on the menu. Submenus always
  320. * open automatically.
  321. *
  322. * @return true if the root menus open without click, the default is false
  323. */
  324. public boolean isAutoOpen() {
  325. return openRootOnHover;
  326. }
  327. /**
  328. * Sets whether html is allowed in the item captions. If set to true, the
  329. * captions are passed to the browser as html and the developer is
  330. * responsible for ensuring no harmful html is used. If set to false, the
  331. * content is passed to the browser as plain text.
  332. *
  333. * @param htmlContentAllowed
  334. * true if the captions are used as html, false if used as plain
  335. * text
  336. */
  337. public void setHtmlContentAllowed(boolean htmlContentAllowed) {
  338. this.htmlContentAllowed = htmlContentAllowed;
  339. markAsDirty();
  340. }
  341. /**
  342. * Checks whether item captions are interpreted as html or plain text.
  343. *
  344. * @return true if the captions are used as html, false if used as plain
  345. * text
  346. * @see #setHtmlContentAllowed(boolean)
  347. */
  348. public boolean isHtmlContentAllowed() {
  349. return htmlContentAllowed;
  350. }
  351. @Override
  352. public int getTabIndex() {
  353. return getState(false).tabIndex;
  354. }
  355. /*
  356. * (non-Javadoc)
  357. *
  358. * @see com.vaadin.ui.Component.Focusable#setTabIndex(int)
  359. */
  360. @Override
  361. public void setTabIndex(int tabIndex) {
  362. getState().tabIndex = tabIndex;
  363. }
  364. @Override
  365. public void focus() {
  366. // Overridden only to make public
  367. super.focus();
  368. }
  369. /**
  370. * This interface contains the layer for menu commands of the
  371. * {@link com.vaadin.ui.MenuBar} class. It's method will fire when the user
  372. * clicks on the containing {@link com.vaadin.ui.MenuBar.MenuItem}. The
  373. * selected item is given as an argument.
  374. */
  375. public interface Command extends Serializable {
  376. public void menuSelected(MenuBar.MenuItem selectedItem);
  377. }
  378. /**
  379. * A composite class for menu items and sub-menus. You can set commands to
  380. * be fired on user click by implementing the
  381. * {@link com.vaadin.ui.MenuBar.Command} interface. You can also add
  382. * multiple MenuItems to a MenuItem and create a sub-menu.
  383. *
  384. */
  385. public class MenuItem implements Serializable {
  386. /** Private members * */
  387. private final int itsId;
  388. private Command itsCommand;
  389. private String itsText;
  390. private List<MenuItem> itsChildren;
  391. private Resource itsIcon;
  392. private MenuItem itsParent;
  393. private boolean enabled = true;
  394. private boolean visible = true;
  395. private boolean isSeparator = false;
  396. private String styleName;
  397. private String description;
  398. private boolean checkable = false;
  399. private boolean checked = false;
  400. /**
  401. * Constructs a new menu item that can optionally have an icon and a
  402. * command associated with it. Icon and command can be null, but a
  403. * caption must be given.
  404. *
  405. * @param text
  406. * The text associated with the command
  407. * @param command
  408. * The command to be fired
  409. * @throws IllegalArgumentException
  410. */
  411. public MenuItem(String caption, Resource icon,
  412. MenuBar.Command command) {
  413. if (caption == null) {
  414. throw new IllegalArgumentException("caption cannot be null");
  415. }
  416. itsId = ++numberOfItems;
  417. itsText = caption;
  418. itsIcon = icon;
  419. itsCommand = command;
  420. }
  421. /**
  422. * Checks if the item has children (if it is a sub-menu).
  423. *
  424. * @return True if this item has children
  425. */
  426. public boolean hasChildren() {
  427. return !isSeparator() && itsChildren != null;
  428. }
  429. /**
  430. * Adds a separator to this menu. A separator is a way to visually group
  431. * items in a menu, to make it easier for users to find what they are
  432. * looking for in the menu.
  433. *
  434. * @author Jouni Koivuviita / Vaadin Ltd.
  435. * @since 6.2.0
  436. */
  437. public MenuBar.MenuItem addSeparator() {
  438. MenuItem item = addItem("", null, null);
  439. item.setSeparator(true);
  440. return item;
  441. }
  442. public MenuBar.MenuItem addSeparatorBefore(MenuItem itemToAddBefore) {
  443. MenuItem item = addItemBefore("", null, null, itemToAddBefore);
  444. item.setSeparator(true);
  445. return item;
  446. }
  447. /**
  448. * Add a new item inside this item, thus creating a sub-menu. Command
  449. * can be null, but a caption must be given.
  450. *
  451. * @param caption
  452. * the text for the menu item
  453. * @param command
  454. * the command for the menu item
  455. */
  456. public MenuBar.MenuItem addItem(String caption,
  457. MenuBar.Command command) {
  458. return addItem(caption, null, command);
  459. }
  460. /**
  461. * Add a new item inside this item, thus creating a sub-menu. Icon and
  462. * command can be null, but a caption must be given.
  463. *
  464. * @param caption
  465. * the text for the menu item
  466. * @param icon
  467. * the icon for the menu item
  468. * @param command
  469. * the command for the menu item
  470. * @throws IllegalStateException
  471. * If the item is checkable and thus cannot have children.
  472. */
  473. public MenuBar.MenuItem addItem(String caption, Resource icon,
  474. MenuBar.Command command) throws IllegalStateException {
  475. if (isSeparator()) {
  476. throw new UnsupportedOperationException(
  477. "Cannot add items to a separator");
  478. }
  479. if (isCheckable()) {
  480. throw new IllegalStateException(
  481. "A checkable item cannot have children");
  482. }
  483. if (caption == null) {
  484. throw new IllegalArgumentException("Caption cannot be null");
  485. }
  486. if (itsChildren == null) {
  487. itsChildren = new ArrayList<MenuItem>();
  488. }
  489. MenuItem newItem = new MenuItem(caption, icon, command);
  490. // The only place where the parent is set
  491. newItem.setParent(this);
  492. itsChildren.add(newItem);
  493. markAsDirty();
  494. return newItem;
  495. }
  496. /**
  497. * Add an item before some item. If the given item does not exist the
  498. * item is added at the end of the menu. Icon and command can be null,
  499. * but a caption must be given.
  500. *
  501. * @param caption
  502. * the text for the menu item
  503. * @param icon
  504. * the icon for the menu item
  505. * @param command
  506. * the command for the menu item
  507. * @param itemToAddBefore
  508. * the item that will be after the new item
  509. * @throws IllegalStateException
  510. * If the item is checkable and thus cannot have children.
  511. */
  512. public MenuBar.MenuItem addItemBefore(String caption, Resource icon,
  513. MenuBar.Command command, MenuBar.MenuItem itemToAddBefore)
  514. throws IllegalStateException {
  515. if (isCheckable()) {
  516. throw new IllegalStateException(
  517. "A checkable item cannot have children");
  518. }
  519. MenuItem newItem = null;
  520. if (hasChildren() && itsChildren.contains(itemToAddBefore)) {
  521. int index = itsChildren.indexOf(itemToAddBefore);
  522. newItem = new MenuItem(caption, icon, command);
  523. newItem.setParent(this);
  524. itsChildren.add(index, newItem);
  525. } else {
  526. newItem = addItem(caption, icon, command);
  527. }
  528. markAsDirty();
  529. return newItem;
  530. }
  531. /**
  532. * For the associated command.
  533. *
  534. * @return The associated command, or null if there is none
  535. */
  536. public Command getCommand() {
  537. return itsCommand;
  538. }
  539. /**
  540. * Gets the objects icon.
  541. *
  542. * @return The icon of the item, null if the item doesn't have an icon
  543. */
  544. public Resource getIcon() {
  545. return itsIcon;
  546. }
  547. /**
  548. * For the containing item. This will return null if the item is in the
  549. * top-level menu bar.
  550. *
  551. * @return The containing {@link com.vaadin.ui.MenuBar.MenuItem} , or
  552. * null if there is none
  553. */
  554. public MenuBar.MenuItem getParent() {
  555. return itsParent;
  556. }
  557. /**
  558. * This will return the children of this item or null if there are none.
  559. *
  560. * @return List of children items, or null if there are none
  561. */
  562. public List<MenuItem> getChildren() {
  563. return itsChildren;
  564. }
  565. /**
  566. * Gets the objects text
  567. *
  568. * @return The text
  569. */
  570. public java.lang.String getText() {
  571. return itsText;
  572. }
  573. /**
  574. * Returns the number of children.
  575. *
  576. * @return The number of child items
  577. */
  578. public int getSize() {
  579. if (itsChildren != null) {
  580. return itsChildren.size();
  581. }
  582. return -1;
  583. }
  584. /**
  585. * Get the unique identifier for this item.
  586. *
  587. * @return The id of this item
  588. */
  589. public int getId() {
  590. return itsId;
  591. }
  592. /**
  593. * Set the command for this item. Set null to remove.
  594. *
  595. * @param command
  596. * The MenuCommand of this item
  597. */
  598. public void setCommand(MenuBar.Command command) {
  599. itsCommand = command;
  600. }
  601. /**
  602. * Sets the icon. Set null to remove.
  603. *
  604. * @param icon
  605. * The icon for this item
  606. */
  607. public void setIcon(Resource icon) {
  608. itsIcon = icon;
  609. markAsDirty();
  610. }
  611. /**
  612. * Set the text of this object.
  613. *
  614. * @param text
  615. * Text for this object
  616. */
  617. public void setText(java.lang.String text) {
  618. if (text != null) {
  619. itsText = text;
  620. }
  621. markAsDirty();
  622. }
  623. /**
  624. * Remove the first occurrence of the item.
  625. *
  626. * @param item
  627. * The item to be removed
  628. */
  629. public void removeChild(MenuBar.MenuItem item) {
  630. if (item != null && itsChildren != null) {
  631. itsChildren.remove(item);
  632. if (itsChildren.isEmpty()) {
  633. itsChildren = null;
  634. }
  635. markAsDirty();
  636. }
  637. }
  638. /**
  639. * Empty the list of children items.
  640. */
  641. public void removeChildren() {
  642. if (itsChildren != null) {
  643. itsChildren.clear();
  644. itsChildren = null;
  645. markAsDirty();
  646. }
  647. }
  648. /**
  649. * Set the parent of this item. This is called by the addItem method.
  650. *
  651. * @param parent
  652. * The parent item
  653. */
  654. protected void setParent(MenuBar.MenuItem parent) {
  655. itsParent = parent;
  656. }
  657. public void setEnabled(boolean enabled) {
  658. this.enabled = enabled;
  659. markAsDirty();
  660. }
  661. public boolean isEnabled() {
  662. return enabled;
  663. }
  664. public void setVisible(boolean visible) {
  665. this.visible = visible;
  666. markAsDirty();
  667. }
  668. public boolean isVisible() {
  669. return visible;
  670. }
  671. private void setSeparator(boolean isSeparator) {
  672. this.isSeparator = isSeparator;
  673. markAsDirty();
  674. }
  675. public boolean isSeparator() {
  676. return isSeparator;
  677. }
  678. public void setStyleName(String styleName) {
  679. this.styleName = styleName;
  680. markAsDirty();
  681. }
  682. public String getStyleName() {
  683. return styleName;
  684. }
  685. /**
  686. * Sets the items's description. See {@link #getDescription()} for more
  687. * information on what the description is. This method will trigger a
  688. * {@link RepaintRequestEvent}.
  689. *
  690. * @param description
  691. * the new description string for the component.
  692. */
  693. public void setDescription(String description) {
  694. this.description = description;
  695. markAsDirty();
  696. }
  697. /**
  698. * <p>
  699. * Gets the items's description. The description can be used to briefly
  700. * describe the state of the item to the user. The description string
  701. * may contain certain XML tags:
  702. * </p>
  703. *
  704. * <p>
  705. * <table border=1>
  706. * <tr>
  707. * <td width=120><b>Tag</b></td>
  708. * <td width=120><b>Description</b></td>
  709. * <td width=120><b>Example</b></td>
  710. * </tr>
  711. * <tr>
  712. * <td>&lt;b></td>
  713. * <td>bold</td>
  714. * <td><b>bold text</b></td>
  715. * </tr>
  716. * <tr>
  717. * <td>&lt;i></td>
  718. * <td>italic</td>
  719. * <td><i>italic text</i></td>
  720. * </tr>
  721. * <tr>
  722. * <td>&lt;u></td>
  723. * <td>underlined</td>
  724. * <td><u>underlined text</u></td>
  725. * </tr>
  726. * <tr>
  727. * <td>&lt;br></td>
  728. * <td>linebreak</td>
  729. * <td>N/A</td>
  730. * </tr>
  731. * <tr>
  732. * <td>&lt;ul><br>
  733. * &lt;li>item1<br>
  734. * &lt;li>item1<br>
  735. * &lt;/ul></td>
  736. * <td>item list</td>
  737. * <td>
  738. * <ul>
  739. * <li>item1
  740. * <li>item2
  741. * </ul>
  742. * </td>
  743. * </tr>
  744. * </table>
  745. * </p>
  746. *
  747. * <p>
  748. * These tags may be nested.
  749. * </p>
  750. *
  751. * @return item's description <code>String</code>
  752. */
  753. public String getDescription() {
  754. return description;
  755. }
  756. /**
  757. * Gets the checkable state of the item - whether the item has checked
  758. * and unchecked states. If an item is checkable its checked state (as
  759. * returned by {@link #isChecked()}) is indicated in the UI.
  760. *
  761. * <p>
  762. * An item is not checkable by default.
  763. * </p>
  764. *
  765. * @return true if the item is checkable, false otherwise
  766. * @since 6.6.2
  767. */
  768. public boolean isCheckable() {
  769. return checkable;
  770. }
  771. /**
  772. * Sets the checkable state of the item. If an item is checkable its
  773. * checked state (as returned by {@link #isChecked()}) is indicated in
  774. * the UI.
  775. *
  776. * <p>
  777. * An item is not checkable by default.
  778. * </p>
  779. *
  780. * <p>
  781. * Items with sub items cannot be checkable.
  782. * </p>
  783. *
  784. * @param checkable
  785. * true if the item should be checkable, false otherwise
  786. * @throws IllegalStateException
  787. * If the item has children
  788. * @since 6.6.2
  789. */
  790. public void setCheckable(boolean checkable)
  791. throws IllegalStateException {
  792. if (hasChildren()) {
  793. throw new IllegalStateException(
  794. "A menu item with children cannot be checkable");
  795. }
  796. this.checkable = checkable;
  797. markAsDirty();
  798. }
  799. /**
  800. * Gets the checked state of the item (checked or unchecked). Only used
  801. * if the item is checkable (as indicated by {@link #isCheckable()}).
  802. * The checked state is indicated in the UI with the item, if the item
  803. * is checkable.
  804. *
  805. * <p>
  806. * An item is not checked by default.
  807. * </p>
  808. *
  809. * <p>
  810. * The CSS style corresponding to the checked state is "-checked".
  811. * </p>
  812. *
  813. * @return true if the item is checked, false otherwise
  814. * @since 6.6.2
  815. */
  816. public boolean isChecked() {
  817. return checked;
  818. }
  819. /**
  820. * Sets the checked state of the item. Only used if the item is
  821. * checkable (indicated by {@link #isCheckable()}). The checked state is
  822. * indicated in the UI with the item, if the item is checkable.
  823. *
  824. * <p>
  825. * An item is not checked by default.
  826. * </p>
  827. *
  828. * <p>
  829. * The CSS style corresponding to the checked state is "-checked".
  830. * </p>
  831. *
  832. * @return true if the item is checked, false otherwise
  833. * @since 6.6.2
  834. */
  835. public void setChecked(boolean checked) {
  836. this.checked = checked;
  837. markAsDirty();
  838. }
  839. }// class MenuItem
  840. @Override
  841. public void writeDesign(Element design, DesignContext designContext) {
  842. super.writeDesign(design, designContext);
  843. for (MenuItem item : getItems()) {
  844. design.appendChild(createMenuElement(item));
  845. }
  846. // in many cases there seems to be an empty more menu item
  847. if (getMoreMenuItem() != null
  848. && !getMoreMenuItem().getText().isEmpty()) {
  849. Element moreMenu = createMenuElement(getMoreMenuItem());
  850. moreMenu.attr("more", true);
  851. design.appendChild(moreMenu);
  852. }
  853. if (!htmlContentAllowed) {
  854. design.attr(DESIGN_ATTR_PLAIN_TEXT, true);
  855. }
  856. }
  857. protected Element createMenuElement(MenuItem item) {
  858. Element menuElement = new Element(Tag.valueOf("menu"), "");
  859. // Defaults
  860. MenuItem def = new MenuItem("", null, null);
  861. Attributes attr = menuElement.attributes();
  862. DesignAttributeHandler.writeAttribute("icon", attr, item.getIcon(),
  863. def.getIcon(), Resource.class);
  864. DesignAttributeHandler.writeAttribute("disabled", attr,
  865. !item.isEnabled(), !def.isEnabled(), boolean.class);
  866. DesignAttributeHandler.writeAttribute("visible", attr, item.isVisible(),
  867. def.isVisible(), boolean.class);
  868. DesignAttributeHandler.writeAttribute("separator", attr,
  869. item.isSeparator(), def.isSeparator(), boolean.class);
  870. DesignAttributeHandler.writeAttribute("checkable", attr,
  871. item.isCheckable(), def.isCheckable(), boolean.class);
  872. DesignAttributeHandler.writeAttribute("checked", attr, item.isChecked(),
  873. def.isChecked(), boolean.class);
  874. DesignAttributeHandler.writeAttribute("description", attr,
  875. item.getDescription(), def.getDescription(), String.class);
  876. DesignAttributeHandler.writeAttribute("style-name", attr,
  877. item.getStyleName(), def.getStyleName(), String.class);
  878. menuElement.append(item.getText());
  879. if (item.hasChildren()) {
  880. for (MenuItem subMenu : item.getChildren()) {
  881. menuElement.appendChild(createMenuElement(subMenu));
  882. }
  883. }
  884. return menuElement;
  885. }
  886. protected MenuItem readMenuElement(Element menuElement) {
  887. Resource icon = null;
  888. if (menuElement.hasAttr("icon")) {
  889. icon = DesignAttributeHandler.getFormatter()
  890. .parse(menuElement.attr("icon"), Resource.class);
  891. }
  892. String caption = "";
  893. List<Element> subMenus = new ArrayList<Element>();
  894. for (Node node : menuElement.childNodes()) {
  895. if (node instanceof Element
  896. && ((Element) node).tagName().equals("menu")) {
  897. subMenus.add((Element) node);
  898. } else {
  899. caption += node.toString();
  900. }
  901. }
  902. MenuItem menu = new MenuItem(caption.trim(), icon, null);
  903. Attributes attr = menuElement.attributes();
  904. if (menuElement.hasAttr("icon")) {
  905. menu.setIcon(DesignAttributeHandler.readAttribute("icon", attr,
  906. Resource.class));
  907. }
  908. if (menuElement.hasAttr("disabled")) {
  909. menu.setEnabled(!DesignAttributeHandler.readAttribute("disabled",
  910. attr, boolean.class));
  911. }
  912. if (menuElement.hasAttr("visible")) {
  913. menu.setVisible(DesignAttributeHandler.readAttribute("visible",
  914. attr, boolean.class));
  915. }
  916. if (menuElement.hasAttr("separator")) {
  917. menu.setSeparator(DesignAttributeHandler.readAttribute("separator",
  918. attr, boolean.class));
  919. }
  920. if (menuElement.hasAttr("checkable")) {
  921. menu.setCheckable(DesignAttributeHandler.readAttribute("checkable",
  922. attr, boolean.class));
  923. }
  924. if (menuElement.hasAttr("checked")) {
  925. menu.setChecked(DesignAttributeHandler.readAttribute("checked",
  926. attr, boolean.class));
  927. }
  928. if (menuElement.hasAttr("description")) {
  929. menu.setDescription(DesignAttributeHandler
  930. .readAttribute("description", attr, String.class));
  931. }
  932. if (menuElement.hasAttr("style-name")) {
  933. menu.setStyleName(DesignAttributeHandler.readAttribute("style-name",
  934. attr, String.class));
  935. }
  936. if (!subMenus.isEmpty()) {
  937. menu.itsChildren = new ArrayList<MenuItem>();
  938. }
  939. for (Element subMenu : subMenus) {
  940. MenuItem newItem = readMenuElement(subMenu);
  941. newItem.setParent(menu);
  942. menu.itsChildren.add(newItem);
  943. }
  944. return menu;
  945. }
  946. @Override
  947. public void readDesign(Element design, DesignContext designContext) {
  948. super.readDesign(design, designContext);
  949. for (Element itemElement : design.children()) {
  950. if (itemElement.tagName().equals("menu")) {
  951. MenuItem menuItem = readMenuElement(itemElement);
  952. if (itemElement.hasAttr("more")) {
  953. setMoreMenuItem(menuItem);
  954. } else {
  955. menuItems.add(menuItem);
  956. }
  957. }
  958. }
  959. setHtmlContentAllowed(!design.hasAttr(DESIGN_ATTR_PLAIN_TEXT));
  960. }
  961. @Override
  962. protected Collection<String> getCustomAttributes() {
  963. Collection<String> result = super.getCustomAttributes();
  964. result.add(DESIGN_ATTR_PLAIN_TEXT);
  965. result.add("html-content-allowed");
  966. return result;
  967. }
  968. }// class MenuBar