/* * Created on Jan 30, 2008 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. * * Copyright @2008-2013 the original author or authors. */ package org.fest.swing.driver; import static java.lang.Boolean.getBoolean; import static org.fest.swing.core.WindowAncestorFinder.windowAncestorOf; import static org.fest.swing.driver.ComponentPreconditions.checkEnabledAndShowing; import static org.fest.swing.driver.JMenuPopupMenuQuery.popupMenuOf; import static org.fest.swing.driver.WindowMoveToFrontTask.toFront; import static org.fest.swing.edt.GuiActionRunner.execute; import static org.fest.swing.exception.ActionFailedException.actionFailure; import static org.fest.swing.format.Formatting.format; import static org.fest.swing.timing.Pause.pause; import static org.fest.swing.util.Platform.isOSX; import static org.fest.util.Preconditions.checkNotNull; import static org.fest.util.Strings.concat; import java.awt.Component; import java.awt.Window; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import org.fest.swing.annotation.RunsInEDT; import org.fest.swing.core.Robot; import org.fest.swing.edt.GuiQuery; import org.fest.swing.edt.GuiTask; import org.fest.swing.exception.ActionFailedException; import org.fest.util.InternalApi; /** * <p> * Supports functional testing of {@code JMenuItem}s. * </p> * * <p> * <b>Note:</b> This class is intended for internal use only. Please use the classes in the package * {@link org.fest.swing.fixture} in your tests. * </p> * * @author Alex Ruiz * @author Yvonne Wang */ @InternalApi public class JMenuItemDriver extends JComponentDriver { /** * Creates a new {@link JMenuItemDriver}. * * @param robot the robot to use to simulate user input. */ public JMenuItemDriver(@Nonnull Robot robot) { super(robot); } /** * Finds and selects the given {@code JMenuItem}. * * @param menuItem the {@code JMenuItem} to select. * @throws IllegalStateException if the menu to select is disabled. * @throws IllegalStateException if the menu to select is not showing on the screen. * @throws ActionFailedException if the menu has a pop-up and it fails to show up. */ @RunsInEDT public void click(@Nonnull JMenuItem menuItem) { show(menuItem); doClick(menuItem); ensurePopupIsShowing(menuItem); } @RunsInEDT private void show(@Nonnull JMenuItem menuItem) { JMenuItemLocation location = locationOf(menuItem); activateParentIfIsMenu(location); moveParentWindowToFront(location); if (menuItem instanceof JMenu && !location.inMenuBar()) { waitForSubMenuToShow(); } } @RunsInEDT private static @Nonnull JMenuItemLocation locationOf(final @Nonnull JMenuItem menuItem) { JMenuItemLocation result = execute(new GuiQuery<JMenuItemLocation>() { @Override protected JMenuItemLocation executeInEDT() { return new JMenuItemLocation(menuItem); } }); return checkNotNull(result); } @RunsInEDT private void activateParentIfIsMenu(@Nonnull JMenuItemLocation location) { if (!location.isParentAMenu()) { return; } Component c = location.parentOrInvoker(); if (c instanceof JMenuItem) { click((JMenuItem) c); } } @RunsInEDT private void moveParentWindowToFront(@Nonnull JMenuItemLocation location) { if (!location.inMenuBar()) { return; } // TODO windowAncestorOf is not being called in EDT moveToFront(windowAncestorOf(location.parentOrInvoker())); } @RunsInEDT private void doClick(@Nonnull JMenuItem menuItem) { if (isMacOSMenuBar()) { validateAndDoClick(menuItem); return; } super.click(menuItem); robot.waitForIdle(); } private boolean isMacOSMenuBar() { return isOSX() && (getBoolean("apple.laf.useScreenMenuBar") || getBoolean("com.apple.macos.useScreenMenuBar")); } @RunsInEDT private static void validateAndDoClick(final @Nonnull JMenuItem menuItem) { execute(new GuiTask() { @Override protected void executeInEDT() { checkEnabledAndShowing(menuItem); menuItem.doClick(); } }); } @RunsInEDT private void ensurePopupIsShowing(@Nonnull JMenuItem menuItem) { if (!(menuItem instanceof JMenu)) { return; } JPopupMenu popup = popupMenuOf((JMenu) menuItem); // TODO review EDT access if (!waitForShowing(popup, robot.settings().timeoutToFindPopup())) { throw actionFailure(concat("Clicking on menu item <", format(menuItem), "> never showed a pop-up menu")); } waitForSubMenuToShow(); } private void waitForSubMenuToShow() { pause(robot.settings().timeoutToFindSubMenu()); } @RunsInEDT private void moveToFront(@Nullable Window w) { if (w == null) { return; } // Make sure the window is in front, or its menus may be obscured by another window. toFront(w); robot.waitForIdle(); robot.moveMouse(w); } }