]> source.dussan.org Git - vaadin-framework.git/commitdiff
MenuBar fixes:
authorJouni Koivuviita <jouni.koivuviita@itmill.com>
Sun, 8 Nov 2009 20:17:30 +0000 (20:17 +0000)
committerJouni Koivuviita <jouni.koivuviita@itmill.com>
Sun, 8 Nov 2009 20:17:30 +0000 (20:17 +0000)
 * Fixes #2849: Deprecate MenuBar.setSubmenuIcon method, and provide the same functionality via CSS
 * Fixes #2821: Sumbenu icon is not aligned with the menu item's text
 * Fixes #3482: MenuItem: Subitem is wrongly marked as selected

Deprecated setCollapse method at the same time, redundant method (the feature should always be enabled).

svn changeset:9675/svn branch:6.2

WebContent/VAADIN/themes/base/menubar/menubar.css
WebContent/VAADIN/themes/base/styles.css
WebContent/VAADIN/themes/reindeer/menubar/menubar.css
WebContent/VAADIN/themes/reindeer/styles.css
WebContent/VAADIN/themes/runo/menubar/menubar.css
WebContent/VAADIN/themes/runo/styles.css
src/com/vaadin/terminal/gwt/client/ui/Icon.java
src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
src/com/vaadin/ui/MenuBar.java

index e39598d7f2692c211974af1d1de6441b8bf82ab1..610fb4d9b48841f51f7ec453b7672773521473ba 100644 (file)
@@ -1,23 +1,20 @@
 .v-menubar table {
-       white-space: nowrap;
-       border-collapse: collapse;
-       padding: 0;
-       margin: 0;
-}
-.v-menubar table {
-       white-space: nowrap;
        border-collapse: collapse;
        padding: 0;
        margin: 0;
 }
 .v-menubar .menuitem {
        cursor: default;
+       vertical-align: middle;
+       white-space: nowrap;
+}
+.v-menubar .menuitem * {
+       vertical-align: middle;
 }
 .v-menubar-submenu {
        background: #fff;
 }
 .v-menubar-submenu table {
-       white-space: nowrap;
        border-collapse: collapse;
        padding: 0;
        margin: 0;
 }
 .v-menubar-submenu .menuitem { 
        cursor: default;
+       vertical-align: middle;
+       white-space: nowrap;
+}
+.v-menubar-submenu .menuitem * { 
+       vertical-align: middle;
+}
+.v-menubar .v-menubar-submenu-indicator {
+       display: none;
+}
+.v-menubar-submenu .v-menubar-submenu-indicator {
+       margin-left: 1em;
+       float: right;
+       height: 100%;
+       font-size: 0.9em;
 }
\ No newline at end of file
index 5752bd803bbd9bce2651842e88fcb4c558cc309b..6fbb87bf51c6785385340f134d1888640f85013f 100644 (file)
@@ -622,25 +622,22 @@ div.v-app-loading {
 }
 
 .v-menubar table {
-       white-space: nowrap;
-       border-collapse: collapse;
-       padding: 0;
-       margin: 0;
-}
-.v-menubar table {
-       white-space: nowrap;
        border-collapse: collapse;
        padding: 0;
        margin: 0;
 }
 .v-menubar .menuitem {
        cursor: default;
+       vertical-align: middle;
+       white-space: nowrap;
+}
+.v-menubar .menuitem * {
+       vertical-align: middle;
 }
 .v-menubar-submenu {
        background: #fff;
 }
 .v-menubar-submenu table {
-       white-space: nowrap;
        border-collapse: collapse;
        padding: 0;
        margin: 0;
@@ -657,6 +654,20 @@ div.v-app-loading {
 }
 .v-menubar-submenu .menuitem { 
        cursor: default;
+       vertical-align: middle;
+       white-space: nowrap;
+}
+.v-menubar-submenu .menuitem * { 
+       vertical-align: middle;
+}
+.v-menubar .v-menubar-submenu-indicator {
+       display: none;
+}
+.v-menubar-submenu .v-menubar-submenu-indicator {
+       margin-left: 1em;
+       float: right;
+       height: 100%;
+       font-size: 0.9em;
 }
 
 .v-Notification {
index a5090003cdae300eef02d1af8d86409ba4f06511..ae156fa596652aa47c9b456920916a9cd24d42f7 100644 (file)
@@ -7,12 +7,13 @@
        text-shadow: rgba(0,0,0,.9) 0 1px 0;
 }
 .v-menubar table {
-       margin-left: 8px;
+       margin: 0 8px;
        height: 23px;
 }
 .v-menubar .menuitem {
        padding: 3px 8px;
        height: 17px;
+       line-height: 16px;
 }
 .v-menubar-submenu {
        background: #f8f8f9;
@@ -27,6 +28,7 @@
 .v-menubar-submenu .menuitem {
        padding: 1px 15px 1px 10px;
        height: 16px;
+       line-height: 16px;
 }
 .v-menubar .menuitem-selected,
 .v-menubar-submenu .menuitem-selected {
 .v-menubar .menuitem-selected {
        background-image: url(img/menu-sel-bg.png); /** sprite-ref: verticals; sprite-alignment: repeat */
 }
-
-/* Submenu icon (remove after #2849 is fixed) */
-.v-menubar-submenu .menuitem img[align="right"] {
-       margin-right: -15px;
-}
-.v-ie .v-menubar-submenu .menuitem img[align="right"] {
-       margin-top: -14px;
+.v-menubar-submenu .v-menubar-submenu-indicator {
+       background: transparent url(img/submenu-icon.png) no-repeat right 50%;
+       display: inline;
+       display: inline-block;
+       zoom: 1;
+       width: 16px;
+       margin: 0 -15px 0 5px;
+       text-indent: -999px;
+       vertical-align: middle;
+}
+.v-menubar-submenu .menuitem-selected .v-menubar-submenu-indicator {
+       background-image: url(img/submenu-icon-hover.png);
 }
\ No newline at end of file
index 99aa1d9b4546af107d494beec25fc4203ed293de..ad09f5b1e5ac793324767ffd3b67c6a430cd5164 100644 (file)
@@ -622,25 +622,22 @@ div.v-app-loading {
 }
 
 .v-menubar table {
-       white-space: nowrap;
-       border-collapse: collapse;
-       padding: 0;
-       margin: 0;
-}
-.v-menubar table {
-       white-space: nowrap;
        border-collapse: collapse;
        padding: 0;
        margin: 0;
 }
 .v-menubar .menuitem {
        cursor: default;
+       vertical-align: middle;
+       white-space: nowrap;
+}
+.v-menubar .menuitem * {
+       vertical-align: middle;
 }
 .v-menubar-submenu {
        background: #fff;
 }
 .v-menubar-submenu table {
-       white-space: nowrap;
        border-collapse: collapse;
        padding: 0;
        margin: 0;
@@ -657,6 +654,20 @@ div.v-app-loading {
 }
 .v-menubar-submenu .menuitem { 
        cursor: default;
+       vertical-align: middle;
+       white-space: nowrap;
+}
+.v-menubar-submenu .menuitem * { 
+       vertical-align: middle;
+}
+.v-menubar .v-menubar-submenu-indicator {
+       display: none;
+}
+.v-menubar-submenu .v-menubar-submenu-indicator {
+       margin-left: 1em;
+       float: right;
+       height: 100%;
+       font-size: 0.9em;
 }
 
 .v-Notification {
@@ -2979,12 +2990,13 @@ td.v-datefield-calendarpanel-nextyear {
        text-shadow: rgba(0,0,0,.9) 0 1px 0;
 }
 .v-menubar table {
-       margin-left: 8px;
+       margin: 0 8px;
        height: 23px;
 }
 .v-menubar .menuitem {
        padding: 3px 8px;
        height: 17px;
+       line-height: 16px;
 }
 .v-menubar-submenu {
        background: #f8f8f9;
@@ -2999,6 +3011,7 @@ td.v-datefield-calendarpanel-nextyear {
 .v-menubar-submenu .menuitem {
        padding: 1px 15px 1px 10px;
        height: 16px;
+       line-height: 16px;
 }
 .v-menubar .menuitem-selected,
 .v-menubar-submenu .menuitem-selected {
@@ -3014,13 +3027,18 @@ td.v-datefield-calendarpanel-nextyear {
   -background-image: url(common/img/vertical-sprites-ie6.png);
   background-position: left -423px;
 }
-
-/* Submenu icon (remove after #2849 is fixed) */
-.v-menubar-submenu .menuitem img[align="right"] {
-       margin-right: -15px;
+.v-menubar-submenu .v-menubar-submenu-indicator {
+       background: transparent url(menubar/img/submenu-icon.png) no-repeat right 50%;
+       display: inline;
+       display: inline-block;
+       zoom: 1;
+       width: 16px;
+       margin: 0 -15px 0 5px;
+       text-indent: -999px;
+       vertical-align: middle;
 }
-.v-ie .v-menubar-submenu .menuitem img[align="right"] {
-       margin-top: -14px;
+.v-menubar-submenu .menuitem-selected .v-menubar-submenu-indicator {
+       background-image: url(menubar/img/submenu-icon-hover.png);
 }
 
 .v-Notification {
index 650d00b1f2a3b8e963853dd11479c4cf8a40f91e..6ef4b93fc6aa94589a91ea248e3cca44b978c73a 100644 (file)
@@ -29,4 +29,7 @@
 .v-menubar-submenu .menuitem-selected {
        color: #fff;
        background: #5daee8;
+}
+.v-menubar-submenu .v-menubar-submenu-indicator {
+       margin-right: -3px;
 }
\ No newline at end of file
index 17b09dde1fd683ffcecff86f51c7f35b814a7ae1..815d09cdc3f434a2c5df793a0854a2b6b01ac635 100644 (file)
@@ -622,25 +622,22 @@ div.v-app-loading {
 }
 
 .v-menubar table {
-       white-space: nowrap;
-       border-collapse: collapse;
-       padding: 0;
-       margin: 0;
-}
-.v-menubar table {
-       white-space: nowrap;
        border-collapse: collapse;
        padding: 0;
        margin: 0;
 }
 .v-menubar .menuitem {
        cursor: default;
+       vertical-align: middle;
+       white-space: nowrap;
+}
+.v-menubar .menuitem * {
+       vertical-align: middle;
 }
 .v-menubar-submenu {
        background: #fff;
 }
 .v-menubar-submenu table {
-       white-space: nowrap;
        border-collapse: collapse;
        padding: 0;
        margin: 0;
@@ -657,6 +654,20 @@ div.v-app-loading {
 }
 .v-menubar-submenu .menuitem { 
        cursor: default;
+       vertical-align: middle;
+       white-space: nowrap;
+}
+.v-menubar-submenu .menuitem * { 
+       vertical-align: middle;
+}
+.v-menubar .v-menubar-submenu-indicator {
+       display: none;
+}
+.v-menubar-submenu .v-menubar-submenu-indicator {
+       margin-left: 1em;
+       float: right;
+       height: 100%;
+       font-size: 0.9em;
 }
 
 .v-Notification {
@@ -2142,6 +2153,9 @@ div.v-tree-node-leaf {
        color: #fff;
        background: #5daee8;
 }
+.v-menubar-submenu .v-menubar-submenu-indicator {
+       margin-right: -3px;
+}
 
 .v-Notification {
        font-family: "Trebuchet MS", geneva, helvetica, arial, tahoma, verdana, sans-serif;
index 1ee19c1d177b5a51b0caaf15459e9286b00c2af6..eba1a9bd784edcc46c2b5854501cdb280524e9a4 100644 (file)
@@ -10,13 +10,14 @@ import com.google.gwt.user.client.ui.UIObject;
 import com.vaadin.terminal.gwt.client.ApplicationConnection;
 
 public class Icon extends UIObject {
+    public static final String CLASSNAME = "v-icon";
     private final ApplicationConnection client;
     private String myUri;
 
     public Icon(ApplicationConnection client) {
         setElement(DOM.createImg());
         DOM.setElementProperty(getElement(), "alt", "");
-        setStyleName("v-icon");
+        setStyleName(CLASSNAME);
         this.client = client;
         client.addPngFix(getElement());
     }
index 5bfaea92432faa576307ceccae00a6312de9c401..22f35fe30f402dbf52209124dc56cfb77dd9b3ae 100644 (file)
@@ -14,14 +14,16 @@ import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.HasHTML;
 import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.RootPanel;
 import com.google.gwt.user.client.ui.UIObject;
 import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.ContainerResizedListener;
 import com.vaadin.terminal.gwt.client.Paintable;
 import com.vaadin.terminal.gwt.client.UIDL;
 
 public class VMenuBar extends Widget implements Paintable,
-        CloseHandler<PopupPanel> {
+        CloseHandler<PopupPanel>, ContainerResizedListener {
 
     /** Set the CSS class name to allow styling. */
     public static final String CLASSNAME = "v-menubar";
@@ -32,8 +34,8 @@ public class VMenuBar extends Widget implements Paintable,
 
     protected final VMenuBar hostReference = this;
     protected String submenuIcon = null;
-    protected boolean collapseItems = true;
     protected CustomMenuItem moreItem = null;
+    protected VMenuBar collapsedRootItems;
 
     // Construct an empty command to be used when the item has no command
     // associated
@@ -83,7 +85,7 @@ public class VMenuBar extends Widget implements Paintable,
     /**
      * This method must be implemented to update the client-side component from
      * UIDL data received from server.
-     *
+     * 
      * This method is called when the page is loaded for the first time, and
      * every time UI changes in the component are received from the server.
      */
@@ -112,21 +114,22 @@ public class VMenuBar extends Widget implements Paintable,
             submenuIcon = null;
         }
 
-        collapseItems = options.getBooleanAttribute("collapseItems");
-
-        if (collapseItems) {
+        if (uidl.hasAttribute("width")) {
             UIDL moreItemUIDL = options.getChildUIDL(0);
             StringBuffer itemHTML = new StringBuffer();
 
             if (moreItemUIDL.hasAttribute("icon")) {
                 itemHTML.append("<img src=\""
                         + client.translateVaadinUri(moreItemUIDL
-                                .getStringAttribute("icon"))
-                        + "\" align=\"left\" />");
+                                .getStringAttribute("icon")) + "\" class=\""
+                        + Icon.CLASSNAME + "\" alt=\"\" />");
             }
             itemHTML.append(moreItemUIDL.getStringAttribute("text"));
 
             moreItem = new CustomMenuItem(itemHTML.toString(), emptyCommand);
+            collapsedRootItems = new VMenuBar(true);
+            moreItem.setSubMenu(collapsedRootItems);
+            moreItem.addStyleName(CLASSNAME + "-more-menuitem");
         }
 
         UIDL uidlItems = uidl.getChildUIDL(1);
@@ -150,16 +153,24 @@ public class VMenuBar extends Widget implements Paintable,
             if (item.hasAttribute("icon")) {
                 itemHTML.append("<img src=\""
                         + client.translateVaadinUri(item
-                                .getStringAttribute("icon"))
-                        + "\" align=\"left\" />");
+                                .getStringAttribute("icon")) + "\" class=\""
+                        + Icon.CLASSNAME + "\" alt=\"\" />");
             }
 
             itemHTML.append(itemText);
 
-            if (currentMenu != this && item.getChildCount() > 0
-                    && submenuIcon != null) {
-                itemHTML.append("<img src=\"" + submenuIcon
-                        + "\" align=\"right\" />");
+            // Add submenu indicator
+            if (item.getChildCount() > 0) {
+                // FIXME For compatibility reasons: remove in version 7
+                String bgStyle = "";
+                if (submenuIcon != null) {
+                    bgStyle = " style=\"background-image: url(" + submenuIcon
+                            + "); text-indent: -999px; width: 1em;\"";
+                }
+                itemHTML
+                        .append("<span class=\"" + CLASSNAME
+                                + "-submenu-indicator\"" + bgStyle
+                                + ">&#x25B6;</span>");
             }
 
             Command cmd = null;
@@ -190,54 +201,14 @@ public class VMenuBar extends Widget implements Paintable,
             }
         }// while
 
-        // we might need to collapse the top-level menu
-        // Only needed if there is more than 1 top level item
-        // TODO and if width is defined
-        if (collapseItems && getItems().size() > 1) {
-
-            int topLevelWidth = 0;
-
-            int ourWidth = getOffsetWidth();
-
-            int i = 0;
-            for (; i < getItems().size() && topLevelWidth < ourWidth; i++) {
-                CustomMenuItem item = getItems().get(i);
-                topLevelWidth += item.getOffsetWidth();
-            }
-
-            if (topLevelWidth > getOffsetWidth()) {
-                ArrayList<CustomMenuItem> toBeCollapsed = new ArrayList<CustomMenuItem>();
-                VMenuBar collapsed = new VMenuBar(true);
-                for (int j = i - 2; j < getItems().size(); j++) {
-                    toBeCollapsed.add(getItems().get(j));
-                }
-
-                for (int j = 0; j < toBeCollapsed.size(); j++) {
-                    CustomMenuItem item = toBeCollapsed.get(j);
-                    removeItem(item);
-
-                    // it's ugly, but we have to insert the submenu icon
-                    if (item.getSubMenu() != null && submenuIcon != null) {
-                        StringBuffer itemText = new StringBuffer(item.getHTML());
-                        itemText.append("<img src=\"");
-                        itemText.append(submenuIcon);
-                        itemText.append("\" align=\"right\" />");
-                        item.setHTML(itemText.toString());
-                    }
+        iLayout();
 
-                    collapsed.addItem(item);
-                }
-
-                moreItem.setSubMenu(collapsed);
-                addItem(moreItem);
-            }
-        }
     }// updateFromUIDL
 
     /**
      * This is called by the items in the menu and it communicates the
      * information to the server
-     *
+     * 
      * @param clickedItemId
      *            id of the item that was clicked
      */
@@ -274,7 +245,7 @@ public class VMenuBar extends Widget implements Paintable,
 
     /**
      * Returns the containing element of the menu
-     *
+     * 
      * @return
      */
     public Element getContainingElement() {
@@ -283,23 +254,30 @@ public class VMenuBar extends Widget implements Paintable,
 
     /**
      * Returns a new child element to add an item to
-     *
+     * 
+     * @param index
+     *            the index in which point to add a new element in a submenu. -1
+     *            will add the new element as the last child (append)
+     * 
      * @return
      */
-    public Element getNewChildElement() {
+    public Element getNewChildElement(int index) {
         if (subMenu) {
             Element tr = DOM.createTR();
-            DOM.appendChild(getContainingElement(), tr);
+            if (index == -1) {
+                DOM.appendChild(getContainingElement(), tr);
+            } else {
+                DOM.insertChild(getContainingElement(), tr, index);
+            }
             return tr;
         } else {
             return getContainingElement();
         }
-
     }
 
     /**
      * Add a new item to this menu
-     *
+     * 
      * @param html
      *            items text
      * @param cmd
@@ -314,19 +292,36 @@ public class VMenuBar extends Widget implements Paintable,
 
     /**
      * Add a new item to this menu
-     *
+     * 
      * @param item
      */
     public void addItem(CustomMenuItem item) {
-        DOM.appendChild(getNewChildElement(), item.getElement());
+        if (items.contains(item)) {
+            return;
+        }
+        DOM.appendChild(getNewChildElement(-1), item.getElement());
         item.setParentMenu(this);
         item.setSelected(false);
         items.add(item);
     }
 
+    public void addItem(CustomMenuItem item, int index) {
+        if (items.contains(item)) {
+            return;
+        }
+        if (subMenu) {
+            DOM.appendChild(getNewChildElement(index), item.getElement());
+        } else {
+            DOM.insertChild(getNewChildElement(-1), item.getElement(), index);
+        }
+        item.setParentMenu(this);
+        item.setSelected(false);
+        items.add(index, item);
+    }
+
     /**
      * Remove the given item from this menu
-     *
+     * 
      * @param item
      */
     public void removeItem(CustomMenuItem item) {
@@ -377,7 +372,7 @@ public class VMenuBar extends Widget implements Paintable,
 
     /**
      * When an item is clicked
-     *
+     * 
      * @param item
      */
     public void itemClick(CustomMenuItem item) {
@@ -402,7 +397,7 @@ public class VMenuBar extends Widget implements Paintable,
 
     /**
      * When the user hovers the mouse over the item
-     *
+     * 
      * @param item
      */
     public void itemOver(CustomMenuItem item) {
@@ -412,7 +407,6 @@ public class VMenuBar extends Widget implements Paintable,
 
         if (menuWasVisible && visibleChildMenu != item.getSubMenu()) {
             popup.hide();
-            visibleChildMenu = null;
         }
 
         if (item.getSubMenu() != null && (parentMenu != null || menuWasVisible)
@@ -423,7 +417,7 @@ public class VMenuBar extends Widget implements Paintable,
 
     /**
      * When the mouse is moved away from an item
-     *
+     * 
      * @param item
      */
     public void itemOut(CustomMenuItem item) {
@@ -436,34 +430,49 @@ public class VMenuBar extends Widget implements Paintable,
     /**
      * Shows the child menu of an item. The caller must ensure that the item has
      * a submenu.
-     *
+     * 
      * @param item
      */
     public void showChildMenu(CustomMenuItem item) {
         popup = new VOverlay(true, false, true);
         popup.setWidget(item.getSubMenu());
         popup.addCloseHandler(this);
-
+        int left = 0;
+        int top = 0;
         if (subMenu) {
-            popup.setPopupPosition(item.getParentMenu().getAbsoluteLeft()
-                    + item.getParentMenu().getOffsetWidth(), item
-                    .getAbsoluteTop());
+            left = item.getParentMenu().getAbsoluteLeft()
+                    + item.getParentMenu().getOffsetWidth();
+            top = item.getAbsoluteTop();
         } else {
-            popup.setPopupPosition(item.getAbsoluteLeft(), item.getParentMenu()
-                    .getAbsoluteTop()
-                    + item.getParentMenu().getOffsetHeight());
+            left = item.getAbsoluteLeft();
+            top = item.getParentMenu().getAbsoluteTop()
+                    + item.getParentMenu().getOffsetHeight();
         }
+        popup.setPopupPosition(left, top);
 
         item.getSubMenu().onShow();
         visibleChildMenu = item.getSubMenu();
         item.getSubMenu().setParentMenu(this);
 
         popup.show();
+
+        if (left + popup.getOffsetWidth() >= RootPanel.getBodyElement()
+                .getOffsetWidth()) {
+            if (subMenu) {
+                left = item.getParentMenu().getAbsoluteLeft()
+                        - popup.getOffsetWidth();
+            } else {
+                left = RootPanel.getBodyElement().getOffsetWidth()
+                        - popup.getOffsetWidth();
+                ApplicationConnection.getConsole().log("" + left);
+            }
+            popup.setPopupPosition(left, top);
+        }
     }
 
     /**
      * Hides the submenu of an item
-     *
+     * 
      * @param item
      */
     public void hideChildMenu(CustomMenuItem item) {
@@ -478,8 +487,10 @@ public class VMenuBar extends Widget implements Paintable,
      * When the menu is shown.
      */
     public void onShow() {
-        if (!items.isEmpty()) {
-            (items.get(0)).setSelected(true);
+        // remove possible previous selection
+        if (selected != null) {
+            selected.setSelected(false);
+            selected = null;
         }
     }
 
@@ -511,7 +522,7 @@ public class VMenuBar extends Widget implements Paintable,
     /**
      * Returns the parent menu of this menu, or null if this is the top-level
      * menu
-     *
+     * 
      * @return
      */
     public VMenuBar getParentMenu() {
@@ -520,7 +531,7 @@ public class VMenuBar extends Widget implements Paintable,
 
     /**
      * Set the parent menu of this menu
-     *
+     * 
      * @param parent
      */
     public void setParentMenu(VMenuBar parent) {
@@ -530,7 +541,7 @@ public class VMenuBar extends Widget implements Paintable,
     /**
      * Returns the currently selected item of this menu, or null if nothing is
      * selected
-     *
+     * 
      * @return
      */
     public CustomMenuItem getSelected() {
@@ -539,7 +550,7 @@ public class VMenuBar extends Widget implements Paintable,
 
     /**
      * Set the currently selected item of this menu
-     *
+     * 
      * @param item
      */
     public void setSelected(CustomMenuItem item) {
@@ -563,16 +574,15 @@ public class VMenuBar extends Widget implements Paintable,
         if (event.isAutoClosed()) {
             hideParents();
         }
-        // setSelected(null);
         visibleChildMenu = null;
         popup = null;
 
     }
 
     /**
-     *
+     * 
      * A class to hold information on menu items
-     *
+     * 
      */
     private class CustomMenuItem extends UIObject implements HasHTML {
 
@@ -646,4 +656,73 @@ public class VMenuBar extends Widget implements Paintable,
         }
     }
 
-}// class VMenuBar
+    /**
+     * @author Jouni Koivuviita / IT Mill Ltd.
+     */
+
+    public void iLayout() {
+        // Only collapse if there is more than one item in the root menu and the
+        // menu has an explicit size
+        if ((getItems().size() > 1 || collapsedRootItems.getItems().size() > 0)
+                && getElement().getStyle().getProperty("width") != null) {
+
+            // Measure the width of the "more" item
+            final boolean morePresent = getItems().contains(moreItem);
+            addItem(moreItem);
+            final int moreItemWidth = moreItem.getOffsetWidth();
+            if (!morePresent) {
+                removeItem(moreItem);
+            }
+
+            // Measure available space
+            int availableWidth = getElement().getClientWidth();
+            final int rootWidth = getElement().getFirstChildElement()
+                    .getOffsetWidth();
+            int diff = availableWidth - rootWidth;
+
+            removeItem(moreItem);
+
+            if (diff < 0) {
+                // Too many items: collapse last items from root menu
+                final int widthNeeded = moreItemWidth - diff;
+                int widthReduced = 0;
+
+                while (widthReduced < widthNeeded && getItems().size() > 0) {
+                    // Move last root menu item to collapsed menu
+                    CustomMenuItem collapse = getItems().get(
+                            getItems().size() - 1);
+                    widthReduced += collapse.getOffsetWidth();
+                    removeItem(collapse);
+                    collapsedRootItems.addItem(collapse, 0);
+                }
+            } else if (collapsedRootItems.getItems().size() > 0) {
+                // Space available for items: expand first items from collapsed
+                // menu
+                int widthAvailable = diff + moreItemWidth;
+                int widthGrowth = 0;
+
+                while (widthAvailable > widthGrowth) {
+                    // Move first item from collapsed menu to the root menu
+                    CustomMenuItem expand = collapsedRootItems.getItems()
+                            .get(0);
+                    collapsedRootItems.removeItem(expand);
+                    addItem(expand);
+                    widthGrowth += expand.getOffsetWidth();
+                    if (collapsedRootItems.getItems().size() > 0) {
+                        widthAvailable -= moreItemWidth;
+                    }
+                    if (widthGrowth > widthAvailable) {
+                        removeItem(expand);
+                        collapsedRootItems.addItem(expand, 0);
+                    } else {
+                        widthAvailable = diff;
+                    }
+                }
+            }
+            if (collapsedRootItems.getItems().size() > 0) {
+                addItem(moreItem);
+            }
+        }
+    }
+
+}
index 30049431d383487b306e0e6f9104b1b871bd697f..c0939d23ed7f4c1085cd5aa9e20f9a46627f397d 100644 (file)
@@ -29,8 +29,20 @@ public class MenuBar extends AbstractComponent {
     // Number of items in this menu
     private static int numberOfItems = 0;
 
+    /**
+     * @deprecated
+     * @see #setCollapse(boolean)
+     */
+    @Deprecated
     private boolean collapseItems;
+
+    /**
+     * @deprecated
+     * @see #setSubmenuIcon(Resource)
+     */
+    @Deprecated
     private Resource submenuIcon;
+
     private MenuItem moreItem;
 
     /** Paint (serialise) the component for the client. */
@@ -49,9 +61,7 @@ public class MenuBar extends AbstractComponent {
             target.addAttribute("submenuIcon", submenuIcon);
         }
 
-        target.addAttribute("collapseItems", collapseItems);
-
-        if (collapseItems) {
+        if (getWidth() > -1) {
             target.startTag("moreItem");
             target.addAttribute("text", moreItem.getText());
             if (moreItem.getIcon() != null) {
@@ -270,40 +280,46 @@ public class MenuBar extends AbstractComponent {
      * Set the icon to be used if a sub-menu has children. Defaults to null;
      * 
      * @param icon
+     * @deprecated (since 6.2, will be removed in 7.0) Icon is set in theme, no
+     *             need to worry about the visual representation here.
      */
+    @Deprecated
     public void setSubmenuIcon(Resource icon) {
         submenuIcon = icon;
         requestRepaint();
     }
 
     /**
-     * Get the icon used for sub-menus. Returns null if no icon is set.
-     * 
-     * @return
+     * @deprecated
+     * @see #setSubmenuIcon(Resource)
      */
+    @Deprecated
     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.
+     * collapse together 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
+     * @deprecated (since 6.2, will be removed in 7.0) Collapsing is always
+     *             enabled if the MenuBar has a specified width.
      */
+    @Deprecated
     public void setCollapse(boolean collapse) {
         collapseItems = collapse;
         requestRepaint();
     }
 
     /**
-     * Collapsing is enabled by default.
-     * 
-     * @return true if the top-level items will be collapsed
+     * @see #setCollapse(boolean)
+     * @deprecated
      */
+    @Deprecated
     public boolean getCollapse() {
         return collapseItems;
     }
@@ -311,16 +327,18 @@ public class MenuBar extends AbstractComponent {
     /**
      * Set the item that is used when collapsing the top level menu. All
      * "overflowing" items will be added below this. The item command will be
-     * ignored. If set to null, the default item with the "More" text is be
+     * ignored. If set to null, the default item with the "More..." text is be
      * used.
      * 
+     * The item command (if specified) is ignored.
+     * 
      * @param item
      */
     public void setMoreMenuItem(MenuItem item) {
         if (item != null) {
             moreItem = item;
         } else {
-            moreItem = new MenuItem("More", null, null);
+            moreItem = new MenuItem("More...", null, null);
         }
         requestRepaint();
     }