KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > user > client > ui > MenuBar


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.user.client.ui;
17
18 import com.google.gwt.user.client.Command;
19 import com.google.gwt.user.client.DOM;
20 import com.google.gwt.user.client.DeferredCommand;
21 import com.google.gwt.user.client.Element;
22 import com.google.gwt.user.client.Event;
23
24 import java.util.ArrayList JavaDoc;
25
26 /**
27  * A standard menu bar widget. A menu bar can contain any number of menu items,
28  * each of which can either fire a {@link com.google.gwt.user.client.Command} or
29  * open a cascaded menu bar.
30  *
31  * <p>
32  * <img class='gallery' SRC='MenuBar.png'/>
33  * </p>
34  *
35  * <h3>CSS Style Rules</h3>
36  * <ul class='css'>
37  * <li>.gwt-MenuBar { the menu bar itself }</li>
38  * <li>.gwt-MenuBar .gwt-MenuItem { menu items }</li>
39  * <li>.gwt-MenuBar .gwt-MenuItem-selected { selected menu items }</li>
40  * </ul>
41  *
42  * <p>
43  * <h3>Example</h3>
44  * {@example com.google.gwt.examples.MenuBarExample}
45  * </p>
46  */

47 public class MenuBar extends Widget implements PopupListener {
48
49   private Element body;
50   private ArrayList JavaDoc items = new ArrayList JavaDoc();
51   private MenuBar parentMenu;
52   private PopupPanel popup;
53   private MenuItem selectedItem;
54   private MenuBar shownChildMenu;
55   private boolean vertical, autoOpen;
56
57   /**
58    * Creates an empty horizontal menu bar.
59    */

60   public MenuBar() {
61     this(false);
62   }
63
64   /**
65    * Creates an empty menu bar.
66    *
67    * @param vertical <code>true</code> to orient the menu bar vertically
68    */

69   public MenuBar(boolean vertical) {
70     super();
71
72     Element table = DOM.createTable();
73     body = DOM.createTBody();
74     DOM.appendChild(table, body);
75
76     if (!vertical) {
77       Element tr = DOM.createTR();
78       DOM.appendChild(body, tr);
79     }
80
81     this.vertical = vertical;
82
83     Element outer = DOM.createDiv();
84     DOM.appendChild(outer, table);
85     setElement(outer);
86
87     sinkEvents(Event.ONCLICK | Event.ONMOUSEOVER | Event.ONMOUSEOUT);
88     setStyleName("gwt-MenuBar");
89   }
90
91   /**
92    * Adds a menu item to the bar.
93    *
94    * @param item the item to be added
95    */

96   public void addItem(MenuItem item) {
97     Element tr;
98     if (vertical) {
99       tr = DOM.createTR();
100       DOM.appendChild(body, tr);
101     } else {
102       tr = DOM.getChild(body, 0);
103     }
104
105     DOM.appendChild(tr, item.getElement());
106
107     item.setParentMenu(this);
108     item.setSelectionStyle(false);
109     items.add(item);
110   }
111
112   /**
113    * Adds a menu item to the bar, that will fire the given command when it is
114    * selected.
115    *
116    * @param text the item's text
117    * @param asHTML <code>true</code> to treat the specified text as html
118    * @param cmd the command to be fired
119    * @return the {@link MenuItem} object created
120    */

121   public MenuItem addItem(String JavaDoc text, boolean asHTML, Command cmd) {
122     MenuItem item = new MenuItem(text, asHTML, cmd);
123     addItem(item);
124     return item;
125   }
126
127   /**
128    * Adds a menu item to the bar, that will open the specified menu when it is
129    * selected.
130    *
131    * @param text the item's text
132    * @param asHTML <code>true</code> to treat the specified text as html
133    * @param popup the menu to be cascaded from it
134    * @return the {@link MenuItem} object created
135    */

136   public MenuItem addItem(String JavaDoc text, boolean asHTML, MenuBar popup) {
137     MenuItem item = new MenuItem(text, asHTML, popup);
138     addItem(item);
139     return item;
140   }
141
142   /**
143    * Adds a menu item to the bar, that will fire the given command when it is
144    * selected.
145    *
146    * @param text the item's text
147    * @param cmd the command to be fired
148    * @return the {@link MenuItem} object created
149    */

150   public MenuItem addItem(String JavaDoc text, Command cmd) {
151     MenuItem item = new MenuItem(text, cmd);
152     addItem(item);
153     return item;
154   }
155
156   /**
157    * Adds a menu item to the bar, that will open the specified menu when it is
158    * selected.
159    *
160    * @param text the item's text
161    * @param popup the menu to be cascaded from it
162    * @return the {@link MenuItem} object created
163    */

164   public MenuItem addItem(String JavaDoc text, MenuBar popup) {
165     MenuItem item = new MenuItem(text, popup);
166     addItem(item);
167     return item;
168   }
169
170   /**
171    * Removes all menu items from this menu bar.
172    */

173   public void clearItems() {
174     Element container = getItemContainerElement();
175     while (DOM.getChildCount(container) > 0) {
176       DOM.removeChild(container, DOM.getChild(container, 0));
177     }
178     items.clear();
179   }
180
181   /**
182    * Gets whether this menu bar's child menus will open when the mouse is moved
183    * over it.
184    *
185    * @return <code>true</code> if child menus will auto-open
186    */

187   public boolean getAutoOpen() {
188     return autoOpen;
189   }
190
191   public void onBrowserEvent(Event event) {
192     super.onBrowserEvent(event);
193
194     MenuItem item = findItem(DOM.eventGetTarget(event));
195     switch (DOM.eventGetType(event)) {
196       case Event.ONCLICK: {
197         // Fire an item's command when the user clicks on it.
198
if (item != null) {
199           doItemAction(item, true);
200         }
201         break;
202       }
203
204       case Event.ONMOUSEOVER: {
205         if (item != null) {
206           itemOver(item);
207         }
208         break;
209       }
210
211       case Event.ONMOUSEOUT: {
212         if (item != null) {
213           itemOver(null);
214         }
215         break;
216       }
217     }
218   }
219
220   public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
221     // If the menu popup was auto-closed, close all of its parents as well.
222
if (autoClosed) {
223       closeAllParents();
224     }
225
226     // When the menu popup closes, remember that no item is
227
// currently showing a popup menu.
228
onHide();
229     shownChildMenu = null;
230     popup = null;
231   }
232
233   /**
234    * Removes the specified menu item from the bar.
235    *
236    * @param item the item to be removed
237    */

238   public void removeItem(MenuItem item) {
239     int idx = items.indexOf(item);
240     if (idx == -1) {
241       return;
242     }
243
244     Element container = getItemContainerElement();
245     DOM.removeChild(container, DOM.getChild(container, idx));
246     items.remove(idx);
247   }
248
249   /**
250    * Sets whether this menu bar's child menus will open when the mouse is moved
251    * over it.
252    *
253    * @param autoOpen <code>true</code> to cause child menus to auto-open
254    */

255   public void setAutoOpen(boolean autoOpen) {
256     this.autoOpen = autoOpen;
257   }
258
259   protected void onDetach() {
260     // When the menu is detached, make sure to close all of its children.
261
if (popup != null) {
262       popup.hide();
263     }
264
265     super.onDetach();
266   }
267
268   /*
269    * Closes all parent menu popups.
270    */

271   void closeAllParents() {
272     MenuBar curMenu = this;
273     while (curMenu != null) {
274       curMenu.close();
275
276       if ((curMenu.parentMenu == null) && (curMenu.selectedItem != null)) {
277         curMenu.selectedItem.setSelectionStyle(false);
278         curMenu.selectedItem = null;
279       }
280
281       curMenu = curMenu.parentMenu;
282     }
283   }
284
285   /*
286    * Performs the action associated with the given menu item. If the item has a
287    * popup associated with it, the popup will be shown. If it has a command
288    * associated with it, and 'fireCommand' is true, then the command will be
289    * fired. Popups associated with other items will be hidden.
290    *
291    * @param item the item whose popup is to be shown. @param fireCommand <code>true</code>
292    * if the item's command should be fired, <code>false</code> otherwise.
293    */

294   void doItemAction(final MenuItem item, boolean fireCommand) {
295     // If the given item is already showing its menu, we're done.
296
if ((shownChildMenu != null) && (item.getSubMenu() == shownChildMenu)) {
297       return;
298     }
299
300     // If another item is showing its menu, then hide it.
301
if (shownChildMenu != null) {
302       shownChildMenu.onHide();
303       popup.hide();
304     }
305
306     // If the item has no popup, optionally fire its command.
307
if (item.getSubMenu() == null) {
308       if (fireCommand) {
309         // Close this menu and all of its parents.
310
closeAllParents();
311
312         // Fire the item's command.
313
Command cmd = item.getCommand();
314         if (cmd != null) {
315           DeferredCommand.addCommand(cmd);
316         }
317       }
318       return;
319     }
320
321     // Ensure that the item is selected.
322
selectItem(item);
323
324     // Create a new popup for this item, and position it next to
325
// the item (below if this is a horizontal menu bar, to the
326
// right if it's a vertical bar).
327
popup = new PopupPanel(true) {
328       {
329         setWidget(item.getSubMenu());
330         item.getSubMenu().onShow();
331       }
332
333       public boolean onEventPreview(Event event) {
334         // Hook the popup panel's event preview. We use this to keep it from
335
// auto-hiding when the parent menu is clicked.
336
switch (DOM.eventGetType(event)) {
337           case Event.ONCLICK:
338             // If the event target is part of the parent menu, suppress the
339
// event altogether.
340
Element target = DOM.eventGetTarget(event);
341             Element parentMenuElement = item.getParentMenu().getElement();
342             if (DOM.isOrHasChild(parentMenuElement, target)) {
343               return false;
344             }
345             break;
346         }
347
348         return super.onEventPreview(event);
349       }
350     };
351     popup.addPopupListener(this);
352
353     if (vertical) {
354       popup.setPopupPosition(item.getAbsoluteLeft() + item.getOffsetWidth(),
355           item.getAbsoluteTop());
356     } else {
357       popup.setPopupPosition(item.getAbsoluteLeft(), item.getAbsoluteTop()
358           + item.getOffsetHeight());
359     }
360
361     shownChildMenu = item.getSubMenu();
362     item.getSubMenu().parentMenu = this;
363
364     // Show the popup, ensuring that the menubar's event preview remains on top
365
// of the popup's.
366
popup.show();
367   }
368
369   void itemOver(MenuItem item) {
370     if (item == null) {
371       // Don't clear selection if the currently selected item's menu is showing.
372
if ((selectedItem != null)
373           && (shownChildMenu == selectedItem.getSubMenu())) {
374         return;
375       }
376     }
377
378     // Style the item selected when the mouse enters.
379
selectItem(item);
380
381     // If child menus are being shown, or this menu is itself
382
// a child menu, automatically show an item's child menu
383
// when the mouse enters.
384
if (item != null) {
385       if ((shownChildMenu != null) || (parentMenu != null) || autoOpen) {
386         doItemAction(item, false);
387       }
388     }
389   }
390
391   /**
392    * Closes this menu (if it is a popup).
393    */

394   private void close() {
395     if (parentMenu != null) {
396       parentMenu.popup.hide();
397     }
398   }
399
400   private MenuItem findItem(Element hItem) {
401     for (int i = 0; i < items.size(); ++i) {
402       MenuItem item = (MenuItem) items.get(i);
403       if (DOM.isOrHasChild(item.getElement(), hItem)) {
404         return item;
405       }
406     }
407
408     return null;
409   }
410
411   private Element getItemContainerElement() {
412     if (vertical) {
413       return body;
414     } else {
415       return DOM.getChild(body, 0);
416     }
417   }
418
419   /*
420    * This method is called when a menu bar is hidden, so that it can hide any
421    * child popups that are currently being shown.
422    */

423   private void onHide() {
424     if (shownChildMenu != null) {
425       shownChildMenu.onHide();
426       popup.hide();
427     }
428   }
429
430   /*
431    * This method is called when a menu bar is shown.
432    */

433   private void onShow() {
434     // Select the first item when a menu is shown.
435
if (items.size() > 0) {
436       selectItem((MenuItem) items.get(0));
437     }
438   }
439
440   private void selectItem(MenuItem item) {
441     if (item == selectedItem) {
442       return;
443     }
444
445     if (selectedItem != null) {
446       selectedItem.setSelectionStyle(false);
447     }
448
449     if (item != null) {
450       item.setSelectionStyle(true);
451     }
452
453     selectedItem = item;
454   }
455 }
456
Popular Tags