001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Pavel Dolgov
019: * @version $Revision$
020: */package java.awt;
021:
022: import java.awt.event.KeyEvent;
023: import java.awt.event.MouseEvent;
024: import java.util.ArrayList;
025: import java.util.Collections;
026: import java.util.Enumeration;
027: import java.util.HashSet;
028:
029: import javax.accessibility.Accessible;
030: import javax.accessibility.AccessibleContext;
031: import javax.accessibility.AccessibleRole;
032:
033: import org.apache.harmony.awt.gl.MultiRectArea;
034: import org.apache.harmony.awt.state.MenuBarState;
035: import org.apache.harmony.awt.wtk.NativeWindow;
036:
037: public class MenuBar extends MenuComponent implements MenuContainer,
038: Accessible {
039:
040: private static final long serialVersionUID = -4930327919388951260L;
041: private final ArrayList<Menu> menuList;
042: private Menu helpMenu; // one of the list items
043: private boolean unfolded;
044:
045: final State menuBarState = new State();
046: private final MenuBarBox box = new MenuBarBox();
047:
048: protected class AccessibleAWTMenuBar extends
049: AccessibleAWTMenuComponent {
050:
051: private static final long serialVersionUID = -8577604491830083815L;
052:
053: @Override
054: public AccessibleRole getAccessibleRole() {
055: return AccessibleRole.MENU_BAR;
056: }
057: }
058:
059: /**
060: * The accessor to MenuBar internal state, utilized by the visual theme
061: */
062: final class State extends MenuComponent.State implements
063: MenuBarState {
064:
065: private Frame getFrame() {
066: return ((Frame) MenuBar.this .parent);
067: }
068:
069: public Point getLocationOnScreen() {
070: return MenuBar.this .getScreenLocation();
071: }
072:
073: @Override
074: void calculate() {
075: Frame f = getFrame();
076: Insets ins = f.getNativeInsets();
077: int width = f.w - ins.left - ins.right;
078: toolkit.theme.layoutMenuBar(this , width);
079: }
080:
081: @Override
082: void reset() {
083: super .reset();
084: }
085: }
086:
087: /**
088: * Pseudo pop-up box for menu bar. Actually it's Frame's child window,
089: * but in other aspects it is similar to the normal pop-up box.
090: */
091: private final class MenuBarBox extends MenuComponent.MenuPopupBox {
092:
093: @Override
094: boolean isMenuBar() {
095: return true;
096: }
097:
098: boolean isActive() {
099: return toolkit.dispatcher.popupDispatcher.isActive(this );
100: }
101:
102: @Override
103: Dimension getSize() {
104: size.setSize(menuBarState.getSize());
105: return size;
106: }
107:
108: @Override
109: Point getLocation() {
110: location.setLocation(MenuBar.this .getLocation());
111: return location;
112: }
113:
114: @Override
115: Point getScreenLocation() {
116: return MenuBar.this .getScreenLocation();
117: }
118:
119: @Override
120: void paint(Graphics gr) {
121: MenuBar.this .paint(gr);
122: }
123:
124: @Override
125: Rectangle calculateBounds() {
126: Dimension size = MenuBar.this .menuBarState.getSize();
127: Point location = MenuBar.this .getLocation();
128: return new Rectangle(location, size);
129: }
130:
131: void show() {
132: show((Frame) MenuBar.this .getParent());
133: }
134:
135: @Override
136: void hide() {
137: selectItem(-1);
138: toolkit.dispatcher.popupDispatcher.deactivate(this );
139: }
140:
141: void updateBounds() {
142: Rectangle bounds = calculateBounds();
143: boolean moved = !location.equals(bounds.getLocation());
144: boolean resized = !size.equals(bounds.getSize());
145: if (moved || resized) {
146: int mask = 0;
147: mask |= moved ? 0 : NativeWindow.BOUNDS_NOMOVE;
148: mask |= resized ? 0 : NativeWindow.BOUNDS_NOSIZE;
149: if (nativeWindow != null) {
150: nativeWindow.setBounds(bounds.x, bounds.y,
151: bounds.width, bounds.height, mask);
152: }
153: location.setLocation(bounds.getLocation());
154: size.setSize(bounds.getSize());
155: }
156: }
157: }
158:
159: public MenuBar() throws HeadlessException {
160: toolkit.lockAWT();
161: try {
162: menuList = new ArrayList<Menu>();
163: } finally {
164: toolkit.unlockAWT();
165: }
166: }
167:
168: public Menu add(Menu menu) {
169: toolkit.lockAWT();
170: try {
171: if (!menuList.contains(menu)) {
172: MenuContainer oldParent = menu.getParent();
173: if (oldParent != null) {
174: oldParent.remove(menu);
175: }
176: menu.setParent(this );
177: menuList.add(menu);
178: }
179: menuBarState.reset();
180: updateParent();
181: return menu;
182: } finally {
183: toolkit.unlockAWT();
184: }
185: }
186:
187: public void remove(MenuComponent menu) {
188: if (menu == null)
189: return;
190: toolkit.lockAWT();
191: try {
192: menuList.remove(menu);
193: if (menu == helpMenu) {
194: helpMenu = null;
195: }
196: menu.setParent(null);
197: menuBarState.reset();
198: updateParent();
199: } finally {
200: toolkit.unlockAWT();
201: }
202: }
203:
204: public void remove(int index) {
205: toolkit.lockAWT();
206: try {
207: Menu menu = menuList.get(index);
208: remove(menu);
209: } finally {
210: toolkit.unlockAWT();
211: }
212: }
213:
214: public void addNotify() {
215: toolkit.lockAWT();
216: try {
217: menuBarState.calculate();
218: box.show();
219: } finally {
220: toolkit.unlockAWT();
221: }
222: }
223:
224: @Override
225: public AccessibleContext getAccessibleContext() {
226: toolkit.lockAWT();
227: try {
228: return super .getAccessibleContext();
229: } finally {
230: toolkit.unlockAWT();
231: }
232: }
233:
234: @Override
235: public void removeNotify() {
236: toolkit.lockAWT();
237: try {
238: box.removeNotify();
239: } finally {
240: toolkit.unlockAWT();
241: }
242: }
243:
244: public void deleteShortcut(MenuShortcut ms) {
245: toolkit.lockAWT();
246: try {
247: MenuItem mi = getShortcutMenuItemImpl(ms);
248: if (mi != null) {
249: mi.deleteShortcut();
250: }
251: } finally {
252: toolkit.unlockAWT();
253: }
254: }
255:
256: public MenuItem getShortcutMenuItem(MenuShortcut ms) {
257: toolkit.lockAWT();
258: try {
259: return getShortcutMenuItemImpl(ms);
260: } finally {
261: toolkit.unlockAWT();
262: }
263: }
264:
265: public Enumeration<MenuShortcut> shortcuts() {
266: toolkit.lockAWT();
267: try {
268: HashSet<MenuShortcut> shortcuts = new HashSet<MenuShortcut>();
269: collectShortcuts(shortcuts);
270: return Collections.enumeration(shortcuts);
271: } finally {
272: toolkit.unlockAWT();
273: }
274: }
275:
276: /**
277: * @deprecated
278: */
279: @Deprecated
280: public int countMenus() {
281: toolkit.lockAWT();
282: try {
283: return menuList.size();
284: } finally {
285: toolkit.unlockAWT();
286: }
287: }
288:
289: public Menu getHelpMenu() {
290: toolkit.lockAWT();
291: try {
292: return helpMenu;
293: } finally {
294: toolkit.unlockAWT();
295: }
296: }
297:
298: public Menu getMenu(int index) {
299: toolkit.lockAWT();
300: try {
301: return menuList.get(index);
302: } finally {
303: toolkit.unlockAWT();
304: }
305: }
306:
307: public int getMenuCount() {
308: toolkit.lockAWT();
309: try {
310: return menuList.size();
311: } finally {
312: toolkit.unlockAWT();
313: }
314: }
315:
316: public void setHelpMenu(Menu menu) {
317: toolkit.lockAWT();
318: try {
319: if (helpMenu == menu) {
320: return;
321: }
322: helpMenu = menu;
323: add(menu);
324: } finally {
325: toolkit.unlockAWT();
326: }
327: }
328:
329: @Override
330: boolean hasDefaultFont() {
331: return true;
332: }
333:
334: void updateParent() {
335: MenuContainer parent = getParent();
336: if (parent == null) {
337: return;
338: }
339: Frame f = (Frame) parent;
340: f.invalidate();
341: f.validate();
342: }
343:
344: @Override
345: MenuItem getItem(int index) {
346: return menuList.get(index);
347: }
348:
349: @Override
350: int getItemCount() {
351: return menuList.size();
352: }
353:
354: @Override
355: int getWidth() {
356: return menuBarState.getWidth();
357: }
358:
359: @Override
360: int getHeight() {
361: return menuBarState.getHeight();
362: }
363:
364: @Override
365: Point getLocation() {
366: Frame f = (Frame) getParent();
367: if (f == null) {
368: return new Point(0, 0);
369: }
370: Insets ins = f.getNativeInsets();
371: return new Point(ins.left, ins.top);
372: }
373:
374: Point getScreenLocation() {
375: Frame f = (Frame) getParent();
376: if (f == null) {
377: return new Point(0, 0);
378: }
379: Insets ins = f.getNativeInsets();
380: return new Point(f.x + ins.left, f.y + ins.top);
381: }
382:
383: @Override
384: void paint(Graphics gr) {
385: toolkit.theme.drawMenuBar(menuBarState, gr);
386: }
387:
388: @Override
389: Rectangle getItemRect(int index) {
390: return menuBarState.getItem(index).getItemBounds();
391: }
392:
393: @Override
394: final void onMouseEvent(int eventId, Point where, int mouseButton,
395: long when, int modifiers) {
396: int index = toolkit.theme.getMenuBarItemIndex(menuBarState,
397: where);
398:
399: if (box.isActive()) {
400: switch (eventId) {
401: case MouseEvent.MOUSE_PRESSED:
402: endMenu();
403: break;
404: case MouseEvent.MOUSE_RELEASED:
405: if (index >= 0) {
406: selectItem(index);
407: } else {
408: endMenu();
409: }
410: break;
411: default:
412: if (index >= 0 || getSelectedItemIndex() < 0) {
413: selectItem(index);
414: }
415: }
416: } else {
417: if ((index >= 0) && (eventId == MouseEvent.MOUSE_PRESSED)) {
418: toolkit.dispatcher.popupDispatcher.activate(box);
419: showSubMenu(index);
420: } else {
421: selectItem(index);
422: }
423: }
424: }
425:
426: @Override
427: void onKeyEvent(int eventId, int vKey, long when, int modifiers) {
428: if (eventId != KeyEvent.KEY_PRESSED) {
429: return;
430: }
431: Menu subMenu;
432: switch (vKey) {
433: case KeyEvent.VK_ESCAPE:
434: endMenu();
435: break;
436: case KeyEvent.VK_RIGHT:
437: case KeyEvent.VK_LEFT:
438: selectNextItem(vKey == KeyEvent.VK_RIGHT);
439: subMenu = getSelectedSubmenu();
440: if (subMenu != null) {
441: subMenu.selectNextItem(true, false);
442: }
443: break;
444: case KeyEvent.VK_UP:
445: case KeyEvent.VK_DOWN:
446: case KeyEvent.VK_ENTER:
447: subMenu = getSelectedSubmenu();
448: if (subMenu != null && !subMenu.isVisible()) {
449: unfolded = true;
450: showSubMenu(getSelectedItemIndex());
451: subMenu = getSelectedSubmenu();
452: subMenu.selectNextItem(true, false);
453: }
454: }
455: }
456:
457: @Override
458: boolean isActive() {
459: return box.isActive();
460: }
461:
462: @Override
463: MenuBar getMenuBar() {
464: return this ;
465: }
466:
467: @Override
468: PopupBox getPopupBox() {
469: return box;
470: }
471:
472: @Override
473: void hide() {
474: // do nothing
475: }
476:
477: @Override
478: void itemHidden(MenuComponent mc) {
479: unfolded = false;
480: }
481:
482: @Override
483: Point getSubmenuLocation(int index) {
484: return toolkit.theme
485: .getMenuBarItemLocation(menuBarState, index);
486: }
487:
488: void selectNextItem(boolean forward) {
489: super .selectNextItem(forward, unfolded);
490: }
491:
492: @Override
493: void selectItem(int index) {
494: unfolded = (index >= 0);
495: super .selectItem(index, true);
496: }
497:
498: @Override
499: void showSubMenu(int index) {
500: unfolded = (index >= 0);
501: super .showSubMenu(index);
502: }
503:
504: void validate() {
505: menuBarState.calculate();
506: box.updateBounds();
507: }
508:
509: @Override
510: Graphics getGraphics(MultiRectArea clip) {
511: return box.getGraphics(clip);
512: }
513:
514: @Override
515: AccessibleContext createAccessibleContext() {
516: return new AccessibleAWTMenuBar();
517: }
518:
519: void handleShortcut(KeyEvent ke) {
520: MenuShortcut shortcut = MenuShortcut.lookup(ke);
521: MenuItem item = getShortcutMenuItem(shortcut);
522: if (item != null) {
523: item.itemSelected(ke.getWhen(), ke.getModifiersEx());
524: ke.consume();
525: }
526: }
527:
528: void collectShortcuts(HashSet<MenuShortcut> shortcuts) {
529: for (int i = 0; i < menuList.size(); i++) {
530: menuList.get(i).collectShortcuts(shortcuts);
531: }
532: }
533: }
|