1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.awt; 19 20import java.awt.event.FocusListener; 21import java.awt.event.MouseEvent; 22import java.awt.peer.MenuComponentPeer; 23import java.io.Serializable; 24import java.util.Locale; //import javax.accessibility.Accessible; 25//import javax.accessibility.AccessibleComponent; 26//import javax.accessibility.AccessibleContext; 27//import javax.accessibility.AccessibleRole; 28//import javax.accessibility.AccessibleSelection; 29//import javax.accessibility.AccessibleStateSet; 30import org.apache.harmony.awt.gl.MultiRectArea; 31import org.apache.harmony.awt.state.MenuItemState; 32import org.apache.harmony.awt.state.MenuState; 33import org.apache.harmony.luni.util.NotImplementedException; 34 35/** 36 * The MenuComponent abstract class is the superclass for menu components. Menu 37 * components receive and process AWT events. 38 * 39 * @since Android 1.0 40 */ 41public abstract class MenuComponent implements Serializable { 42 43 /** 44 * The Constant serialVersionUID. 45 */ 46 private static final long serialVersionUID = -4536902356223894379L; 47 48 /** 49 * The name. 50 */ 51 private String name; 52 53 /** 54 * The font. 55 */ 56 private Font font; 57 58 /** 59 * The parent. 60 */ 61 MenuContainer parent; 62 63 /** 64 * The deprecated event handler. 65 */ 66 boolean deprecatedEventHandler = true; 67 68 /** 69 * The selected item index. 70 */ 71 private int selectedItemIndex; 72 73 // ???AWT: private AccessibleContext accessibleContext; 74 75 /** 76 * The toolkit. 77 */ 78 final Toolkit toolkit = Toolkit.getDefaultToolkit(); 79 80 // ???AWT 81 /* 82 * protected abstract class AccessibleAWTMenuComponent extends 83 * AccessibleContext implements Serializable, AccessibleComponent, 84 * AccessibleSelection { private static final long serialVersionUID = 85 * -4269533416223798698L; public void addFocusListener(FocusListener 86 * listener) { } public boolean contains(Point pt) { return false; } public 87 * Accessible getAccessibleAt(Point pt) { return null; } public Color 88 * getBackground() { return null; } public Rectangle getBounds() { return 89 * null; } public Cursor getCursor() { return null; } public Font getFont() 90 * { return MenuComponent.this.getFont(); } public FontMetrics 91 * getFontMetrics(Font font) { return null; } public Color getForeground() { 92 * return null; } public Point getLocation() { return null; } public Point 93 * getLocationOnScreen() { return null; } public Dimension getSize() { 94 * return null; } public boolean isEnabled() { return true; // always 95 * enabled } public boolean isFocusTraversable() { return true; // always 96 * focus traversable } public boolean isShowing() { return true;// always 97 * showing } public boolean isVisible() { return true; // always visible } 98 * public void removeFocusListener(FocusListener listener) { } public void 99 * requestFocus() { } public void setBackground(Color color) { } public void 100 * setBounds(Rectangle rect) { } public void setCursor(Cursor cursor) { } 101 * public void setEnabled(boolean enabled) { } public void setFont(Font 102 * font) { MenuComponent.this.setFont(font); } public void 103 * setForeground(Color color) { } public void setLocation(Point pt) { } 104 * public void setSize(Dimension pt) { } public void setVisible(boolean 105 * visible) { } public void addAccessibleSelection(int index) { } public 106 * void clearAccessibleSelection() { } public Accessible 107 * getAccessibleSelection(int index) { return null; } public int 108 * getAccessibleSelectionCount() { return 0; } public boolean 109 * isAccessibleChildSelected(int index) { return false; } public void 110 * removeAccessibleSelection(int index) { } public void 111 * selectAllAccessibleSelection() { } 112 * @Override public Accessible getAccessibleChild(int index) { return null; 113 * } 114 * @Override public int getAccessibleChildrenCount() { return 0; } 115 * @Override public AccessibleComponent getAccessibleComponent() { return 116 * this; } 117 * @Override public String getAccessibleDescription() { return 118 * super.getAccessibleDescription(); } 119 * @Override public int getAccessibleIndexInParent() { toolkit.lockAWT(); 120 * try { Accessible aParent = getAccessibleParent(); int aIndex = -1; if 121 * (aParent instanceof MenuComponent) { MenuComponent parent = 122 * (MenuComponent) aParent; int count = parent.getItemCount(); for (int i = 123 * 0; i < count; i++) { MenuComponent comp = parent.getItem(i); if (comp 124 * instanceof Accessible) { aIndex++; if (comp == MenuComponent.this) { 125 * return aIndex; } } } } return -1; } finally { toolkit.unlockAWT(); } } 126 * @Override public String getAccessibleName() { return 127 * super.getAccessibleName(); } 128 * @Override public Accessible getAccessibleParent() { toolkit.lockAWT(); 129 * try { Accessible aParent = super.getAccessibleParent(); if (aParent != 130 * null) { return aParent; } MenuContainer parent = getParent(); if (parent 131 * instanceof Accessible) { aParent = (Accessible) parent; } return aParent; 132 * } finally { toolkit.unlockAWT(); } } 133 * @Override public AccessibleRole getAccessibleRole() { return 134 * AccessibleRole.AWT_COMPONENT; } 135 * @Override public AccessibleSelection getAccessibleSelection() { return 136 * this; } 137 * @Override public AccessibleStateSet getAccessibleStateSet() { return new 138 * AccessibleStateSet(); } 139 * @Override public Locale getLocale() { return Locale.getDefault(); } } 140 */ 141 142 /** 143 * The accessor to MenuComponent internal state, utilized by the visual 144 * theme. 145 * 146 * @throws HeadlessException 147 * the headless exception. 148 */ 149 // ???AWT 150 /* 151 * class State implements MenuState { Dimension size; Dimension getSize() { 152 * if (size == null) { calculate(); } return size; } public int getWidth() { 153 * return getSize().width; } public int getHeight() { return 154 * getSize().height; } public Font getFont() { return 155 * MenuComponent.this.getFont(); } public int getItemCount() { return 156 * MenuComponent.this.getItemCount(); } public int getSelectedItemIndex() { 157 * return MenuComponent.this.getSelectedItemIndex(); } public boolean 158 * isFontSet() { return MenuComponent.this.isFontSet(); } 159 * @SuppressWarnings("deprecation") public FontMetrics getFontMetrics(Font 160 * f) { return MenuComponent.this.toolkit.getFontMetrics(f); } public Point 161 * getLocation() { return MenuComponent.this.getLocation(); } public 162 * MenuItemState getItem(int index) { MenuItem item = 163 * MenuComponent.this.getItem(index); return item.itemState; } public void 164 * setSize(int w, int h) { this.size = new Dimension(w, h); } void 165 * calculate() { size = new Dimension(); 166 * size.setSize(toolkit.theme.calculateMenuSize(this)); } void reset() { for 167 * (int i = 0; i < getItemCount(); i++) { ((MenuItem.State) 168 * getItem(i)).reset(); } } } 169 */ 170 171 /** 172 * Pop-up box for menu. It transfers the paint events, keyboard and mouse 173 * events to the menu component itself. 174 */ 175 // ???AWT 176 /* 177 * class MenuPopupBox extends PopupBox { private final Point lastMousePos = 178 * new Point(); 179 * @Override boolean isMenu() { return true; } 180 * @Override void paint(Graphics gr) { MenuComponent.this.paint(gr); } 181 * @Override void onKeyEvent(int eventId, int vKey, long when, int 182 * modifiers) { MenuComponent.this.onKeyEvent(eventId, vKey, when, 183 * modifiers); } 184 * @Override void onMouseEvent(int eventId, Point where, int mouseButton, 185 * long when, int modifiers, int wheelRotation) { // prevent conflict of 186 * mouse and keyboard // when sub-menu drops down due to keyboard navigation 187 * if (lastMousePos.equals(where) && (eventId == MouseEvent.MOUSE_MOVED || 188 * eventId == MouseEvent.MOUSE_ENTERED)) { return; } 189 * lastMousePos.setLocation(where); MenuComponent.this.onMouseEvent(eventId, 190 * where, mouseButton, when, modifiers); } } 191 */ 192 193 /** 194 * Instantiates a new MenuComponent object. 195 * 196 * @throws HeadlessException 197 * if the graphical interface environment can't support 198 * MenuComponents. 199 */ 200 public MenuComponent() throws HeadlessException { 201 toolkit.lockAWT(); 202 try { 203 Toolkit.checkHeadless(); 204 name = autoName(); 205 selectedItemIndex = -1; 206 } finally { 207 toolkit.unlockAWT(); 208 } 209 } 210 211 /** 212 * Gets the name of the MenuComponent object. 213 * 214 * @return the name of the MenuComponent object. 215 */ 216 public String getName() { 217 toolkit.lockAWT(); 218 try { 219 return name; 220 } finally { 221 toolkit.unlockAWT(); 222 } 223 } 224 225 /** 226 * Returns a String representation of the MenuComponent object. 227 * 228 * @return a String representation of the MenuComponent object. 229 */ 230 @Override 231 public String toString() { 232 toolkit.lockAWT(); 233 try { 234 return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ 235 } finally { 236 toolkit.unlockAWT(); 237 } 238 } 239 240 /** 241 * Gets the parent menu container. 242 * 243 * @return the parent. 244 */ 245 public MenuContainer getParent() { 246 toolkit.lockAWT(); 247 try { 248 return parent; 249 } finally { 250 toolkit.unlockAWT(); 251 } 252 } 253 254 /** 255 * Sets the name of the MenuComponent to the specified string. 256 * 257 * @param name 258 * the new name of the MenuComponent object. 259 */ 260 public void setName(String name) { 261 toolkit.lockAWT(); 262 try { 263 this.name = name; 264 } finally { 265 toolkit.unlockAWT(); 266 } 267 } 268 269 /** 270 * Dispatches AWT event. 271 * 272 * @param event 273 * the AWTEvent. 274 */ 275 public final void dispatchEvent(AWTEvent event) { 276 toolkit.lockAWT(); 277 try { 278 processEvent(event); 279 if (deprecatedEventHandler) { 280 postDeprecatedEvent(event); 281 } 282 } finally { 283 toolkit.unlockAWT(); 284 } 285 } 286 287 /** 288 * Post deprecated event. 289 * 290 * @param event 291 * the event. 292 */ 293 void postDeprecatedEvent(AWTEvent event) { 294 Event evt = event.getEvent(); 295 if (evt != null) { 296 postEvent(evt); 297 } 298 } 299 300 /** 301 * Gets the peer of the MenuComponent; an application must not use this 302 * method directly. 303 * 304 * @return the MenuComponentPeer object. 305 * @throws NotImplementedException 306 * if this method is not implemented by a subclass. 307 * @deprecated an application must not use this method directly. 308 */ 309 @Deprecated 310 public MenuComponentPeer getPeer() throws org.apache.harmony.luni.util.NotImplementedException { 311 toolkit.lockAWT(); 312 try { 313 } finally { 314 toolkit.unlockAWT(); 315 } 316 if (true) { 317 throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$ 318 } 319 return null; 320 } 321 322 /** 323 * Gets the locking object of this MenuComponent. 324 * 325 * @return the locking object of this MenuComponent. 326 */ 327 protected final Object getTreeLock() { 328 return toolkit.awtTreeLock; 329 } 330 331 /** 332 * Posts the Event to the MenuComponent. 333 * 334 * @param e 335 * the Event. 336 * @return true, if the event is posted successfully, false otherwise. 337 * @deprecated Replaced dispatchEvent method. 338 */ 339 @SuppressWarnings("deprecation") 340 @Deprecated 341 public boolean postEvent(Event e) { 342 toolkit.lockAWT(); 343 try { 344 if (parent != null) { 345 return parent.postEvent(e); 346 } 347 return false; 348 } finally { 349 toolkit.unlockAWT(); 350 } 351 } 352 353 /** 354 * Returns the string representation of the MenuComponent state. 355 * 356 * @return returns the string representation of the MenuComponent state. 357 */ 358 protected String paramString() { 359 toolkit.lockAWT(); 360 try { 361 return getName(); 362 } finally { 363 toolkit.unlockAWT(); 364 } 365 } 366 367 // ???AWT 368 /* 369 * public AccessibleContext getAccessibleContext() { toolkit.lockAWT(); try 370 * { if (accessibleContext == null) { accessibleContext = 371 * createAccessibleContext(); } return accessibleContext; } finally { 372 * toolkit.unlockAWT(); } } 373 */ 374 375 /** 376 * Gets the font of the MenuComponent object. 377 * 378 * @return the Font of the MenuComponent object. 379 */ 380 public Font getFont() { 381 toolkit.lockAWT(); 382 try { 383 if (font == null && hasDefaultFont()) { 384 return toolkit.getDefaultFont(); 385 } 386 if (font == null && parent != null) { 387 return parent.getFont(); 388 } 389 return font; 390 } finally { 391 toolkit.unlockAWT(); 392 } 393 } 394 395 /** 396 * Checks if is font set. 397 * 398 * @return true, if is font set 399 */ 400 boolean isFontSet() { 401 return font != null 402 || ((parent instanceof MenuComponent) && ((MenuComponent)parent).isFontSet()); 403 } 404 405 /** 406 * Checks for default font. 407 * 408 * @return true, if successful. 409 */ 410 boolean hasDefaultFont() { 411 return false; 412 } 413 414 /** 415 * Processes an AWTEevent on this menu component. 416 * 417 * @param event 418 * the AWTEvent. 419 */ 420 protected void processEvent(AWTEvent event) { 421 toolkit.lockAWT(); 422 try { 423 // do nothing 424 } finally { 425 toolkit.unlockAWT(); 426 } 427 } 428 429 /** 430 * Removes the peer of the MenuComponent. 431 */ 432 public void removeNotify() { 433 toolkit.lockAWT(); 434 try { 435 } finally { 436 toolkit.unlockAWT(); 437 } 438 } 439 440 /** 441 * Sets the Font for this MenuComponent object. 442 * 443 * @param font 444 * the new Font to be used for this MenuComponent. 445 */ 446 public void setFont(Font font) { 447 toolkit.lockAWT(); 448 try { 449 this.font = font; 450 } finally { 451 toolkit.unlockAWT(); 452 } 453 } 454 455 /** 456 * Sets the parent. 457 * 458 * @param parent 459 * the new parent. 460 */ 461 void setParent(MenuContainer parent) { 462 this.parent = parent; 463 } 464 465 /** 466 * Gets the location. 467 * 468 * @return the location. 469 */ 470 Point getLocation() { 471 // to be overridden 472 return new Point(0, 0); 473 } 474 475 /** 476 * Gets the width. 477 * 478 * @return the width. 479 */ 480 int getWidth() { 481 // to be overridden 482 return 1; 483 } 484 485 /** 486 * Gets the height. 487 * 488 * @return the height. 489 */ 490 int getHeight() { 491 // to be overridden 492 return 1; 493 } 494 495 /** 496 * Recursively find the menu item for a menu shortcut. 497 * 498 * @param gr 499 * the gr. 500 * @return the menu item; or null if the item is not available for this 501 * shortcut. 502 */ 503 // ???AWT 504 /* 505 * MenuItem getShortcutMenuItemImpl(MenuShortcut ms) { if (ms == null) { 506 * return null; } for (int i = 0; i < getItemCount(); i++) { MenuItem mi = 507 * getItem(i); if (mi instanceof Menu) { mi = ((Menu) 508 * mi).getShortcutMenuItemImpl(ms); if (mi != null) { return mi; } } else if 509 * (ms.equals(mi.getShortcut())) { return mi; } } return null; } 510 */ 511 512 void paint(Graphics gr) { 513 gr.setColor(Color.LIGHT_GRAY); 514 gr.fillRect(0, 0, getWidth(), getHeight()); 515 gr.setColor(Color.BLACK); 516 } 517 518 /** 519 * Mouse events handler. 520 * 521 * @param eventId 522 * one of the MouseEvent.MOUSE_* constants. 523 * @param where 524 * mouse location. 525 * @param mouseButton 526 * mouse button that was pressed or released. 527 * @param when 528 * event time. 529 * @param modifiers 530 * input event modifiers. 531 */ 532 void onMouseEvent(int eventId, Point where, int mouseButton, long when, int modifiers) { 533 // to be overridden 534 } 535 536 /** 537 * Keyboard event handler. 538 * 539 * @param eventId 540 * one of the KeyEvent.KEY_* constants. 541 * @param vKey 542 * the key code. 543 * @param when 544 * event time. 545 * @param modifiers 546 * input event modifiers. 547 */ 548 void onKeyEvent(int eventId, int vKey, long when, int modifiers) { 549 // to be overridden 550 } 551 552 /** 553 * Post the ActionEvent or ItemEvent, depending on type of the menu item. 554 * 555 * @param index 556 * the index. 557 * @return the item rect. 558 */ 559 // ???AWT 560 /* 561 * void fireItemAction(int item, long when, int modifiers) { MenuItem mi = 562 * getItem(item); mi.itemSelected(when, modifiers); } MenuItem getItem(int 563 * index) { // to be overridden return null; } int getItemCount() { return 564 * 0; } 565 */ 566 567 /** 568 * @return The sub-menu of currently selecetd item, or null if such a 569 * sub-menu is not available. 570 */ 571 // ???AWT 572 /* 573 * Menu getSelectedSubmenu() { if (selectedItemIndex < 0) { return null; } 574 * MenuItem item = getItem(selectedItemIndex); return (item instanceof Menu) 575 * ? (Menu) item : null; } 576 */ 577 578 /** 579 * Convenience method for selectItem(index, true). 580 */ 581 // ???AWT 582 /* 583 * void selectItem(int index) { selectItem(index, true); } 584 */ 585 586 /** 587 * Change the selection in the menu. 588 * 589 * @param index 590 * new selecetd item's index. 591 * @param showSubMenu 592 * if new selected item has a sub-menu, should that sub-menu be 593 * displayed. 594 */ 595 // ???AWT 596 /* 597 * void selectItem(int index, boolean showSubMenu) { if (selectedItemIndex 598 * == index) { return; } if (selectedItemIndex >= 0 && 599 * getItem(selectedItemIndex) instanceof Menu) { ((Menu) 600 * getItem(selectedItemIndex)).hide(); } MultiRectArea clip = 601 * getUpdateClip(index, selectedItemIndex); selectedItemIndex = index; 602 * Graphics gr = getGraphics(clip); if (gr != null) { paint(gr); } if 603 * (showSubMenu) { showSubMenu(selectedItemIndex); } } 604 */ 605 606 /** 607 * Change the selected item to the next one in the requested direction 608 * moving cyclically, skipping separators 609 * 610 * @param forward 611 * the direction to move the selection. 612 * @param showSubMenu 613 * if new selected item has a sub-menu, should that sub-menu be 614 * displayed. 615 */ 616 // ???AWT 617 /* 618 * void selectNextItem(boolean forward, boolean showSubMenu) { int selected 619 * = getSelectedItemIndex(); int count = getItemCount(); if (count == 0) { 620 * return; } if (selected < 0) { selected = (forward ? count - 1 : 0); } int 621 * i = selected; do { i = (forward ? (i + 1) : (i + count - 1)) % count; i 622 * %= count; MenuItem item = getItem(i); if (!"-".equals(item.getLabel())) { 623 * //$NON-NLS-1$ selectItem(i, showSubMenu); return; } } while (i != 624 * selected); } void showSubMenu(int index) { if ((index < 0) || 625 * !isActive()) { return; } MenuItem item = getItem(index); if (item 626 * instanceof Menu) { Menu menu = ((Menu) getItem(index)); if 627 * (menu.getItemCount() == 0) { return; } Point location = 628 * getSubmenuLocation(index); menu.show(location.x, location.y, false); } } 629 */ 630 631 /** 632 * @return the menu bar which is the root of current menu's hierarchy; or 633 * null if the hierarchy root is not a menu bar. 634 */ 635 // ???AWT 636 /* 637 * MenuBar getMenuBar() { if (parent instanceof MenuBar) { return (MenuBar) 638 * parent; } if (parent instanceof MenuComponent) { return ((MenuComponent) 639 * parent).getMenuBar(); } return null; } PopupBox getPopupBox() { return 640 * null; } 641 */ 642 643 Rectangle getItemRect(int index) { 644 // to be overridden 645 return null; 646 } 647 648 /** 649 * Determine the clip region when menu selection is changed from index1 to 650 * index2. 651 * 652 * @param index1 653 * old selected item. 654 * @param index2 655 * new selected item. 656 * @return the region to repaint. 657 */ 658 final MultiRectArea getUpdateClip(int index1, int index2) { 659 MultiRectArea clip = new MultiRectArea(); 660 if (index1 >= 0) { 661 clip.add(getItemRect(index1)); 662 } 663 if (index2 >= 0) { 664 clip.add(getItemRect(index2)); 665 } 666 return clip; 667 } 668 669 /** 670 * Gets the submenu location. 671 * 672 * @param index 673 * the index. 674 * @return the submenu location. 675 */ 676 Point getSubmenuLocation(int index) { 677 // to be overridden 678 return new Point(0, 0); 679 } 680 681 /** 682 * Gets the selected item index. 683 * 684 * @return the selected item index. 685 */ 686 int getSelectedItemIndex() { 687 return selectedItemIndex; 688 } 689 690 /** 691 * Hide. 692 */ 693 void hide() { 694 selectedItemIndex = -1; 695 if (parent instanceof MenuComponent) { 696 ((MenuComponent)parent).itemHidden(this); 697 } 698 } 699 700 /** 701 * Item hidden. 702 * 703 * @param mc 704 * the mc. 705 */ 706 void itemHidden(MenuComponent mc) { 707 // to be overridden 708 } 709 710 /** 711 * Checks if is visible. 712 * 713 * @return true, if is visible. 714 */ 715 boolean isVisible() { 716 return true; 717 } 718 719 /** 720 * Checks if is active. 721 * 722 * @return true, if is active. 723 */ 724 boolean isActive() { 725 return true; 726 } 727 728 /** 729 * Hide all menu hierarchy. 730 */ 731 void endMenu() { 732 // ???AWT: toolkit.dispatcher.popupDispatcher.deactivateAll(); 733 } 734 735 /** 736 * Handle the mouse click or Enter key event on a menu's item. 737 * 738 * @param when 739 * the event time. 740 * @param modifiers 741 * input event modifiers. 742 */ 743 void itemSelected(long when, int modifiers) { 744 endMenu(); 745 } 746 747 /** 748 * Auto name. 749 * 750 * @return the string. 751 */ 752 String autoName() { 753 String name = getClass().getName(); 754 if (name.indexOf("$") != -1) { //$NON-NLS-1$ 755 return null; 756 } 757 // ???AWT: int number = toolkit.autoNumber.nextMenuComponent++; 758 int number = 0; 759 name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$ 760 return name; 761 } 762 763 /** 764 * Creates the Graphics object for the pop-up box of this menu component. 765 * 766 * @param clip 767 * the clip to set on this Graphics. 768 * @return the created Graphics object, or null if such object is not 769 * available. 770 */ 771 Graphics getGraphics(MultiRectArea clip) { 772 // to be overridden 773 return null; 774 } 775 776 /** 777 * @return accessible context specific for particular menu component. 778 */ 779 // ???AWT 780 /* 781 * AccessibleContext createAccessibleContext() { return null; } 782 */ 783} 784