< prev index next >

src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java

Print this page


   1 /*
   2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 310     /**
 311      * Handles mnemonic for children JMenuItems.
 312      * @since 1.5
 313      */
 314     private class BasicMenuKeyListener implements MenuKeyListener {
 315         MenuElement menuToOpen = null;
 316 
 317         public void menuKeyTyped(MenuKeyEvent e) {
 318             if (menuToOpen != null) {
 319                 // we have a submenu to open
 320                 JPopupMenu subpopup = ((JMenu)menuToOpen).getPopupMenu();
 321                 MenuElement subitem = findEnabledChild(
 322                         subpopup.getSubElements(), -1, true);
 323 
 324                 ArrayList<MenuElement> lst = new ArrayList<MenuElement>(Arrays.asList(e.getPath()));
 325                 lst.add(menuToOpen);
 326                 lst.add(subpopup);
 327                 if (subitem != null) {
 328                     lst.add(subitem);
 329                 }
 330                 MenuElement newPath[] = new MenuElement[0];
 331                 newPath = lst.toArray(newPath);
 332                 MenuSelectionManager.defaultManager().setSelectedPath(newPath);
 333                 e.consume();
 334             }
 335             menuToOpen = null;
 336         }
 337 
 338         public void menuKeyPressed(MenuKeyEvent e) {
 339             char keyChar = e.getKeyChar();
 340 
 341             // Handle the case for Escape or Enter...
 342             if (!Character.isLetterOrDigit(keyChar)) {
 343                 return;
 344             }
 345 
 346             MenuSelectionManager manager = e.getMenuSelectionManager();
 347             MenuElement path[] = e.getPath();
 348             MenuElement items[] = popupMenu.getSubElements();
 349             int currentIndex = -1;
 350             int matches = 0;
 351             int firstMatch = -1;
 352             int indexes[] = null;
 353 
 354             for (int j = 0; j < items.length; j++) {
 355                 if (! (items[j] instanceof JMenuItem)) {
 356                     continue;
 357                 }
 358                 JMenuItem item = (JMenuItem)items[j];
 359                 int mnemonic = item.getMnemonic();
 360                 if (item.isEnabled() &&
 361                     item.isVisible() && lower(keyChar) == lower(mnemonic)) {
 362                     if (matches == 0) {
 363                         firstMatch = j;
 364                         matches++;
 365                     } else {
 366                         if (indexes == null) {
 367                             indexes = new int[items.length];
 368                             indexes[0] = firstMatch;
 369                         }
 370                         indexes[matches++] = j;
 371                     }
 372                 }


 380             } else if (matches == 1) {
 381                 // Invoke the menu action
 382                 JMenuItem item = (JMenuItem)items[firstMatch];
 383                 if (item instanceof JMenu) {
 384                     // submenus are handled in menuKeyTyped
 385                     menuToOpen = item;
 386                 } else if (item.isEnabled()) {
 387                     // we have a menu item
 388                     manager.clearSelectedPath();
 389                     item.doClick();
 390                 }
 391                 e.consume();
 392             } else {
 393                 // Select the menu item with the matching mnemonic. If
 394                 // the same mnemonic has been invoked then select the next
 395                 // menu item in the cycle.
 396                 MenuElement newItem;
 397 
 398                 newItem = items[indexes[(currentIndex + 1) % matches]];
 399 
 400                 MenuElement newPath[] = new MenuElement[path.length+1];
 401                 System.arraycopy(path, 0, newPath, 0, path.length);
 402                 newPath[path.length] = newItem;
 403                 manager.setSelectedPath(newPath);
 404                 e.consume();
 405             }
 406         }
 407 
 408         public void menuKeyReleased(MenuKeyEvent e) {
 409         }
 410 
 411         private char lower(char keyChar) {
 412             return Character.toLowerCase(keyChar);
 413         }
 414 
 415         private char lower(int mnemonic) {
 416             return Character.toLowerCase((char) mnemonic);
 417         }
 418     }
 419 
 420     private static class Actions extends UIAction {


 453             else if (key == SELECT_PARENT) {
 454                 selectParentChild(PARENT);
 455             }
 456             else if (key == SELECT_CHILD) {
 457                 selectParentChild(CHILD);
 458             }
 459             else if (key == RETURN) {
 460                 doReturn();
 461             }
 462         }
 463 
 464         private void doReturn() {
 465             KeyboardFocusManager fmgr =
 466                 KeyboardFocusManager.getCurrentKeyboardFocusManager();
 467             Component focusOwner = fmgr.getFocusOwner();
 468             if(focusOwner != null && !(focusOwner instanceof JRootPane)) {
 469                 return;
 470             }
 471 
 472             MenuSelectionManager msm = MenuSelectionManager.defaultManager();
 473             MenuElement path[] = msm.getSelectedPath();
 474             MenuElement lastElement;
 475             if(path.length > 0) {
 476                 lastElement = path[path.length-1];
 477                 if(lastElement instanceof JMenu) {
 478                     MenuElement newPath[] = new MenuElement[path.length+1];
 479                     System.arraycopy(path,0,newPath,0,path.length);
 480                     newPath[path.length] = ((JMenu)lastElement).getPopupMenu();
 481                     msm.setSelectedPath(newPath);
 482                 } else if(lastElement instanceof JMenuItem) {
 483                     JMenuItem mi = (JMenuItem)lastElement;
 484 
 485                     if (mi.getUI() instanceof BasicMenuItemUI) {
 486                         ((BasicMenuItemUI)mi.getUI()).doClick(msm);
 487                     }
 488                     else {
 489                         msm.clearSelectedPath();
 490                         mi.doClick(0);
 491                     }
 492                 }
 493             }
 494         }
 495         private void selectParentChild(boolean direction) {
 496             MenuSelectionManager msm = MenuSelectionManager.defaultManager();
 497             MenuElement path[] = msm.getSelectedPath();
 498             int len = path.length;
 499 
 500             if (direction == PARENT) {
 501                 // selecting parent
 502                 int popupIndex = len-1;
 503 
 504                 if (len > 2 &&
 505                     // check if we have an open submenu. A submenu item may or
 506                     // may not be selected, so submenu popup can be either the
 507                     // last or next to the last item.
 508                     (path[popupIndex] instanceof JPopupMenu ||
 509                      path[--popupIndex] instanceof JPopupMenu) &&
 510                     !((JMenu)path[popupIndex-1]).isTopLevelMenu()) {
 511 
 512                     // we have a submenu, just close it
 513                     MenuElement newPath[] = new MenuElement[popupIndex];
 514                     System.arraycopy(path, 0, newPath, 0, popupIndex);
 515                     msm.setSelectedPath(newPath);
 516                     return;
 517                 }
 518             } else {
 519                 // selecting child
 520                 if (len > 0 && path[len-1] instanceof JMenu &&
 521                     !((JMenu)path[len-1]).isTopLevelMenu()) {
 522 
 523                     // we have a submenu, open it
 524                     JMenu menu = (JMenu)path[len-1];
 525                     JPopupMenu popup = menu.getPopupMenu();
 526                     MenuElement[] subs = popup.getSubElements();
 527                     MenuElement item = findEnabledChild(subs, -1, true);
 528                     MenuElement[] newPath;
 529 
 530                     if (item == null) {
 531                         newPath = new MenuElement[len+1];
 532                     } else {
 533                         newPath = new MenuElement[len+2];
 534                         newPath[len+1] = item;
 535                     }
 536                     System.arraycopy(path, 0, newPath, 0, len);
 537                     newPath[len] = popup;
 538                     msm.setSelectedPath(newPath);
 539                     return;
 540                 }
 541             }
 542 
 543             // check if we have a toplevel menu selected.
 544             // If this is the case, we select another toplevel menu
 545             if (len > 1 && path[0] instanceof JMenuBar) {
 546                 MenuElement currentMenu = path[1];
 547                 MenuElement nextMenu = findEnabledChild(
 548                     path[0].getSubElements(), currentMenu, direction);
 549 
 550                 if (nextMenu != null && nextMenu != currentMenu) {
 551                     MenuElement newSelection[];
 552                     if (len == 2) {
 553                         // menu is selected but its popup not shown
 554                         newSelection = new MenuElement[2];
 555                         newSelection[0] = path[0];
 556                         newSelection[1] = nextMenu;
 557                     } else {
 558                         // menu is selected and its popup is shown
 559                         newSelection = new MenuElement[3];
 560                         newSelection[0] = path[0];
 561                         newSelection[1] = nextMenu;
 562                         newSelection[2] = ((JMenu)nextMenu).getPopupMenu();
 563                     }
 564                     msm.setSelectedPath(newSelection);
 565                 }
 566             }
 567         }
 568 
 569         private void selectItem(boolean direction) {
 570             MenuSelectionManager msm = MenuSelectionManager.defaultManager();
 571             MenuElement path[] = msm.getSelectedPath();
 572             if (path.length == 0) {
 573                 return;
 574             }
 575             int len = path.length;
 576             if (len == 1 && path[0] instanceof JPopupMenu) {
 577 
 578                 JPopupMenu popup = (JPopupMenu) path[0];
 579                 MenuElement[] newPath = new MenuElement[2];
 580                 newPath[0] = popup;
 581                 newPath[1] = findEnabledChild(popup.getSubElements(), -1, direction);
 582                 msm.setSelectedPath(newPath);
 583             } else if (len == 2 &&
 584                     path[0] instanceof JMenuBar && path[1] instanceof JMenu) {
 585 
 586                 // a toplevel menu is selected, but its popup not shown.
 587                 // Show the popup and select the first item
 588                 JPopupMenu popup = ((JMenu)path[1]).getPopupMenu();
 589                 MenuElement next =
 590                     findEnabledChild(popup.getSubElements(), -1, FORWARD);
 591                 MenuElement[] newPath;


 621                     // all items in the popup are disabled.
 622                     // We're going to find the parent popup menu and select
 623                     // its next item. If there's no parent popup menu (i.e.
 624                     // current menu is toplevel), do nothing
 625                     if (len > 2 && path[len-3] instanceof JPopupMenu) {
 626                         popup = ((JPopupMenu)path[len-3]);
 627                         next = findEnabledChild(popup.getSubElements(),
 628                                                 menu, direction);
 629 
 630                         if (next != null && next != menu) {
 631                             MenuElement[] newPath = new MenuElement[len-1];
 632                             System.arraycopy(path, 0, newPath, 0, len-2);
 633                             newPath[len-2] = next;
 634                             msm.setSelectedPath(newPath);
 635                         }
 636                     }
 637                 }
 638 
 639             } else {
 640                 // just select the next item, no path expansion needed
 641                 MenuElement subs[] = path[len-2].getSubElements();
 642                 MenuElement nextChild =
 643                     findEnabledChild(subs, path[len-1], direction);
 644                 if (nextChild == null) {
 645                     nextChild = findEnabledChild(subs, -1, direction);
 646                 }
 647                 if (nextChild != null) {
 648                     path[len-1] = nextChild;
 649                     msm.setSelectedPath(path);
 650                 }
 651             }
 652         }
 653 
 654         private void cancel() {
 655             // 4234793: This action should call JPopupMenu.firePopupMenuCanceled but it's
 656             // a protected method. The real solution could be to make
 657             // firePopupMenuCanceled public and call it directly.
 658             JPopupMenu lastPopup = getLastPopup();
 659             if (lastPopup != null) {
 660                 lastPopup.putClientProperty("JPopupMenu.firePopupMenuCanceled", Boolean.TRUE);
 661             }
 662             String mode = UIManager.getString("Menu.cancelMode");
 663             if ("hideMenuTree".equals(mode)) {
 664                 MenuSelectionManager.defaultManager().clearSelectedPath();
 665             } else {
 666                 shortenSelectedPath();
 667             }
 668         }
 669 
 670         private void shortenSelectedPath() {
 671             MenuElement path[] = MenuSelectionManager.defaultManager().getSelectedPath();
 672             if (path.length <= 2) {
 673                 MenuSelectionManager.defaultManager().clearSelectedPath();
 674                 return;
 675             }
 676             // unselect MenuItem and its Popup by default
 677             int value = 2;
 678             MenuElement lastElement = path[path.length - 1];
 679             JPopupMenu lastPopup = getLastPopup();
 680             if (lastElement == lastPopup) {
 681                 MenuElement previousElement = path[path.length - 2];
 682                 if (previousElement instanceof JMenu) {
 683                     JMenu lastMenu = (JMenu) previousElement;
 684                     if (lastMenu.isEnabled() && lastPopup.getComponentCount() > 0) {
 685                         // unselect the last visible popup only
 686                         value = 1;
 687                     } else {
 688                         // unselect invisible popup and two visible elements
 689                         value = 3;
 690                     }
 691                 }
 692             }
 693             if (path.length - value <= 2
 694                     && !UIManager.getBoolean("Menu.preserveTopLevelSelection")) {
 695                 // clear selection for the topLevelMenu
 696                 value = path.length;
 697             }
 698             MenuElement newPath[] = new MenuElement[path.length - value];
 699             System.arraycopy(path, 0, newPath, 0, path.length - value);
 700             MenuSelectionManager.defaultManager().setSelectedPath(newPath);
 701         }
 702     }
 703 
 704     private static MenuElement nextEnabledChild(MenuElement e[],
 705                                                 int fromIndex, int toIndex) {
 706         for (int i=fromIndex; i<=toIndex; i++) {
 707             if (e[i] != null) {
 708                 Component comp = e[i].getComponent();
 709                 if ( comp != null
 710                         && (comp.isEnabled() || UIManager.getBoolean("MenuItem.disabledAreNavigable"))
 711                         && comp.isVisible()) {
 712                     return e[i];
 713                 }
 714             }
 715         }
 716         return null;
 717     }
 718 
 719     private static MenuElement previousEnabledChild(MenuElement e[],
 720                                                 int fromIndex, int toIndex) {
 721         for (int i=fromIndex; i>=toIndex; i--) {
 722             if (e[i] != null) {
 723                 Component comp = e[i].getComponent();
 724                 if ( comp != null
 725                         && (comp.isEnabled() || UIManager.getBoolean("MenuItem.disabledAreNavigable"))
 726                         && comp.isVisible()) {
 727                     return e[i];
 728                 }
 729             }
 730         }
 731         return null;
 732     }
 733 
 734     static MenuElement findEnabledChild(MenuElement e[], int fromIndex,
 735                                                 boolean forward) {
 736         MenuElement result;
 737         if (forward) {
 738             result = nextEnabledChild(e, fromIndex+1, e.length-1);
 739             if (result == null) result = nextEnabledChild(e, 0, fromIndex-1);
 740         } else {
 741             result = previousEnabledChild(e, fromIndex-1, 0);
 742             if (result == null) result = previousEnabledChild(e, e.length-1,
 743                                                               fromIndex+1);
 744         }
 745         return result;
 746     }
 747 
 748     static MenuElement findEnabledChild(MenuElement e[],
 749                                    MenuElement elem, boolean forward) {
 750         for (int i=0; i<e.length; i++) {
 751             if (e[i] == elem) {
 752                 return findEnabledChild(e, i, forward);
 753             }
 754         }
 755         return null;
 756     }
 757 
 758     static class MouseGrabber implements ChangeListener,
 759         AWTEventListener, ComponentListener, WindowListener {
 760 
 761         Window grabbedWindow;
 762         MenuElement[] lastPathSelected;
 763 
 764         public MouseGrabber() {
 765             MenuSelectionManager msm = MenuSelectionManager.defaultManager();
 766             msm.addChangeListener(this);
 767             this.lastPathSelected = msm.getSelectedPath();
 768             if(this.lastPathSelected.length != 0) {


   1 /*
   2  * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 310     /**
 311      * Handles mnemonic for children JMenuItems.
 312      * @since 1.5
 313      */
 314     private class BasicMenuKeyListener implements MenuKeyListener {
 315         MenuElement menuToOpen = null;
 316 
 317         public void menuKeyTyped(MenuKeyEvent e) {
 318             if (menuToOpen != null) {
 319                 // we have a submenu to open
 320                 JPopupMenu subpopup = ((JMenu)menuToOpen).getPopupMenu();
 321                 MenuElement subitem = findEnabledChild(
 322                         subpopup.getSubElements(), -1, true);
 323 
 324                 ArrayList<MenuElement> lst = new ArrayList<MenuElement>(Arrays.asList(e.getPath()));
 325                 lst.add(menuToOpen);
 326                 lst.add(subpopup);
 327                 if (subitem != null) {
 328                     lst.add(subitem);
 329                 }
 330                 MenuElement[] newPath = new MenuElement[0];
 331                 newPath = lst.toArray(newPath);
 332                 MenuSelectionManager.defaultManager().setSelectedPath(newPath);
 333                 e.consume();
 334             }
 335             menuToOpen = null;
 336         }
 337 
 338         public void menuKeyPressed(MenuKeyEvent e) {
 339             char keyChar = e.getKeyChar();
 340 
 341             // Handle the case for Escape or Enter...
 342             if (!Character.isLetterOrDigit(keyChar)) {
 343                 return;
 344             }
 345 
 346             MenuSelectionManager manager = e.getMenuSelectionManager();
 347             MenuElement[] path = e.getPath();
 348             MenuElement[] items = popupMenu.getSubElements();
 349             int currentIndex = -1;
 350             int matches = 0;
 351             int firstMatch = -1;
 352             int[] indexes = null;
 353 
 354             for (int j = 0; j < items.length; j++) {
 355                 if (! (items[j] instanceof JMenuItem)) {
 356                     continue;
 357                 }
 358                 JMenuItem item = (JMenuItem)items[j];
 359                 int mnemonic = item.getMnemonic();
 360                 if (item.isEnabled() &&
 361                     item.isVisible() && lower(keyChar) == lower(mnemonic)) {
 362                     if (matches == 0) {
 363                         firstMatch = j;
 364                         matches++;
 365                     } else {
 366                         if (indexes == null) {
 367                             indexes = new int[items.length];
 368                             indexes[0] = firstMatch;
 369                         }
 370                         indexes[matches++] = j;
 371                     }
 372                 }


 380             } else if (matches == 1) {
 381                 // Invoke the menu action
 382                 JMenuItem item = (JMenuItem)items[firstMatch];
 383                 if (item instanceof JMenu) {
 384                     // submenus are handled in menuKeyTyped
 385                     menuToOpen = item;
 386                 } else if (item.isEnabled()) {
 387                     // we have a menu item
 388                     manager.clearSelectedPath();
 389                     item.doClick();
 390                 }
 391                 e.consume();
 392             } else {
 393                 // Select the menu item with the matching mnemonic. If
 394                 // the same mnemonic has been invoked then select the next
 395                 // menu item in the cycle.
 396                 MenuElement newItem;
 397 
 398                 newItem = items[indexes[(currentIndex + 1) % matches]];
 399 
 400                 MenuElement[] newPath = new MenuElement[path.length+1];
 401                 System.arraycopy(path, 0, newPath, 0, path.length);
 402                 newPath[path.length] = newItem;
 403                 manager.setSelectedPath(newPath);
 404                 e.consume();
 405             }
 406         }
 407 
 408         public void menuKeyReleased(MenuKeyEvent e) {
 409         }
 410 
 411         private char lower(char keyChar) {
 412             return Character.toLowerCase(keyChar);
 413         }
 414 
 415         private char lower(int mnemonic) {
 416             return Character.toLowerCase((char) mnemonic);
 417         }
 418     }
 419 
 420     private static class Actions extends UIAction {


 453             else if (key == SELECT_PARENT) {
 454                 selectParentChild(PARENT);
 455             }
 456             else if (key == SELECT_CHILD) {
 457                 selectParentChild(CHILD);
 458             }
 459             else if (key == RETURN) {
 460                 doReturn();
 461             }
 462         }
 463 
 464         private void doReturn() {
 465             KeyboardFocusManager fmgr =
 466                 KeyboardFocusManager.getCurrentKeyboardFocusManager();
 467             Component focusOwner = fmgr.getFocusOwner();
 468             if(focusOwner != null && !(focusOwner instanceof JRootPane)) {
 469                 return;
 470             }
 471 
 472             MenuSelectionManager msm = MenuSelectionManager.defaultManager();
 473             MenuElement[] path = msm.getSelectedPath();
 474             MenuElement lastElement;
 475             if(path.length > 0) {
 476                 lastElement = path[path.length-1];
 477                 if(lastElement instanceof JMenu) {
 478                     MenuElement[] newPath = new MenuElement[path.length+1];
 479                     System.arraycopy(path,0,newPath,0,path.length);
 480                     newPath[path.length] = ((JMenu)lastElement).getPopupMenu();
 481                     msm.setSelectedPath(newPath);
 482                 } else if(lastElement instanceof JMenuItem) {
 483                     JMenuItem mi = (JMenuItem)lastElement;
 484 
 485                     if (mi.getUI() instanceof BasicMenuItemUI) {
 486                         ((BasicMenuItemUI)mi.getUI()).doClick(msm);
 487                     }
 488                     else {
 489                         msm.clearSelectedPath();
 490                         mi.doClick(0);
 491                     }
 492                 }
 493             }
 494         }
 495         private void selectParentChild(boolean direction) {
 496             MenuSelectionManager msm = MenuSelectionManager.defaultManager();
 497             MenuElement[] path = msm.getSelectedPath();
 498             int len = path.length;
 499 
 500             if (direction == PARENT) {
 501                 // selecting parent
 502                 int popupIndex = len-1;
 503 
 504                 if (len > 2 &&
 505                     // check if we have an open submenu. A submenu item may or
 506                     // may not be selected, so submenu popup can be either the
 507                     // last or next to the last item.
 508                     (path[popupIndex] instanceof JPopupMenu ||
 509                      path[--popupIndex] instanceof JPopupMenu) &&
 510                     !((JMenu)path[popupIndex-1]).isTopLevelMenu()) {
 511 
 512                     // we have a submenu, just close it
 513                     MenuElement[] newPath = new MenuElement[popupIndex];
 514                     System.arraycopy(path, 0, newPath, 0, popupIndex);
 515                     msm.setSelectedPath(newPath);
 516                     return;
 517                 }
 518             } else {
 519                 // selecting child
 520                 if (len > 0 && path[len-1] instanceof JMenu &&
 521                     !((JMenu)path[len-1]).isTopLevelMenu()) {
 522 
 523                     // we have a submenu, open it
 524                     JMenu menu = (JMenu)path[len-1];
 525                     JPopupMenu popup = menu.getPopupMenu();
 526                     MenuElement[] subs = popup.getSubElements();
 527                     MenuElement item = findEnabledChild(subs, -1, true);
 528                     MenuElement[] newPath;
 529 
 530                     if (item == null) {
 531                         newPath = new MenuElement[len+1];
 532                     } else {
 533                         newPath = new MenuElement[len+2];
 534                         newPath[len+1] = item;
 535                     }
 536                     System.arraycopy(path, 0, newPath, 0, len);
 537                     newPath[len] = popup;
 538                     msm.setSelectedPath(newPath);
 539                     return;
 540                 }
 541             }
 542 
 543             // check if we have a toplevel menu selected.
 544             // If this is the case, we select another toplevel menu
 545             if (len > 1 && path[0] instanceof JMenuBar) {
 546                 MenuElement currentMenu = path[1];
 547                 MenuElement nextMenu = findEnabledChild(
 548                     path[0].getSubElements(), currentMenu, direction);
 549 
 550                 if (nextMenu != null && nextMenu != currentMenu) {
 551                     MenuElement[] newSelection;
 552                     if (len == 2) {
 553                         // menu is selected but its popup not shown
 554                         newSelection = new MenuElement[2];
 555                         newSelection[0] = path[0];
 556                         newSelection[1] = nextMenu;
 557                     } else {
 558                         // menu is selected and its popup is shown
 559                         newSelection = new MenuElement[3];
 560                         newSelection[0] = path[0];
 561                         newSelection[1] = nextMenu;
 562                         newSelection[2] = ((JMenu)nextMenu).getPopupMenu();
 563                     }
 564                     msm.setSelectedPath(newSelection);
 565                 }
 566             }
 567         }
 568 
 569         private void selectItem(boolean direction) {
 570             MenuSelectionManager msm = MenuSelectionManager.defaultManager();
 571             MenuElement[] path = msm.getSelectedPath();
 572             if (path.length == 0) {
 573                 return;
 574             }
 575             int len = path.length;
 576             if (len == 1 && path[0] instanceof JPopupMenu) {
 577 
 578                 JPopupMenu popup = (JPopupMenu) path[0];
 579                 MenuElement[] newPath = new MenuElement[2];
 580                 newPath[0] = popup;
 581                 newPath[1] = findEnabledChild(popup.getSubElements(), -1, direction);
 582                 msm.setSelectedPath(newPath);
 583             } else if (len == 2 &&
 584                     path[0] instanceof JMenuBar && path[1] instanceof JMenu) {
 585 
 586                 // a toplevel menu is selected, but its popup not shown.
 587                 // Show the popup and select the first item
 588                 JPopupMenu popup = ((JMenu)path[1]).getPopupMenu();
 589                 MenuElement next =
 590                     findEnabledChild(popup.getSubElements(), -1, FORWARD);
 591                 MenuElement[] newPath;


 621                     // all items in the popup are disabled.
 622                     // We're going to find the parent popup menu and select
 623                     // its next item. If there's no parent popup menu (i.e.
 624                     // current menu is toplevel), do nothing
 625                     if (len > 2 && path[len-3] instanceof JPopupMenu) {
 626                         popup = ((JPopupMenu)path[len-3]);
 627                         next = findEnabledChild(popup.getSubElements(),
 628                                                 menu, direction);
 629 
 630                         if (next != null && next != menu) {
 631                             MenuElement[] newPath = new MenuElement[len-1];
 632                             System.arraycopy(path, 0, newPath, 0, len-2);
 633                             newPath[len-2] = next;
 634                             msm.setSelectedPath(newPath);
 635                         }
 636                     }
 637                 }
 638 
 639             } else {
 640                 // just select the next item, no path expansion needed
 641                 MenuElement[] subs = path[len-2].getSubElements();
 642                 MenuElement nextChild =
 643                     findEnabledChild(subs, path[len-1], direction);
 644                 if (nextChild == null) {
 645                     nextChild = findEnabledChild(subs, -1, direction);
 646                 }
 647                 if (nextChild != null) {
 648                     path[len-1] = nextChild;
 649                     msm.setSelectedPath(path);
 650                 }
 651             }
 652         }
 653 
 654         private void cancel() {
 655             // 4234793: This action should call JPopupMenu.firePopupMenuCanceled but it's
 656             // a protected method. The real solution could be to make
 657             // firePopupMenuCanceled public and call it directly.
 658             JPopupMenu lastPopup = getLastPopup();
 659             if (lastPopup != null) {
 660                 lastPopup.putClientProperty("JPopupMenu.firePopupMenuCanceled", Boolean.TRUE);
 661             }
 662             String mode = UIManager.getString("Menu.cancelMode");
 663             if ("hideMenuTree".equals(mode)) {
 664                 MenuSelectionManager.defaultManager().clearSelectedPath();
 665             } else {
 666                 shortenSelectedPath();
 667             }
 668         }
 669 
 670         private void shortenSelectedPath() {
 671             MenuElement[] path = MenuSelectionManager.defaultManager().getSelectedPath();
 672             if (path.length <= 2) {
 673                 MenuSelectionManager.defaultManager().clearSelectedPath();
 674                 return;
 675             }
 676             // unselect MenuItem and its Popup by default
 677             int value = 2;
 678             MenuElement lastElement = path[path.length - 1];
 679             JPopupMenu lastPopup = getLastPopup();
 680             if (lastElement == lastPopup) {
 681                 MenuElement previousElement = path[path.length - 2];
 682                 if (previousElement instanceof JMenu) {
 683                     JMenu lastMenu = (JMenu) previousElement;
 684                     if (lastMenu.isEnabled() && lastPopup.getComponentCount() > 0) {
 685                         // unselect the last visible popup only
 686                         value = 1;
 687                     } else {
 688                         // unselect invisible popup and two visible elements
 689                         value = 3;
 690                     }
 691                 }
 692             }
 693             if (path.length - value <= 2
 694                     && !UIManager.getBoolean("Menu.preserveTopLevelSelection")) {
 695                 // clear selection for the topLevelMenu
 696                 value = path.length;
 697             }
 698             MenuElement[] newPath = new MenuElement[path.length - value];
 699             System.arraycopy(path, 0, newPath, 0, path.length - value);
 700             MenuSelectionManager.defaultManager().setSelectedPath(newPath);
 701         }
 702     }
 703 
 704     private static MenuElement nextEnabledChild(MenuElement[] e,
 705                                                 int fromIndex, int toIndex) {
 706         for (int i=fromIndex; i<=toIndex; i++) {
 707             if (e[i] != null) {
 708                 Component comp = e[i].getComponent();
 709                 if ( comp != null
 710                         && (comp.isEnabled() || UIManager.getBoolean("MenuItem.disabledAreNavigable"))
 711                         && comp.isVisible()) {
 712                     return e[i];
 713                 }
 714             }
 715         }
 716         return null;
 717     }
 718 
 719     private static MenuElement previousEnabledChild(MenuElement[] e,
 720                                                 int fromIndex, int toIndex) {
 721         for (int i=fromIndex; i>=toIndex; i--) {
 722             if (e[i] != null) {
 723                 Component comp = e[i].getComponent();
 724                 if ( comp != null
 725                         && (comp.isEnabled() || UIManager.getBoolean("MenuItem.disabledAreNavigable"))
 726                         && comp.isVisible()) {
 727                     return e[i];
 728                 }
 729             }
 730         }
 731         return null;
 732     }
 733 
 734     static MenuElement findEnabledChild(MenuElement[] e, int fromIndex,
 735                                                 boolean forward) {
 736         MenuElement result;
 737         if (forward) {
 738             result = nextEnabledChild(e, fromIndex+1, e.length-1);
 739             if (result == null) result = nextEnabledChild(e, 0, fromIndex-1);
 740         } else {
 741             result = previousEnabledChild(e, fromIndex-1, 0);
 742             if (result == null) result = previousEnabledChild(e, e.length-1,
 743                                                               fromIndex+1);
 744         }
 745         return result;
 746     }
 747 
 748     static MenuElement findEnabledChild(MenuElement[] e,
 749                                    MenuElement elem, boolean forward) {
 750         for (int i=0; i<e.length; i++) {
 751             if (e[i] == elem) {
 752                 return findEnabledChild(e, i, forward);
 753             }
 754         }
 755         return null;
 756     }
 757 
 758     static class MouseGrabber implements ChangeListener,
 759         AWTEventListener, ComponentListener, WindowListener {
 760 
 761         Window grabbedWindow;
 762         MenuElement[] lastPathSelected;
 763 
 764         public MouseGrabber() {
 765             MenuSelectionManager msm = MenuSelectionManager.defaultManager();
 766             msm.addChangeListener(this);
 767             this.lastPathSelected = msm.getSelectedPath();
 768             if(this.lastPathSelected.length != 0) {


< prev index next >