]> source.dussan.org Git - vaadin-framework.git/commitdiff
Use MenuBar in Grid's sidebar for column hiding #17332
authorPekka Hyvönen <pekka@vaadin.com>
Wed, 8 Apr 2015 08:46:28 +0000 (11:46 +0300)
committerVaadin Code Review <review@vaadin.com>
Thu, 9 Apr 2015 06:39:45 +0000 (06:39 +0000)
Change-Id: I3b15430c6f8dab6dadcd84ddf280153e91192c5f

client/src/com/vaadin/client/widgets/Grid.java
uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java

index ed7c0d180094fb867fbfae9bd5effea411511563..9efea31d0238746fc6e6a2b46afcfc8674c4a1b5 100644 (file)
@@ -49,6 +49,8 @@ import com.google.gwt.dom.client.Touch;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
 import com.google.gwt.event.dom.client.KeyEvent;
 import com.google.gwt.event.dom.client.MouseEvent;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
@@ -66,8 +68,9 @@ import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.HasEnabled;
 import com.google.gwt.user.client.ui.HasWidgets;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
 import com.google.gwt.user.client.ui.ResizeComposite;
-import com.google.gwt.user.client.ui.ToggleButton;
 import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.client.BrowserInfo;
 import com.vaadin.client.DeferredWorker;
@@ -3049,6 +3052,8 @@ public class Grid<T> extends ResizeComposite implements
 
         private final FlowPanel content;
 
+        private final MenuBar menuBar;
+
         private final Button openCloseButton;
 
         private final Grid<?> grid;
@@ -3076,6 +3081,63 @@ public class Grid<T> extends ResizeComposite implements
                     return removed;
                 }
             };
+
+            menuBar = new MenuBar(true) {
+
+                @Override
+                public MenuItem addItem(MenuItem item) {
+                    if (getParent() == null) {
+                        content.insert(this, 0);
+                        updateVisibility();
+                    }
+                    return super.addItem(item);
+                }
+
+                @Override
+                public void removeItem(MenuItem item) {
+                    super.removeItem(item);
+                    if (getItems().isEmpty()) {
+                        menuBar.removeFromParent();
+                    }
+                }
+
+                @Override
+                public void onBrowserEvent(Event event) {
+                    // selecting a item with enter will lose the focus and
+                    // selected item, which means that further keyboard
+                    // selection won't work unless we do this:
+                    if (event.getTypeInt() == Event.ONKEYDOWN
+                            && event.getKeyCode() == KeyCodes.KEY_ENTER) {
+                        final MenuItem item = getSelectedItem();
+                        super.onBrowserEvent(event);
+                        Scheduler.get().scheduleDeferred(
+                                new ScheduledCommand() {
+
+                                    @Override
+                                    public void execute() {
+                                        selectItem(item);
+                                        focus();
+                                    }
+                                });
+
+                    } else {
+                        super.onBrowserEvent(event);
+                    }
+                }
+
+            };
+            KeyDownHandler keyDownHandler = new KeyDownHandler() {
+
+                @Override
+                public void onKeyDown(KeyDownEvent event) {
+                    if (event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
+                        close();
+                    }
+                }
+            };
+            openCloseButton.addDomHandler(keyDownHandler,
+                    KeyDownEvent.getType());
+            menuBar.addDomHandler(keyDownHandler, KeyDownEvent.getType());
         }
 
         /**
@@ -3085,6 +3147,7 @@ public class Grid<T> extends ResizeComposite implements
         public void open() {
             if (!isOpen() && isInDOM()) {
                 addStyleName("opened");
+                removeStyleName("closed");
                 rootContainer.add(content);
             }
         }
@@ -3095,6 +3158,7 @@ public class Grid<T> extends ResizeComposite implements
         public void close() {
             if (isOpen()) {
                 removeStyleName("opened");
+                addStyleName("closed");
                 content.removeFromParent();
             }
         }
@@ -3153,6 +3217,13 @@ public class Grid<T> extends ResizeComposite implements
             super.setStylePrimaryName(styleName);
             content.setStylePrimaryName(styleName + "-content");
             openCloseButton.setStylePrimaryName(styleName + "-button");
+            if (isOpen()) {
+                addStyleName("open");
+                removeStyleName("closed");
+            } else {
+                removeStyleName("open");
+                addStyleName("closed");
+            }
         }
 
         private void updateVisibility() {
@@ -3171,98 +3242,97 @@ public class Grid<T> extends ResizeComposite implements
         private boolean isInDOM() {
             return getParent() != null;
         }
-
     }
 
     /**
      * UI and functionality related to hiding columns with toggles in the
      * sidebar.
      */
-    private final class ColumnHider extends FlowPanel {
-
-        ColumnHider() {
-            setStyleName("column-hiding-panel");
-        }
+    private final class ColumnHider {
 
         /** Map from columns to their hiding toggles, component might change */
-        private HashMap<Column<?, T>, ToggleButton> columnToHidingToggleMap = new HashMap<Grid.Column<?, T>, ToggleButton>();
+        private HashMap<Column<?, T>, MenuItem> columnToHidingToggleMap = new HashMap<Grid.Column<?, T>, MenuItem>();
+
+        /**
+         * When column is being hidden with a toggle, do not refresh toggles for
+         * no reason. Also helps for keeping the keyboard navigation working.
+         */
+        private boolean hidingColumn;
 
         private void updateColumnHidable(final Column<?, T> column) {
             if (column.isHidable()) {
-                ToggleButton cb = columnToHidingToggleMap.get(column);
-                if (cb == null) {
-                    cb = createToggle(column);
+                MenuItem toggle = columnToHidingToggleMap.get(column);
+                if (toggle == null) {
+                    toggle = createToggle(column);
                 }
-                updateToggleValue(cb, column.isHidden());
-            } else if (columnToHidingToggleMap.containsValue(column)) {
-                ((Widget) columnToHidingToggleMap.remove(column))
-                        .removeFromParent();
+                toggle.setStyleName("hidden", column.isHidden());
+            } else if (columnToHidingToggleMap.containsKey(column)) {
+                sidebar.menuBar.removeItem((columnToHidingToggleMap
+                        .remove(column)));
             }
             updateTogglesOrder();
-            updatePanelVisibility();
         }
 
-        private ToggleButton createToggle(final Column<?, T> column) {
-            ToggleButton toggle = new ToggleButton();
-            toggle.addStyleName("column-hiding-toggle");
-            toggle.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
+        private MenuItem createToggle(final Column<?, T> column) {
+            MenuItem toggle = new MenuItem(createHTML(column), true,
+                    new ScheduledCommand() {
 
-                @Override
-                public void onValueChange(ValueChangeEvent<Boolean> event) {
-                    column.setHidden(!event.getValue(), true);
-                }
-            });
-            updateHidingToggleCaption(column, toggle);
+                        @Override
+                        public void execute() {
+                            hidingColumn = true;
+                            column.setHidden(!column.isHidden(), true);
+                            hidingColumn = false;
+                        }
+                    });
+            toggle.addStyleName("column-hiding-toggle");
             columnToHidingToggleMap.put(column, toggle);
             return toggle;
         }
 
-        private void updateTogglesOrder() {
-            clear();
-            for (Column<?, T> c : getColumns()) {
-                if (c.isHidable()) {
-                    add(columnToHidingToggleMap.get(c));
-                }
+        private String createHTML(Column<?, T> column) {
+            final StringBuffer buf = new StringBuffer();
+            buf.append("<span class=\"");
+            if (column.isHidden()) {
+                buf.append("v-off");
+            } else {
+                buf.append("v-on");
             }
-        }
+            buf.append("\"><div>");
+            String caption = column.getHidingToggleCaption();
+            if (caption == null) {
+                caption = column.headerCaption;
+            }
+            buf.append(caption);
+            buf.append("</div></span>");
 
-        private void updatePanelVisibility() {
-            final boolean columnHidable = getWidgetCount() > 0;
-            final boolean columnTogglesPanelIsVisible = getParent() != null;
+            return buf.toString();
+        }
 
-            if (columnHidable && !columnTogglesPanelIsVisible) {
-                sidebar.insert(this, 0);
-            } else if (!columnHidable && columnTogglesPanelIsVisible) {
-                sidebar.remove(this);
+        private void updateTogglesOrder() {
+            if (!hidingColumn) {
+                for (Column<?, T> column : getColumns()) {
+                    if (column.isHidable()) {
+                        final MenuItem menuItem = columnToHidingToggleMap
+                                .get(column);
+                        sidebar.menuBar.removeItem(menuItem);
+                        sidebar.menuBar.addItem(menuItem);
+                    }
+                }
             }
         }
 
-        private void updateToggleValue(Column<?, T> column) {
+        private void updateHidingToggle(Column<?, T> column) {
             if (column.isHidable()) {
-                updateToggleValue(columnToHidingToggleMap.get(column),
-                        column.isHidden());
+                MenuItem toggle = columnToHidingToggleMap.get(column);
+                toggle.setHTML(createHTML(column));
+                toggle.setStyleName("hidden", column.isHidden());
             } // else we can just ignore
         }
 
-        private void updateToggleValue(ToggleButton hasValue, boolean hidden) {
-            hasValue.setValue(!hidden, false);
-            hasValue.setStyleName("hidden", hidden);
-        }
-
-        private void updateHidingToggleCaption(Column<?, T> column) {
-            updateHidingToggleCaption(column,
-                    columnToHidingToggleMap.get(column));
+        private void removeColumnHidingToggle(Column<?, T> column) {
+            sidebar.menuBar.removeItem(columnToHidingToggleMap.get(column));
         }
 
-        private void updateHidingToggleCaption(Column<?, T> column,
-                ToggleButton toggle) {
-            String caption = column.getHidingToggleCaption();
-            if (caption == null) {
-                caption = column.headerCaption;
-                // the caption might still be null, but that is the users fault
-            }
-            toggle.setText(caption);
-        }
     }
 
     /**
@@ -4007,7 +4077,7 @@ public class Grid<T> extends ResizeComposite implements
             if (row != null) {
                 row.getCell(this).setText(headerCaption);
                 if (isHidable()) {
-                    grid.columnHider.updateHidingToggleCaption(this);
+                    grid.columnHider.updateHidingToggle(this);
                 }
             }
         }
@@ -4207,7 +4277,7 @@ public class Grid<T> extends ResizeComposite implements
                                 .setFrozenColumnCount(++escalatorFrozenColumns);
                     }
                 }
-                grid.columnHider.updateToggleValue(this);
+                grid.columnHider.updateHidingToggle(this);
                 grid.header.updateColSpans();
                 grid.footer.updateColSpans();
                 scheduleColumnWidthRecalculator();
@@ -4276,7 +4346,7 @@ public class Grid<T> extends ResizeComposite implements
         public void setHidingToggleCaption(String hidingToggleCaption) {
             this.hidingToggleCaption = hidingToggleCaption;
             if (isHidable()) {
-                grid.columnHider.updateHidingToggleCaption(this);
+                grid.columnHider.updateHidingToggle(this);
             }
         }
 
@@ -5019,6 +5089,7 @@ public class Grid<T> extends ResizeComposite implements
         escalator.setStylePrimaryName(style);
         editor.setStylePrimaryName(style);
         sidebar.setStylePrimaryName(style + "-sidebar");
+        sidebar.addStyleName("v-contextmenu");
 
         String rowStyle = getStylePrimaryName() + "-row";
         rowHasDataStyleName = rowStyle + "-has-data";
@@ -5261,7 +5332,7 @@ public class Grid<T> extends ResizeComposite implements
         columns.remove(columnIndex);
 
         if (column.isHidable()) {
-            columnHider.updateColumnHidable(column);
+            columnHider.removeColumnHidingToggle(column);
         }
     }
 
index 94620f34bd2a186698c5e690c3ec6657d5dfe956..2abd603ae4b3f292c61a87923320fca49b0f3f64 100644 (file)
@@ -759,7 +759,6 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
     @SuppressWarnings("boxing")
     protected void createColumnActions() {
         createCategory("Columns", null);
-
         for (int c = 0; c < COLUMNS; c++) {
             final int index = c;
             createCategory(getColumnProperty(c), "Columns");
@@ -974,6 +973,17 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
 
                     }, c);
         }
+        createBooleanAction("All columns hidable", "Columns", false,
+                new Command<Grid, Boolean>() {
+
+                    @Override
+                    public void execute(Grid c, Boolean value, Object data) {
+                        for (Column col : grid.getColumns()) {
+                            col.setHidable(value);
+                        }
+
+                    }
+                });
     }
 
     private static String getColumnProperty(int c) {