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 javax.swing;
019:
020: import java.awt.Component;
021: import java.awt.ComponentOrientation;
022: import java.awt.Point;
023: import java.awt.event.InputEvent;
024: import java.awt.event.WindowAdapter;
025: import java.awt.event.WindowEvent;
026: import java.beans.PropertyChangeListener;
027: import java.io.Serializable;
028: import javax.accessibility.Accessible;
029: import javax.accessibility.AccessibleContext;
030: import javax.accessibility.AccessibleRole;
031: import javax.accessibility.AccessibleSelection;
032: import javax.swing.event.MenuEvent;
033: import javax.swing.event.MenuListener;
034: import org.apache.harmony.luni.util.NotImplementedException;
035: import org.apache.harmony.x.swing.Utilities;
036:
037: import org.apache.harmony.x.swing.internal.nls.Messages;
038:
039: /**
040: * <p>
041: * <i>JMenu</i>
042: * </p>
043: * <h3>Implementation Notes:</h3>
044: * <ul>
045: * <li>The <code>serialVersionUID</code> fields are explicitly declared as a performance
046: * optimization, not as a guarantee of serialization compatibility.</li>
047: * </ul>
048: */
049: public class JMenu extends JMenuItem implements Accessible, MenuElement {
050: private static final long serialVersionUID = 6344812061970456262L;
051:
052: // TODO implement accessibility
053: protected class AccessibleJMenu extends AccessibleJMenuItem
054: implements AccessibleSelection {
055: private static final long serialVersionUID = -7871723353224195081L;
056:
057: public void addAccessibleSelection(int i)
058: throws NotImplementedException {
059: throw new NotImplementedException();
060: }
061:
062: public void clearAccessibleSelection()
063: throws NotImplementedException {
064: throw new NotImplementedException();
065: }
066:
067: @Override
068: public int getAccessibleChildrenCount()
069: throws NotImplementedException {
070: throw new NotImplementedException();
071: }
072:
073: @Override
074: public Accessible getAccessibleChild(int i)
075: throws NotImplementedException {
076: throw new NotImplementedException();
077: }
078:
079: @Override
080: public AccessibleRole getAccessibleRole() {
081: return AccessibleRole.MENU;
082: }
083:
084: @Override
085: public AccessibleSelection getAccessibleSelection()
086: throws NotImplementedException {
087: throw new NotImplementedException();
088: }
089:
090: public Accessible getAccessibleSelection(int i)
091: throws NotImplementedException {
092: throw new NotImplementedException();
093: }
094:
095: public int getAccessibleSelectionCount()
096: throws NotImplementedException {
097: throw new NotImplementedException();
098: }
099:
100: public boolean isAccessibleChildSelected(int i)
101: throws NotImplementedException {
102: throw new NotImplementedException();
103: }
104:
105: public void removeAccessibleSelection(int i)
106: throws NotImplementedException {
107: throw new NotImplementedException();
108: }
109:
110: public void selectAllAccessibleSelection()
111: throws NotImplementedException {
112: throw new NotImplementedException();
113: }
114: }
115:
116: protected class WinListener extends WindowAdapter implements
117: Serializable {
118: private static final long serialVersionUID = 1L;
119:
120: private final JPopupMenu popup;
121:
122: public WinListener(JPopupMenu p) {
123: popup = p;
124: }
125:
126: @Override
127: public void windowClosing(WindowEvent e) {
128: setSelected(false);
129: }
130: }
131:
132: protected WinListener popupListener;
133:
134: private static final String UI_CLASS_ID = "MenuUI";
135:
136: private static final Object ALL_ACTION_PROPERTIES = new Object() { //$NON-LOCK-1$
137: @Override
138: public boolean equals(Object o) {
139: return !Action.ACCELERATOR_KEY.equals(o);
140: }
141: };
142:
143: private int delay = 200;
144:
145: private JPopupMenu popup;
146:
147: private transient MenuEvent menuEvent;
148:
149: private transient int[] uiMnemonicModifiers;
150:
151: private transient boolean crossMenuMnemonic;
152:
153: public JMenu() {
154: super ();
155: }
156:
157: public JMenu(String text) {
158: super (text);
159: }
160:
161: public JMenu(String text, boolean b) {
162: super (text);
163: }
164:
165: public JMenu(Action action) {
166: setDefaultModelAndFocus();
167: setAction(action);
168: init(getText(), getIcon());
169: }
170:
171: @Override
172: void configurePropertyFromAction(Action action, Object propertyName) {
173: if (propertyName == null
174: || propertyName.equals(Action.ACCELERATOR_KEY)) {
175: return;
176: }
177: super .configurePropertyFromAction(action, propertyName);
178: }
179:
180: @Override
181: public AccessibleContext getAccessibleContext() {
182: return (accessibleContext == null) ? (accessibleContext = new AccessibleJMenu())
183: : accessibleContext;
184: }
185:
186: protected PropertyChangeListener createActionChangeListener(
187: JMenuItem item) {
188: return item.createActionPropertyChangeListener(getAction());
189: }
190:
191: protected JMenuItem createActionComponent(Action action) {
192: return JMenuItem.createJMenuItem(action);
193: }
194:
195: protected WinListener createWinListener(JPopupMenu popup) {
196: return new WinListener(popup);
197: }
198:
199: public void addMenuListener(MenuListener listener) {
200: listenerList.add(MenuListener.class, listener);
201: }
202:
203: public void removeMenuListener(MenuListener listener) {
204: listenerList.remove(MenuListener.class, listener);
205: }
206:
207: public MenuListener[] getMenuListeners() {
208: return getListeners(MenuListener.class);
209: }
210:
211: protected void fireMenuCanceled() {
212: final MenuListener[] listeners = getMenuListeners();
213: if (listeners.length == 0) {
214: return;
215: }
216: if (menuEvent == null) {
217: menuEvent = new MenuEvent(this );
218: }
219: for (int i = 0; i < listeners.length; i++) {
220: listeners[i].menuCanceled(menuEvent);
221: }
222: }
223:
224: protected void fireMenuDeselected() {
225: final MenuListener[] listeners = getMenuListeners();
226: if (listeners.length == 0) {
227: return;
228: }
229: if (menuEvent == null) {
230: menuEvent = new MenuEvent(this );
231: }
232: for (int i = 0; i < listeners.length; i++) {
233: listeners[i].menuDeselected(menuEvent);
234: }
235: }
236:
237: protected void fireMenuSelected() {
238: final MenuListener[] listeners = getMenuListeners();
239: if (listeners.length == 0) {
240: return;
241: }
242: if (menuEvent == null) {
243: menuEvent = new MenuEvent(this );
244: }
245: for (int i = 0; i < listeners.length; i++) {
246: listeners[i].menuSelected(menuEvent);
247: }
248: }
249:
250: @Override
251: public void doClick(int time) {
252: final MenuElement[] path = Utilities
253: .getMenuElementPath(getPopupMenu());
254: MenuSelectionManager.defaultManager().setSelectedPath(path);
255: }
256:
257: public JPopupMenu getPopupMenu() {
258: if (popup == null) {
259: popup = new JPopupMenu();
260: popup.setInvoker(this );
261: }
262: return popup;
263: }
264:
265: protected Point getPopupMenuOrigin() {
266: final boolean leftToRight = getComponentOrientation()
267: .isLeftToRight();
268: Point result = Utilities.getPopupLocation(getBounds(),
269: getPopupMenu().getPreferredSize(), leftToRight,
270: !isTopLevelMenu());
271: String prefix = isTopLevelMenu() ? "Menu.menuPopupOffset"
272: : "Menu.submenuPopupOffset";
273: int xOffset = UIManager.getInt(prefix + "X");
274: int yOffset = UIManager.getInt(prefix + "Y");
275: if (!leftToRight) {
276: xOffset = -xOffset;
277: }
278: result.translate(xOffset - getX(), yOffset - getY());
279: return result;
280: }
281:
282: public boolean isPopupMenuVisible() {
283: return popup != null ? popup.isVisible() : false;
284: }
285:
286: public void setPopupMenuVisible(boolean visible) {
287: if (visible == isPopupMenuVisible()) {
288: return;
289: }
290: popup = getPopupMenu();
291: if (visible) {
292: if (isShowing()) {
293: Point origin = getPopupMenuOrigin();
294: popup.show(this , origin.x, origin.y);
295: }
296: } else {
297: popup.setVisible(visible);
298: }
299: }
300:
301: @Override
302: public String getUIClassID() {
303: return UI_CLASS_ID;
304: }
305:
306: @Override
307: public void setSelected(boolean selected) {
308: if (selected != isSelected()) {
309: super .setSelected(selected);
310: if (selected) {
311: fireMenuSelected();
312: } else {
313: fireMenuDeselected();
314: }
315: }
316: }
317:
318: public boolean isTearOff() {
319: throw new Error(Messages.getString("swing.err.0A")); //$NON-NLS-1$
320: }
321:
322: public boolean isTopLevelMenu() {
323: return (getParent() instanceof JMenuBar);
324: }
325:
326: @Override
327: public void menuSelectionChanged(boolean b) {
328: setSelected(b);
329: }
330:
331: @Override
332: public void setAccelerator(KeyStroke keyStroke) {
333: throw new Error(Messages.getString(
334: "swing.err.0B", "setAccelerator()", "setMnemonic()"));//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
335: }
336:
337: @Override
338: public void setComponentOrientation(ComponentOrientation orientation) {
339: super .setComponentOrientation(orientation);
340: if (popup != null) {
341: popup.setComponentOrientation(orientation);
342: }
343: }
344:
345: @Override
346: public void applyComponentOrientation(
347: ComponentOrientation orientation) {
348: super .applyComponentOrientation(orientation);
349: if (popup != null) {
350: popup.applyComponentOrientation(orientation);
351: }
352: }
353:
354: public void setDelay(int delay) {
355: if (delay < 0) {
356: throw new IllegalArgumentException(Messages
357: .getString("swing.1C")); //$NON-NLS-1$
358: }
359: this .delay = delay;
360: }
361:
362: public int getDelay() {
363: return delay;
364: }
365:
366: public void setMenuLocation(int x, int y) {
367: if (popup != null) {
368: popup.setLocation(x, y);
369: }
370: }
371:
372: @Override
373: public Component add(Component c) {
374: return getPopupMenu().add(c);
375: }
376:
377: public JMenuItem add(Action action) {
378: return getPopupMenu().add(action);
379: }
380:
381: @Override
382: public Component add(Component c, int index) {
383: return getPopupMenu().add(c, index);
384: }
385:
386: public JMenuItem add(String text) {
387: return getPopupMenu().add(text);
388: }
389:
390: public JMenuItem add(JMenuItem item) {
391: return getPopupMenu().add(item);
392: }
393:
394: public void addSeparator() {
395: getPopupMenu().addSeparator();
396: }
397:
398: public void insert(String text, int index) {
399: JMenuItem item = new JMenuItem(text);
400: getPopupMenu().insert(item, getValidIndex(index));
401: }
402:
403: public JMenuItem insert(JMenuItem item, int index) {
404: getPopupMenu().insert(item, index);
405: return item;
406: }
407:
408: public JMenuItem insert(Action action, int index) {
409: JMenuItem item = createActionComponent(action);
410: getPopupMenu().insert(item, getValidIndex(index));
411: return item;
412: }
413:
414: public void insertSeparator(int index) {
415: getPopupMenu().insert(new JPopupMenu.Separator(),
416: getValidIndex(index));
417: }
418:
419: public Component getMenuComponent(int index) {
420: if (popup == null || index < 0
421: || index >= getMenuComponentCount()) {
422: return null;
423: }
424: return popup.getComponent(index);
425: }
426:
427: public JMenuItem getItem(int index) {
428: if (popup == null || index < 0 || index >= getItemCount()) {
429: return null;
430: }
431: Component c = popup.getComponent(index);
432: return (c instanceof JMenuItem) ? (JMenuItem) c : null;
433: }
434:
435: public int getItemCount() {
436: return getMenuComponentCount();
437: }
438:
439: public int getMenuComponentCount() {
440: return (popup != null) ? popup.getComponentCount() : 0;
441: }
442:
443: public Component[] getMenuComponents() {
444: return (popup != null) ? popup.getComponents()
445: : new Component[0];
446: }
447:
448: @Override
449: public MenuElement[] getSubElements() {
450: return new MenuElement[] { getPopupMenu() };
451: }
452:
453: @Override
454: public void remove(Component c) {
455: if (popup == null) {
456: return;
457: }
458: Component[] subComponents = getMenuComponents();
459: for (int i = 0; i < subComponents.length; i++) {
460: if (subComponents[i] == c) {
461: popup.remove(i);
462: break;
463: }
464: }
465: }
466:
467: @Override
468: public void remove(int i) {
469: if (popup != null) {
470: popup.remove(i);
471: }
472: }
473:
474: public void remove(JMenuItem item) {
475: remove((Component) item);
476: }
477:
478: @Override
479: public void removeAll() {
480: if (popup != null) {
481: popup.removeAll();
482: }
483: }
484:
485: public boolean isMenuComponent(Component c) {
486: if (c == null) {
487: return false;
488: }
489: if (c == this ) {
490: return true;
491: }
492: Component[] subComponents = getMenuComponents();
493: for (int i = 0; i < subComponents.length; i++) {
494: if (subComponents[i] == c) {
495: return true;
496: }
497: }
498: for (int i = 0; i < subComponents.length; i++) {
499: if (subComponents[i] instanceof JMenu
500: && ((JMenu) subComponents[i]).isMenuComponent(c)) {
501: return true;
502: }
503: }
504: return false;
505: }
506:
507: @Override
508: public void updateUI() {
509: super .updateUI();
510: uiMnemonicModifiers = (int[]) UIManager
511: .get("Menu.shortcutKeys");
512: crossMenuMnemonic = UIManager
513: .getBoolean("Menu.crossMenuMnemonic");
514: }
515:
516: @Override
517: void setDefaultModelAndFocus() {
518: setModel(createDefaultModel());
519: setFocusPainted(false);
520: setHorizontalAlignment(SwingConstants.LEADING);
521: }
522:
523: @Override
524: Object getActionPropertiesFilter() {
525: return ALL_ACTION_PROPERTIES;
526: }
527:
528: @Override
529: boolean isMnemonicKeyStroke(KeyStroke keyStroke) {
530: if (keyStroke.getKeyCode() != getMnemonic()) {
531: return false;
532: }
533: final int modifiers = keyStroke.getModifiers();
534: if (isTopLevelMenu()) {
535: final MenuSelectionManager defaultManager = MenuSelectionManager
536: .defaultManager();
537: final boolean pathEmpty = defaultManager.isPathEmpty();
538: if (!pathEmpty && !crossMenuMnemonic) {
539: return false;
540: }
541: boolean enableStandardModifiers = defaultManager
542: .isComponentPartOfCurrentMenu(this );
543: return isMnemonicModifiers(modifiers,
544: enableStandardModifiers);
545: }
546: return isStandardModifiers(modifiers);
547: }
548:
549: private boolean isMnemonicModifiers(int modifiers,
550: boolean forceStandardCheck) {
551: if (forceStandardCheck && isStandardModifiers(modifiers)) {
552: return true;
553: }
554: if (Utilities.isEmptyArray(uiMnemonicModifiers)) {
555: return false;
556: }
557: for (int i = 0; i < uiMnemonicModifiers.length; i++) {
558: if ((modifiers & uiMnemonicModifiers[i]) != 0) {
559: return true;
560: }
561: }
562: return false;
563: }
564:
565: private boolean isStandardModifiers(int modifiers) {
566: return (modifiers == 0)
567: || (modifiers & InputEvent.ALT_DOWN_MASK) != 0;
568: }
569:
570: private int getValidIndex(int index) {
571: return index < getItemCount() ? index : getItemCount();
572: }
573: }
|