From 1bec9086a719271baf2129358e02855a1d710c44 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Risto=20Yrj=C3=A4n=C3=A4?= Date: Tue, 22 Jul 2008 05:42:33 +0000 Subject: [PATCH] Adds #1946 collapsing + submenu icons. svn changeset:5109/svn branch:trunk --- .../terminal/gwt/client/ui/IMenuBar.java | 161 ++++++++++++++---- src/com/itmill/toolkit/ui/MenuBar.java | 149 ++++++++++++---- 2 files changed, 244 insertions(+), 66 deletions(-) diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IMenuBar.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IMenuBar.java index 58d6f6fdfc..c943b91ea6 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IMenuBar.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IMenuBar.java @@ -1,9 +1,11 @@ package com.itmill.toolkit.terminal.gwt.client.ui; +import java.util.ArrayList; import java.util.Iterator; import java.util.Stack; import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.ui.MenuBar; import com.google.gwt.user.client.ui.MenuItem; import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection; @@ -15,28 +17,44 @@ public class IMenuBar extends MenuBar implements Paintable { /** Set the CSS class name to allow styling. */ public static final String CLASSNAME = "i-menubar"; - /** Component identifier in UIDL communications. */ + /** For server connections **/ protected String uidlId; - - /** Reference to the server connection object. */ protected ApplicationConnection client; - /** A host reference for the Command objects */ protected final IMenuBar hostReference = this; + protected static final boolean vertical = true; + protected String submenuIcon = null; + protected boolean collapseItems = true; + + protected MenuItem moreItem = null; + + // Construct an empty command to be used when the item has no command + // associated + protected static final Command emptyCommand = null; /** * The constructor should first call super() to initialize the component and * then handle any initialization relevant to IT Mill Toolkit. */ public IMenuBar() { - // The superclass has a lot of relevant initialization + // Create an empty horizontal menubar super(); + DOM.setStyleAttribute(this.getElement(), "white-space", "nowrap"); // This method call of the Paintable interface sets the component // style name in DOM tree setStyleName(CLASSNAME); } + public IMenuBar(boolean vertical) { + super(vertical); + DOM.setStyleAttribute(this.getElement(), "white-space", "nowrap"); + + // This method call of the Paintable interface sets the component + // style name in DOM tree + setStyleName(CLASSNAME + "_submenu"); + } + /** * This method must be implemented to update the client-side component from * UIDL data received from server. @@ -51,11 +69,8 @@ public class IMenuBar extends MenuBar implements Paintable { return; } - // Save reference to server connection object to be able to send - // user interaction later + // For future connections this.client = client; - - // Save the UIDL identifier for the component uidlId = uidl.getId(); // Empty the menu every time it receives new information @@ -63,26 +78,47 @@ public class IMenuBar extends MenuBar implements Paintable { this.clearItems(); } - /* Get tree received from server and actualize it in the GWT-MenuBar */ - + UIDL options = uidl.getChildUIDL(0); // For GWT 1.5 - // this.setAnimationEnabled(uidl.getBooleanAttribute("animationEnabled")); + //this.setAnimationEnabled(options.getBooleanAttribute("animationEnabled" + // )) + // ; + + if (options.hasAttribute("submenuIcon")) { + submenuIcon = client.translateToolkitUri(uidl.getChildUIDL(0) + .getStringAttribute("submenuIcon")); + } else { + submenuIcon = null; + } + + collapseItems = options.getBooleanAttribute("collapseItems"); + + if (collapseItems) { + UIDL moreItemUIDL = options.getChildUIDL(0); + StringBuffer itemHTML = new StringBuffer(); + itemHTML.append("

"); + if (moreItemUIDL.hasAttribute("icon")) { + itemHTML.append(""); + } + itemHTML.append(moreItemUIDL.getStringAttribute("text")); + itemHTML.append("

"); + moreItem = new MenuItem(itemHTML.toString(), true, emptyCommand); + } + UIDL items = uidl.getChildUIDL(1); Iterator itr = items.getChildIterator(); Stack iteratorStack = new Stack(); Stack menuStack = new Stack(); MenuBar currentMenu = this; - // Construct an empty command to be used when the item has no command - // associated - Command emptyCommand = new Command() { - public void execute() { - } - }; + // int topLevelWidth = 0; while (itr.hasNext()) { UIDL item = (UIDL) itr.next(); - MenuItem menuItem = null; // For receiving the item + MenuItem currentItem = null; // For receiving the item String itemText = item.getStringAttribute("text"); final int itemId = item.getIntAttribute("id"); @@ -90,46 +126,96 @@ public class IMenuBar extends MenuBar implements Paintable { boolean itemHasCommand = item.getBooleanAttribute("command"); // Construct html from the text and the optional icon - if (!item.hasAttribute("icon")) { - itemText = "

" + itemText + "

"; - } else { - itemText = "

" - + ""); + + if (item.hasAttribute("icon")) { + itemHTML.append("" - + itemText + "

"; + .getStringAttribute("icon")) + + "\" align=\"left\" />"); } - // Check if we need to attach a command to this item + itemHTML.append(itemText); + + if (currentMenu != this && item.getChildCount() > 0 + && submenuIcon != null) { + itemHTML.append(""); + } + + itemHTML.append("

"); + + Command cmd = null; + + // Check if we need to create a command to this item if (itemHasCommand) { // Construct a command that fires onMenuClick(int) with the // item's id-number - Command normalCommand = new Command() { + cmd = new Command() { public void execute() { hostReference.onMenuClick(itemId); } }; - - menuItem = currentMenu.addItem(itemText, true, normalCommand); - - } else { - menuItem = currentMenu.addItem(itemText, true, emptyCommand); } + currentItem = currentMenu.addItem(itemHTML.toString(), true, cmd); + if (item.getChildCount() > 0) { menuStack.push(currentMenu); iteratorStack.push(itr); itr = item.getChildIterator(); - currentMenu = new MenuBar(true); - menuItem.setSubMenu(currentMenu); + currentMenu = new IMenuBar(vertical); + currentItem.setSubMenu(currentMenu); } - if (!itr.hasNext() && !iteratorStack.empty()) { + while (!itr.hasNext() && !iteratorStack.empty()) { itr = (Iterator) iteratorStack.pop(); currentMenu = (MenuBar) menuStack.pop(); } }// while + // we might need to collapse the top-level menu + if (collapseItems) { + int topLevelWidth = 0; + + int ourWidth = this.getOffsetWidth(); + + int i = 0; + for (; i < getItems().size() && topLevelWidth < ourWidth; i++) { + MenuItem item = (MenuItem) getItems().get(i); + topLevelWidth += item.getOffsetWidth(); + } + + if (topLevelWidth > this.getOffsetWidth()) { + ArrayList toBeCollapsed = new ArrayList(); + MenuBar collapsed = new IMenuBar(vertical); + for (int j = i - 2; j < getItems().size(); j++) { + toBeCollapsed.add(getItems().get(j)); + } + + for (int j = 0; j < toBeCollapsed.size(); j++) { + MenuItem item = (MenuItem) toBeCollapsed.get(j); + removeItem(item); + + // it's ugly, but we have to insert the submenu icon + if (item.getSubMenu() != null && submenuIcon != null) { + String itemHTML = item.getHTML(); + StringBuffer itemText = new StringBuffer(itemHTML + .substring(0, itemHTML.length() - 4)); + itemText.append("

"); + item.setHTML(itemText.toString()); + } + + collapsed.addItem(item); + } + + moreItem.setSubMenu(collapsed); + addItem(moreItem); + } + } }// updateFromUIDL /** @@ -137,7 +223,7 @@ public class IMenuBar extends MenuBar implements Paintable { * information to the server * * @param clickedItemId - * id of the item that was clicked + * id of the item that was clicked */ public void onMenuClick(int clickedItemId) { // Updating the state to the server can not be done before @@ -149,4 +235,5 @@ public class IMenuBar extends MenuBar implements Paintable { client.updateVariable(uidlId, "clickedId", clickedItemId, true); } } + }// class IMenuBar diff --git a/src/com/itmill/toolkit/ui/MenuBar.java b/src/com/itmill/toolkit/ui/MenuBar.java index 6428bcca7e..0b137d7484 100644 --- a/src/com/itmill/toolkit/ui/MenuBar.java +++ b/src/com/itmill/toolkit/ui/MenuBar.java @@ -24,6 +24,9 @@ public class MenuBar extends AbstractComponent { private static int numberOfItems = 0; private boolean animationEnabled; + private boolean collapseItems; + private Resource submenuIcon; + private MenuItem moreItem; /** Tag is the UIDL element name for client-server communications. */ public java.lang.String getTag() { @@ -41,6 +44,22 @@ public class MenuBar extends AbstractComponent { target.startTag("options"); target.addAttribute("animationEnabled", animationEnabled); + + if (submenuIcon != null) { + target.addAttribute("submenuIcon", submenuIcon); + } + + target.addAttribute("collapseItems", collapseItems); + + if (collapseItems) { + target.startTag("moreItem"); + target.addAttribute("text", moreItem.getText()); + if (moreItem.getIcon() != null) { + target.addAttribute("icon", moreItem.getIcon()); + } + target.endTag("moreItem"); + } + target.endTag("options"); target.startTag("items"); @@ -77,7 +96,8 @@ public class MenuBar extends AbstractComponent { target.endTag("item"); // Item had no children, end description } - if (!itr.hasNext() && !iteratorStack.empty()) { // The end submenu + // The end submenu. More than one submenu may end at once. + while (!itr.hasNext() && !iteratorStack.empty()) { itr = (Iterator) iteratorStack.pop(); target.endTag("item"); } @@ -114,11 +134,12 @@ public class MenuBar extends AbstractComponent { } } - } + }// while + // If we got the clicked item, launch the command. if (found) { tmpItem.getCommand().menuSelected(tmpItem); - }// while + } }// if }// changeVariables @@ -127,7 +148,9 @@ public class MenuBar extends AbstractComponent { */ public MenuBar() { menuItems = new ArrayList(); - animationEnabled = false; + setAnimation(false); + setCollapse(true); + setMoreMenuItem(null); } /** @@ -135,11 +158,11 @@ public class MenuBar extends AbstractComponent { * caption must be given. * * @param caption - * the text for the menu item + * the text for the menu item * @param icon - * the icon for the menu item + * the icon for the menu item * @param command - * the command for the menu item + * the command for the menu item * @throws IllegalArgumentException */ public MenuBar.MenuItem addItem(String caption, Resource icon, @@ -161,13 +184,13 @@ public class MenuBar extends AbstractComponent { * caption must be given. * * @param caption - * the text for the menu item + * the text for the menu item * @param icon - * the icon for the menu item + * the icon for the menu item * @param command - * the command for the menu item + * the command for the menu item * @param itemToAddBefore - * the item that will be after the new item + * the item that will be after the new item * @throws IllegalArgumentException */ public MenuBar.MenuItem addItemBefore(String caption, Resource icon, @@ -203,7 +226,7 @@ public class MenuBar extends AbstractComponent { * Remove first occurrence the specified item from the main menu * * @param item - * The item to be removed + * The item to be removed */ public void removeItem(MenuBar.MenuItem item) { if (item != null) { @@ -231,12 +254,13 @@ public class MenuBar extends AbstractComponent { /** * Enable or disable animated menubar appearance. Animation is disabled by - * default. + * default. Currently does nothing. * * @param hasAnimation */ public void setAnimation(boolean animation) { animationEnabled = animation; + requestRepaint(); } /** @@ -251,8 +275,75 @@ public class MenuBar extends AbstractComponent { } /** - * This interface contains the layer for menu commands of the MenuBar class . - * It's method will fire when the user clicks on the containing MenuItem. + * Set the icon to be used if a sub-menu has children. Defaults to null; + * + * @param icon + */ + public void setSubmenuIcon(Resource icon) { + submenuIcon = icon; + requestRepaint(); + } + + /** + * Get the icon used for sub-menus. Returns null if no icon is set. + * + * @return + */ + public Resource getSubmenuIcon() { + return submenuIcon; + } + + /** + * Enable or disable collapsing top-level items. Top-level items will + * collapse to if there is not enough room for them. Items that don't fit + * will be placed under the "More" menu item. + * + * Collapsing is enabled by default. + * + * @param collapse + */ + public void setCollapse(boolean collapse) { + collapseItems = collapse; + requestRepaint(); + } + + /** + * Collapsing is enabled by default. + * + * @return true if the top-level items will be collapsed + */ + public boolean getCollapse() { + return collapseItems; + } + + /** + * Set the item that is used when collapsing the top level menu. The item + * command will be ignored. If set to null, the default item with the "More" + * text will be used. + * + * @param item + */ + public void setMoreMenuItem(MenuItem item) { + if (item != null) { + moreItem = item; + } else { + moreItem = new MenuItem("More", null, null); + } + requestRepaint(); + } + + /** + * Get the MenuItem used as the collapse menu item. + * + * @return + */ + public MenuItem getMoreMenuItem() { + return moreItem; + } + + /** + * This interface contains the layer for menu commands of the MenuBar class + * . It's method will fire when the user clicks on the containing MenuItem. * The selected item is given as an argument. */ public interface Command { @@ -280,9 +371,9 @@ public class MenuBar extends AbstractComponent { * caption must be given. * * @param text - * The text associated with the command + * The text associated with the command * @param command - * The command to be fired + * The command to be fired * @throws IllegalArgumentException */ public MenuItem(String caption, Resource icon, MenuBar.Command command) { @@ -309,11 +400,11 @@ public class MenuBar extends AbstractComponent { * command can be null, but a caption must be given. * * @param caption - * the text for the menu item + * the text for the menu item * @param icon - * the icon for the menu item + * the icon for the menu item * @param command - * the command for the menu item + * the command for the menu item */ public MenuBar.MenuItem addItem(String caption, Resource icon, MenuBar.Command command) { @@ -342,13 +433,13 @@ public class MenuBar extends AbstractComponent { * but a caption must be given. * * @param caption - * the text for the menu item + * the text for the menu item * @param icon - * the icon for the menu item + * the icon for the menu item * @param command - * the command for the menu item + * the command for the menu item * @param itemToAddBefore - * the item that will be after the new item + * the item that will be after the new item * */ public MenuBar.MenuItem addItemBefore(String caption, Resource icon, @@ -439,7 +530,7 @@ public class MenuBar extends AbstractComponent { * Set the command for this item. Set null to remove. * * @param command - * The MenuCommand of this item + * The MenuCommand of this item */ public void setCommand(MenuBar.Command command) { itsCommand = command; @@ -449,7 +540,7 @@ public class MenuBar extends AbstractComponent { * Sets the icon. Set null to remove. * * @param icon - * The icon for this item + * The icon for this item */ public void setIcon(Resource icon) { itsIcon = icon; @@ -460,7 +551,7 @@ public class MenuBar extends AbstractComponent { * Set the text of this object. * * @param text - * Text for this object + * Text for this object */ public void setText(java.lang.String text) { if (text != null) { @@ -473,7 +564,7 @@ public class MenuBar extends AbstractComponent { * Remove the first occurrence of the item. * * @param item - * The item to be removed + * The item to be removed */ public void removeChild(MenuBar.MenuItem item) { if (item != null && itsChildren != null) { @@ -500,7 +591,7 @@ public class MenuBar extends AbstractComponent { * Set the parent of this item. This is called by the addItem method. * * @param parent - * The parent item + * The parent item */ protected void setParent(MenuBar.MenuItem parent) { itsParent = parent; -- 2.39.5