View Javadoc
1   package com.vaadin.contextmenu.client;
2   
3   import com.google.gwt.core.client.Scheduler;
4   import com.google.gwt.core.client.Scheduler.ScheduledCommand;
5   import com.google.gwt.event.dom.client.KeyCodes;
6   import com.google.gwt.user.client.Command;
7   import com.vaadin.client.ui.VMenuBar;
8   import com.vaadin.client.ui.VOverlay;
9   
10  /**
11   * This is just to overcome the issue of application connection. Not needed
12   * later, after this issue is resolved in the framework.
13   */
14  public class MyVMenuBar extends VMenuBar {
15  
16      // FIXME: this should be properly set for all context menus
17      private boolean isContextMenu = true;
18  
19      public MyVMenuBar() {
20      }
21  
22      public MyVMenuBar(boolean subMenu, VMenuBar parentMenu) {
23          super(subMenu, parentMenu);
24      }
25  
26      @Override
27      protected VOverlay createOverlay() {
28          return new MyVOverlay(true, false);
29      }
30  
31      // overridden to be visible for the connector
32      @Override
33      protected void showChildMenuAt(CustomMenuItem item, int top, int left) {
34          super.showChildMenuAt(item, top, left);
35      }
36  
37      // this method has a couple lines added, marked with FIXME
38      @Override
39      public boolean handleNavigation(int keycode, boolean ctrl, boolean shift) {
40  
41          // If tab or shift+tab close menus
42          if (keycode == KeyCodes.KEY_TAB) {
43              setSelected(null);
44              hideChildren();
45              menuVisible = false;
46              return false;
47          }
48  
49          if (ctrl || shift || !enabled) {
50              // Do not handle tab key, nor ctrl keys
51              return false;
52          }
53  
54          if (keycode == getNavigationLeftKey()) {
55              if (getSelected() == null) {
56                  // If nothing is selected then select the last item
57                  setSelected(items.get(items.size() - 1));
58                  if (!getSelected().isSelectable()) {
59                      handleNavigation(keycode, ctrl, shift);
60                  }
61              } else if (visibleChildMenu == null && getParentMenu() == null) {
62                  // If this is the root menu then move to the left
63                  int idx = items.indexOf(getSelected());
64                  if (idx > 0) {
65                      setSelected(items.get(idx - 1));
66                  } else {
67                      setSelected(items.get(items.size() - 1));
68                  }
69  
70                  if (!getSelected().isSelectable()) {
71                      handleNavigation(keycode, ctrl, shift);
72                  }
73              } else if (visibleChildMenu != null) {
74                  // Redirect all navigation to the submenu
75                  visibleChildMenu.handleNavigation(keycode, ctrl, shift);
76  
77              } else if (getParentMenu().getParentMenu() == null) {
78  
79                  // FIXME: this line added
80                  if (isContextMenu) {
81                      return true;
82                  }
83  
84                  // Inside a sub menu, whose parent is a root menu item
85                  VMenuBar root = getParentMenu();
86  
87                  root.getSelected().getSubMenu().setSelected(null);
88                  // #15255 - disable animate-in/out when hide popup
89                  root.hideChildren(false, false);
90  
91                  // Get the root menus items and select the previous one
92                  int idx = root.getItems().indexOf(root.getSelected());
93                  idx = idx > 0 ? idx : root.getItems().size();
94                  CustomMenuItem selected = root.getItems().get(--idx);
95  
96                  while (selected.isSeparator() || !selected.isEnabled()) {
97                      idx = idx > 0 ? idx : root.getItems().size();
98                      selected = root.getItems().get(--idx);
99                  }
100 
101                 root.setSelected(selected);
102                 openMenuAndFocusFirstIfPossible(selected);
103             } else {
104                 getParentMenu().getSelected().getSubMenu().setSelected(null);
105                 getParentMenu().hideChildren();
106             }
107 
108             return true;
109 
110         } else if (keycode == getNavigationRightKey()) {
111 
112             if (getSelected() == null) {
113                 // If nothing is selected then select the first item
114                 setSelected(items.get(0));
115                 if (!getSelected().isSelectable()) {
116                     handleNavigation(keycode, ctrl, shift);
117                 }
118             } else if (visibleChildMenu == null && getParentMenu() == null) {
119                 // If this is the root menu then move to the right
120                 int idx = items.indexOf(getSelected());
121 
122                 if (idx < items.size() - 1) {
123                     setSelected(items.get(idx + 1));
124                 } else {
125                     setSelected(items.get(0));
126                 }
127 
128                 if (!getSelected().isSelectable()) {
129                     handleNavigation(keycode, ctrl, shift);
130                 }
131             } else if (visibleChildMenu == null
132                     && getSelected().getSubMenu() != null) {
133                 // If the item has a submenu then show it and move the selection
134                 // there
135                 showChildMenu(getSelected());
136                 menuVisible = true;
137                 visibleChildMenu.handleNavigation(keycode, ctrl, shift);
138             } else if (visibleChildMenu == null && !isContextMenu /* FIXME */) {
139 
140                 // Get the root menu
141                 VMenuBar root = getParentMenu();
142                 while (root.getParentMenu() != null) {
143                     root = root.getParentMenu();
144                 }
145 
146                 // Hide the submenu (#15255 - disable animate-in/out when hide
147                 // popup)
148                 root.hideChildren(false, false);
149 
150                 // Get the root menus items and select the next one
151                 int idx = root.getItems().indexOf(root.getSelected());
152                 idx = idx < root.getItems().size() - 1 ? idx : -1;
153                 CustomMenuItem selected = root.getItems().get(++idx);
154 
155                 while (selected.isSeparator() || !selected.isEnabled()) {
156                     idx = idx < root.getItems().size() - 1 ? idx : -1;
157                     selected = root.getItems().get(++idx);
158                 }
159 
160                 root.setSelected(selected);
161                 openMenuAndFocusFirstIfPossible(selected);
162             } else if (visibleChildMenu != null) {
163                 // Redirect all navigation to the submenu
164                 visibleChildMenu.handleNavigation(keycode, ctrl, shift);
165             }
166 
167             return true;
168 
169         } else if (keycode == getNavigationUpKey()) {
170 
171             if (getSelected() == null) {
172                 // If nothing is selected then select the last item
173                 setSelected(items.get(items.size() - 1));
174                 if (!getSelected().isSelectable()) {
175                     handleNavigation(keycode, ctrl, shift);
176                 }
177             } else if (visibleChildMenu != null) {
178                 // Redirect all navigation to the submenu
179                 visibleChildMenu.handleNavigation(keycode, ctrl, shift);
180             } else {
181                 // Select the previous item if possible or loop to the last item
182                 int idx = items.indexOf(getSelected());
183                 if (idx > 0) {
184                     setSelected(items.get(idx - 1));
185                 } else {
186                     setSelected(items.get(items.size() - 1));
187                 }
188 
189                 if (!getSelected().isSelectable()) {
190                     handleNavigation(keycode, ctrl, shift);
191                 }
192             }
193 
194             return true;
195 
196         } else if (keycode == getNavigationDownKey()) {
197 
198             if (getSelected() == null) {
199                 // If nothing is selected then select the first item
200                 selectFirstItem();
201             } else if (visibleChildMenu == null && getParentMenu() == null) {
202                 // If this is the root menu the show the child menu with arrow
203                 // down, if there is a child menu
204                 openMenuAndFocusFirstIfPossible(getSelected());
205             } else if (visibleChildMenu != null) {
206                 // Redirect all navigation to the submenu
207                 visibleChildMenu.handleNavigation(keycode, ctrl, shift);
208             } else {
209                 // Select the next item if possible or loop to the first item
210                 int idx = items.indexOf(getSelected());
211                 if (idx < items.size() - 1) {
212                     setSelected(items.get(idx + 1));
213                 } else {
214                     setSelected(items.get(0));
215                 }
216 
217                 if (!getSelected().isSelectable()) {
218                     handleNavigation(keycode, ctrl, shift);
219                 }
220             }
221             return true;
222 
223         } else if (keycode == getCloseMenuKey()) {
224             setSelected(null);
225             hideChildren();
226             menuVisible = false;
227 
228         } else if (isNavigationSelectKey(keycode)) {
229             if (getSelected() == null) {
230                 // If nothing is selected then select the first item
231                 selectFirstItem();
232             } else if (visibleChildMenu != null) {
233                 // Redirect all navigation to the submenu
234                 visibleChildMenu.handleNavigation(keycode, ctrl, shift);
235                 menuVisible = false;
236             } else if (visibleChildMenu == null
237                     && getSelected().getSubMenu() != null) {
238                 // If the item has a sub menu then show it and move the
239                 // selection there
240                 openMenuAndFocusFirstIfPossible(getSelected());
241             } else {
242                 final Command command = getSelected().getCommand();
243 
244                 setSelected(null);
245                 hideParents(true);
246 
247                 // #17076 keyboard selected menuitem without children: do
248                 // not leave menu to visible ("hover open") mode
249                 menuVisible = false;
250 
251                 Scheduler.get().scheduleDeferred(new ScheduledCommand() {
252                     @Override
253                     public void execute() {
254                         if (command != null) {
255                             command.execute();
256                         }
257                     }
258                 });
259             }
260         }
261 
262         return false;
263     }
264 
265     private void selectFirstItem() {
266         for (int i = 0; i < items.size(); i++) {
267             CustomMenuItem item = items.get(i);
268             if (item.isSelectable()) {
269                 setSelected(item);
270                 break;
271             }
272         }
273     }
274 
275     private void openMenuAndFocusFirstIfPossible(CustomMenuItem menuItem) {
276         MyVMenuBar subMenu = (MyVMenuBar) menuItem.getSubMenu();
277         if (subMenu == null) {
278             // No child menu? Nothing to do
279             return;
280         }
281 
282         MyVMenuBar parentMenu = (MyVMenuBar) menuItem.getParentMenu();
283         parentMenu.showChildMenu(menuItem);
284 
285         menuVisible = true;
286         // Select the first item in the newly open submenu
287         subMenu.selectFirstItem();
288 
289     }
290 
291     public boolean isPopupShowing() {
292         return menuVisible;
293     }
294 }