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: package java.awt;
019:
020: import java.awt.event.KeyEvent;
021: import java.awt.event.MouseEvent;
022: import java.util.ArrayList;
023: import java.util.HashSet;
024: import javax.accessibility.Accessible;
025: import javax.accessibility.AccessibleContext;
026: import javax.accessibility.AccessibleRole;
027: import org.apache.harmony.awt.gl.MultiRectArea;
028: import org.apache.harmony.awt.internal.nls.Messages;
029: import org.apache.harmony.awt.state.MenuState;
030:
031: public class Menu extends MenuItem implements MenuContainer, Accessible {
032: private static final long serialVersionUID = -8809584163345499784L;
033:
034: final static int LAST_ELEMENT = Integer.MAX_VALUE;
035:
036: private final ArrayList<MenuItem> menuItems = new ArrayList<MenuItem>();
037:
038: private final Point location = new Point();
039:
040: private final Dimension size = new Dimension();
041:
042: private final boolean tearOff;
043:
044: final MenuPopupBox popupBox = new MenuPopupBox();
045:
046: protected class AccessibleAWTMenu extends AccessibleAWTMenuItem {
047: private static final long serialVersionUID = 5228160894980069094L;
048:
049: @Override
050: public AccessibleRole getAccessibleRole() {
051: return AccessibleRole.MENU;
052: }
053: }
054:
055: /**
056: * The internal menu's state utilized by the visual theme
057: */
058: final class State extends MenuComponent.State implements MenuState {
059: @Override
060: public int getWidth() {
061: return Menu.this .getWidth();
062: }
063:
064: @Override
065: public int getHeight() {
066: return Menu.this .getHeight();
067: }
068:
069: @Override
070: public Font getFont() {
071: return Menu.this .getFont();
072: }
073:
074: @Override
075: public int getItemCount() {
076: return Menu.this .getItemCount();
077: }
078:
079: @Override
080: public int getSelectedItemIndex() {
081: return Menu.this .getSelectedItemIndex();
082: }
083:
084: @Override
085: public boolean isFontSet() {
086: return Menu.this .isFontSet();
087: }
088:
089: @SuppressWarnings("deprecation")
090: @Override
091: public FontMetrics getFontMetrics(Font f) {
092: return Menu.this .toolkit.getFontMetrics(f);
093: }
094:
095: @Override
096: public Point getLocation() {
097: return Menu.this .location;
098: }
099: }
100:
101: final State menuState = new State();
102:
103: public Menu(String label) throws HeadlessException {
104: this (label, false);
105: toolkit.lockAWT();
106: try {
107: } finally {
108: toolkit.unlockAWT();
109: }
110: }
111:
112: public Menu(String label, boolean tearOff) throws HeadlessException {
113: super (label);
114: toolkit.lockAWT();
115: try {
116: this .tearOff = tearOff;
117: } finally {
118: toolkit.unlockAWT();
119: }
120: }
121:
122: public Menu() throws HeadlessException {
123: this ("", false); //$NON-NLS-1$
124: toolkit.lockAWT();
125: try {
126: } finally {
127: toolkit.unlockAWT();
128: }
129: }
130:
131: public void add(String label) {
132: toolkit.lockAWT();
133: try {
134: add(new MenuItem(label));
135: } finally {
136: toolkit.unlockAWT();
137: }
138: }
139:
140: public MenuItem add(MenuItem item) {
141: toolkit.lockAWT();
142: try {
143: insertImpl(item, LAST_ELEMENT);
144: return item;
145: } finally {
146: toolkit.unlockAWT();
147: }
148: }
149:
150: public void remove(int index) {
151: toolkit.lockAWT();
152: try {
153: removeImpl(index);
154: } finally {
155: toolkit.unlockAWT();
156: }
157: }
158:
159: public void remove(MenuComponent item) {
160: if (item == null) {
161: return;
162: }
163: toolkit.lockAWT();
164: try {
165: int index = menuItems.indexOf(item);
166: removeImpl(index);
167: } finally {
168: toolkit.unlockAWT();
169: }
170: }
171:
172: void removeImpl(int index) {
173: MenuComponent item = menuItems.remove(index);
174: item.setParent(null);
175: }
176:
177: public void removeAll() {
178: toolkit.lockAWT();
179: try {
180: while (!menuItems.isEmpty()) {
181: removeImpl(menuItems.size() - 1);
182: }
183: } finally {
184: toolkit.unlockAWT();
185: }
186: }
187:
188: public void insert(String label, int index) {
189: toolkit.lockAWT();
190: try {
191: insertImpl(new MenuItem(label), index);
192: } finally {
193: toolkit.unlockAWT();
194: }
195: }
196:
197: public void insert(MenuItem item, int index) {
198: toolkit.lockAWT();
199: try {
200: insertImpl(item, index);
201: } finally {
202: toolkit.unlockAWT();
203: }
204: }
205:
206: void insertImpl(MenuItem item, int index) {
207: if (index < 0) {
208: // awt.6F=Index less than zero
209: throw new IllegalArgumentException(Messages
210: .getString("awt.6F")); //$NON-NLS-1$
211: }
212: if (item == null) {
213: // awt.70=MenuItem is null
214: throw new NullPointerException(Messages.getString("awt.70")); //$NON-NLS-1$
215: }
216: MenuContainer oldParent = item.getParent();
217: if (oldParent != null) {
218: oldParent.remove(item);
219: }
220: item.setParent(this );
221: if (index >= menuItems.size()) {
222: menuItems.add(item);
223: } else {
224: menuItems.add(index, item);
225: }
226: }
227:
228: @Override
229: public String paramString() {
230: toolkit.lockAWT();
231: try {
232: return super .paramString() + (tearOff ? ",tearOff" : ""); //$NON-NLS-1$ //$NON-NLS-2$
233: } finally {
234: toolkit.unlockAWT();
235: }
236: }
237:
238: @Override
239: public MenuItem getItem(int index) {
240: toolkit.lockAWT();
241: try {
242: return menuItems.get(index);
243: } finally {
244: toolkit.unlockAWT();
245: }
246: }
247:
248: @Override
249: public void addNotify() {
250: toolkit.lockAWT();
251: try {
252: popupBox.addNotify();
253: super .addNotify();
254: } finally {
255: toolkit.unlockAWT();
256: }
257: }
258:
259: @Override
260: public AccessibleContext getAccessibleContext() {
261: toolkit.lockAWT();
262: try {
263: return super .getAccessibleContext();
264: } finally {
265: toolkit.unlockAWT();
266: }
267: }
268:
269: @Override
270: public void removeNotify() {
271: toolkit.lockAWT();
272: try {
273: for (int i = 0; i < getItemCount(); i++) {
274: getItem(i).removeNotify();
275: }
276: super .removeNotify();
277: } finally {
278: toolkit.unlockAWT();
279: }
280: }
281:
282: /**
283: * @deprecated
284: */
285: @Deprecated
286: public int countItems() {
287: toolkit.lockAWT();
288: try {
289: return getItemCount();
290: } finally {
291: toolkit.unlockAWT();
292: }
293: }
294:
295: @Override
296: public int getItemCount() {
297: toolkit.lockAWT();
298: try {
299: return menuItems.size();
300: } finally {
301: toolkit.unlockAWT();
302: }
303: }
304:
305: public void addSeparator() {
306: toolkit.lockAWT();
307: try {
308: add(new MenuItem("-")); //$NON-NLS-1$
309: } finally {
310: toolkit.unlockAWT();
311: }
312: }
313:
314: public void insertSeparator(int index) {
315: toolkit.lockAWT();
316: try {
317: insert(new MenuItem("-"), index); //$NON-NLS-1$
318: } finally {
319: toolkit.unlockAWT();
320: }
321: }
322:
323: public boolean isTearOff() {
324: return tearOff;
325: }
326:
327: @Override
328: Point getLocation() {
329: return location;
330: }
331:
332: Dimension getSize() {
333: return size;
334: }
335:
336: @Override
337: int getWidth() {
338: return size.width;
339: }
340:
341: @Override
342: int getHeight() {
343: return size.height;
344: }
345:
346: @Override
347: void paint(Graphics gr) {
348: toolkit.theme.drawMenu(menuState, gr);
349: }
350:
351: /**
352: * Show menu on the screen
353: * @param x - screen X coordinate
354: * @param y - screen Y coordinate
355: */
356: void show(int x, int y, boolean modal) {
357: if (parent == null) {
358: // awt.71=Parent is null
359: throw new NullPointerException(Messages.getString("awt.71")); //$NON-NLS-1$
360: }
361: location.x = x;
362: location.y = y;
363: selectItem(-1, true);
364: PopupBox parentBox = null;
365: if (parent instanceof MenuComponent) {
366: parentBox = ((MenuComponent) parent).getPopupBox();
367: }
368: size.setSize(toolkit.theme.calculateMenuSize(menuState));
369: popupBox.setParent(parentBox);
370: popupBox.setModal(modal);
371: popupBox.show(location, size, getOwnerWindow());
372: }
373:
374: Window getOwnerWindow() {
375: for (MenuContainer cont = getParent(); cont != null;) {
376: if (cont instanceof Component) {
377: return ((Component) cont).getWindowAncestor();
378: }
379: if (cont instanceof Menu) {
380: cont = ((Menu) cont).parent;
381: continue;
382: }
383: if (cont instanceof MenuBar) {
384: return (Window) ((MenuBar) cont).parent;
385: }
386: }
387: return null;
388: }
389:
390: @Override
391: void hide() {
392: super .hide();
393: for (int i = 0; i < getItemCount(); i++) {
394: getItem(i).hide();
395: }
396: popupBox.hide();
397: }
398:
399: @Override
400: boolean isVisible() {
401: return popupBox.isVisible();
402: }
403:
404: @Override
405: PopupBox getPopupBox() {
406: return popupBox;
407: }
408:
409: @Override
410: void onMouseEvent(int eventId, Point where, int mouseButton,
411: long when, int modifiers) {
412: if (eventId == MouseEvent.MOUSE_PRESSED
413: || eventId == MouseEvent.MOUSE_MOVED
414: || eventId == MouseEvent.MOUSE_DRAGGED) {
415: int index = toolkit.theme
416: .getMenuItemIndex(menuState, where);
417: if (index >= 0 || getSelectedSubmenu() == null) {
418: selectItem(index);
419: }
420: } else if (eventId == MouseEvent.MOUSE_RELEASED) {
421: int index = toolkit.theme
422: .getMenuItemIndex(menuState, where);
423: selectItem(index);
424: if (index >= 0) {
425: fireItemAction(index, when, modifiers);
426: }
427: } else if (eventId == MouseEvent.MOUSE_EXITED) {
428: if (getSelectedSubmenu() == null) {
429: selectItem(-1);
430: }
431: }
432: }
433:
434: @Override
435: void onKeyEvent(int eventId, int vKey, long when, int modifiers) {
436: if (eventId != KeyEvent.KEY_PRESSED) {
437: return;
438: }
439: int selected = getSelectedItemIndex();
440: MenuBar menuBar;
441: switch (vKey) {
442: case KeyEvent.VK_ESCAPE:
443: hide();
444: break;
445: case KeyEvent.VK_RIGHT:
446: Menu subMenu = getSelectedSubmenu();
447: if (subMenu != null) {
448: showSubMenu(selected);
449: subMenu.selectNextItem(true, false);
450: } else {
451: menuBar = getMenuBar();
452: if (menuBar != null) {
453: menuBar.onKeyEvent(eventId, vKey, when, modifiers);
454: }
455: }
456: break;
457: case KeyEvent.VK_LEFT:
458: if (parent instanceof Menu) {
459: hide();
460: } else {
461: menuBar = getMenuBar();
462: if (menuBar != null) {
463: menuBar.onKeyEvent(eventId, vKey, when, modifiers);
464: }
465: }
466: break;
467: case KeyEvent.VK_UP:
468: case KeyEvent.VK_DOWN:
469: selectNextItem(vKey == KeyEvent.VK_DOWN, false);
470: break;
471: case KeyEvent.VK_ENTER:
472: if (selected >= 0) {
473: fireItemAction(selected, when, modifiers);
474: } else {
475: hide();
476: }
477: }
478: }
479:
480: @Override
481: void itemSelected(long when, int modifiers) {
482: // do nothing
483: }
484:
485: @Override
486: Rectangle getItemRect(int index) {
487: return menuState.getItem(index).getItemBounds();
488: }
489:
490: @Override
491: Point getSubmenuLocation(int index) {
492: return toolkit.theme.getMenuItemLocation(menuState, index);
493: }
494:
495: @Override
496: Graphics getGraphics(MultiRectArea clip) {
497: return popupBox.getGraphics(clip);
498: }
499:
500: @Override
501: AccessibleContext createAccessibleContext() {
502: return new AccessibleAWTMenu();
503: }
504:
505: void collectShortcuts(HashSet<MenuShortcut> shortcuts) {
506: for (int i = 0; i < menuItems.size(); i++) {
507: MenuItem item = menuItems.get(i);
508: if (item instanceof Menu) {
509: ((Menu) item).collectShortcuts(shortcuts);
510: } else {
511: MenuShortcut ms = item.getShortcut();
512: if (ms != null) {
513: shortcuts.add(ms);
514: }
515: }
516: }
517: }
518: }
|