1 /*
   2  * Copyright (c) 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
  23  * questions.
  24  */
  25 package com.sun.javafx.scene.control;
  26 
  27 import com.sun.javafx.scene.control.infrastructure.KeyEventFirer;
  28 import com.sun.javafx.scene.control.infrastructure.MouseEventFirer;
  29 import javafx.collections.ObservableList;
  30 import javafx.scene.Node;
  31 import javafx.scene.control.ContextMenu;
  32 import javafx.scene.control.CustomMenuItem;
  33 import javafx.scene.control.Menu;
  34 import javafx.scene.control.MenuItem;
  35 import javafx.scene.control.skin.ContextMenuSkin;
  36 import javafx.scene.input.KeyCode;
  37 
  38 import java.util.Optional;
  39 
  40 public class ContextMenuContentRetriever {
  41 
  42     private ContextMenuContentRetriever() {
  43         // no-op
  44     }
  45 
  46     public static Menu getOpenSubMenu(ContextMenu menu) {
  47         ContextMenuContent content = getMenuContent(menu);
  48         return content.getOpenSubMenu();
  49     }
  50 
  51     public static Menu getShowingSubMenu(ContextMenu menu) {
  52         ContextMenuContent content = getMenuContent(menu);
  53         Menu showingSubMenu = content.getOpenSubMenu();
  54         ContextMenu subContextMenu = content.getSubMenu();
  55 
  56         while (showingSubMenu != null) {
  57             content = getMenuContent(subContextMenu);
  58 
  59             Menu newShowingMenu = content == null ? null : content.getOpenSubMenu();
  60             subContextMenu = content == null ? null : content.getSubMenu();
  61 
  62             if (newShowingMenu == null) {
  63                 break;
  64             }
  65         }
  66         return showingSubMenu;
  67     }
  68 
  69     public static ObservableList<MenuItem> getShowingMenuItems(ContextMenu menu) {
  70         ContextMenuContent content = getMenuContent(menu);
  71         Menu showingSubMenu = content.getOpenSubMenu();
  72         ContextMenu subContextMenu = content.getSubMenu();
  73 
  74         if (showingSubMenu == null || subContextMenu == null) {
  75             return menu.getItems();
  76         }
  77 
  78         while (showingSubMenu != null) {
  79             content = getMenuContent(subContextMenu);
  80 
  81             Menu newShowingMenu = content == null ? null : content.getOpenSubMenu();
  82             subContextMenu = content == null ? null : content.getSubMenu();
  83 
  84             if (newShowingMenu == null) {
  85                 break;
  86             }
  87         }
  88         return showingSubMenu.getItems();
  89     }
  90 
  91     public static Optional<ContextMenuContent> getShowingMenuContent(ContextMenu menu) {
  92         ContextMenuContent content = getMenuContent(menu);
  93         Menu showingSubMenu = content.getOpenSubMenu();
  94         ContextMenu subContextMenu = content.getSubMenu();
  95         return showingSubMenu != null &&
  96                subContextMenu != null &&
  97                subContextMenu.isShowing() ? getShowingMenuContent(subContextMenu) : Optional.of(content);
  98     }
  99 
 100     private static ContextMenuContent getMenuContent(ContextMenu menu) {
 101         ContextMenuSkin skin = (ContextMenuSkin) menu.getSkin();
 102         Node node = skin.getNode();
 103         if (node instanceof ContextMenuContent) {
 104             return (ContextMenuContent) node;
 105         }
 106         return null;
 107     }
 108 
 109     public static int getCurrentFocusedIndex(ContextMenu menu) {
 110 //        Optional<Integer> index = getShowingMenuContent(menu).flatMap(content -> Optional.of(content.getCurrentFocusIndex()));
 111 //        return index.orElse(-1);
 112 
 113         Optional<ContextMenuContent> showingMenuContent = getShowingMenuContent(menu);
 114         if (showingMenuContent.isPresent()) {
 115             ContextMenuContent content = showingMenuContent.get();
 116             return content.getCurrentFocusIndex();
 117         }
 118 
 119         return -1;
 120     }
 121 
 122     public static MenuItem getCurrentFocusedItem(ContextMenu menu) {
 123         ObservableList<MenuItem> showingMenuItems = getShowingMenuItems(menu);
 124 
 125 //        Optional<MenuItem> item = getShowingMenuContent(menu)
 126 //                .flatMap(content -> Optional.of(content.getCurrentFocusIndex()))
 127 //                .flatMap(index   -> Optional.of(showingMenuItems.get(index)));
 128 //        return item.orElse(null);
 129 
 130         Optional<ContextMenuContent> showingMenuContent = getShowingMenuContent(menu);
 131         if (showingMenuContent.isPresent()) {
 132             ContextMenuContent content = showingMenuContent.get();
 133             int currentFocusIndex = content.getCurrentFocusIndex();
 134             return showingMenuItems.get(currentFocusIndex);
 135         }
 136 
 137         return null;
 138     }
 139 
 140     public static void pressDownKey(ContextMenu menu) {
 141 //        getShowingMenuContent(menu).ifPresent(content -> new KeyEventFirer(content).doDownArrowPress());
 142         Optional<ContextMenuContent> showingMenuContent = getShowingMenuContent(menu);
 143         if (showingMenuContent.isPresent()) {
 144             ContextMenuContent content = showingMenuContent.get();
 145             new KeyEventFirer(content).doDownArrowPress();
 146         }
 147     }
 148 
 149     public static void pressUpKey(ContextMenu menu) {
 150 //        getShowingMenuContent(menu).ifPresent(content -> new KeyEventFirer(content).doUpArrowPress());
 151         Optional<ContextMenuContent> showingMenuContent = getShowingMenuContent(menu);
 152         if (showingMenuContent.isPresent()) {
 153             ContextMenuContent content = showingMenuContent.get();
 154             new KeyEventFirer(content).doUpArrowPress();
 155         }
 156     }
 157 
 158     public static void pressLeftKey(ContextMenu menu) {
 159 //        getShowingMenuContent(menu).ifPresent(content -> new KeyEventFirer(content).doLeftArrowPress());
 160         Optional<ContextMenuContent> showingMenuContent = getShowingMenuContent(menu);
 161         if (showingMenuContent.isPresent()) {
 162             ContextMenuContent content = showingMenuContent.get();
 163             new KeyEventFirer(content).doLeftArrowPress();
 164         }
 165     }
 166 
 167     public static void pressRightKey(ContextMenu menu) {
 168 //        getShowingMenuContent(menu).ifPresent(content -> new KeyEventFirer(content).doRightArrowPress());
 169         Optional<ContextMenuContent> showingMenuContent = getShowingMenuContent(menu);
 170         if (showingMenuContent.isPresent()) {
 171             ContextMenuContent content = showingMenuContent.get();
 172             new KeyEventFirer(content).doRightArrowPress();
 173         }
 174     }
 175 
 176     public static void pressEnterKey(ContextMenu menu) {
 177 //        getShowingMenuContent(menu).ifPresent(content -> new KeyEventFirer(content).doKeyPress(KeyCode.ENTER));
 178         Optional<ContextMenuContent> showingMenuContent = getShowingMenuContent(menu);
 179         if (showingMenuContent.isPresent()) {
 180             ContextMenuContent content = showingMenuContent.get();
 181             new KeyEventFirer(content).doKeyPress(KeyCode.ENTER);
 182         }
 183     }
 184 
 185     public static void pressMouseButton(ContextMenu menu) {
 186         Optional<ContextMenuContent> showingMenuContent = getShowingMenuContent(menu);
 187         if (showingMenuContent.isPresent()) {
 188             ContextMenuContent.MenuItemContainer itemContainer =
 189                     (ContextMenuContent.MenuItemContainer) showingMenuContent.get().selectedBackground;
 190 
 191             MenuItem item = itemContainer.getItem();
 192             if (item instanceof CustomMenuItem) {
 193                 // If the item is a CustomMenuItem, we fire the event on the
 194                 // content of that CustomMenuItem.
 195                 // Also, note that we firea mouse _clicked_ event, as opposed to
 196                 // a press and release. I'm not sure why this is what the
 197                 // ContextMenuContent code expects, but I didn't want to mess with
 198                 // it at this point.
 199                 Node customContent = ((CustomMenuItem)item).getContent();
 200                 new MouseEventFirer(customContent).fireMouseClicked();
 201             } else {
 202                 new MouseEventFirer(itemContainer).fireMousePressAndRelease();
 203             }
 204         }
 205     }
 206 }