]> source.dussan.org Git - vaadin-framework.git/commitdiff
Adds #1946 collapsing + submenu icons.
authorRisto Yrjänä <risto.yrjana@itmill.com>
Tue, 22 Jul 2008 05:42:33 +0000 (05:42 +0000)
committerRisto Yrjänä <risto.yrjana@itmill.com>
Tue, 22 Jul 2008 05:42:33 +0000 (05:42 +0000)
svn changeset:5109/svn branch:trunk

src/com/itmill/toolkit/terminal/gwt/client/ui/IMenuBar.java
src/com/itmill/toolkit/ui/MenuBar.java

index 58d6f6fdfc4b7c0ae844390478ad95160ecb14bb..c943b91ea6c66a74f9343e7ce3b597d232efd48f 100644 (file)
@@ -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("<p>");
+            if (moreItemUIDL.hasAttribute("icon")) {
+                itemHTML.append("<img src=\""
+                        + client.translateToolkitUri(moreItemUIDL
+                                .getStringAttribute("icon"))
+                        + "\" align=\"left\" />");
+            }
+            itemHTML.append(moreItemUIDL.getStringAttribute("text"));
+            itemHTML.append("</p>");
+            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 = "<p>" + itemText + "</p>";
-            } else {
-                itemText = "<p>"
-                        + "<img src=\""
+            StringBuffer itemHTML = new StringBuffer();
+
+            itemHTML.append("<p>");
+
+            if (item.hasAttribute("icon")) {
+                itemHTML.append("<img src=\""
                         + client.translateToolkitUri(item
-                                .getStringAttribute("icon")) + "\"</img>"
-                        + itemText + "</p>";
+                                .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("<img src=\"" + submenuIcon
+                        + "\" align=\"right\" />");
+            }
+
+            itemHTML.append("</p>");
+
+            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("<img src=\"" + submenuIcon
+                                + "\" align=\"right\" /></p>");
+                        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
index 6428bcca7e998f5a13ffb17702fb720031e8cdbd..0b137d7484c0d31344ef309094db9777e6e7015d 100644 (file)
@@ -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;