/*******************************************************************************
* Copyright (c) 2012 BREDEX GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BREDEX GmbH - initial API and implementation
*******************************************************************************/
package org.eclipse.jubula.rc.swing.tester;
import java.awt.Component;
import java.awt.Container;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPopupMenu;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import org.eclipse.jubula.rc.common.driver.IRunnable;
import org.eclipse.jubula.rc.common.tester.AbstractMenuTester;
import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IComponent;
import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IMenuComponent;
import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IMenuItemComponent;
import org.eclipse.jubula.rc.swing.tester.adapter.JMenuItemAdapter;
import org.eclipse.jubula.rc.swing.tester.util.WindowHelper;
import org.eclipse.jubula.tools.internal.utils.EnvironmentUtils;
/**
* Toolkit specific commands for the <code>JMenuBar</code>.
*
* @author BREDEX GmbH
*/
public class JMenuBarTester extends AbstractMenuTester {
/**
* {@inheritDoc}
*/
public String[] getTextArrayFromComponent() {
return null;
}
/**
* Workaround to get the menu bar existing somewhere in the given
* container's hierarchy. This method should <b>only</b> be used if
* {@link JFrame#getJMenuBar()} / {@link JDialog#getJMenuBar()} return
* <code>null</code>, which is a very rare case.
*
* This method also performs some unorthodox visibility testing in order
* to avoid retrieving the wrong menu.
*
* @param rootPane The root container from which to start the search for
* the menu bar.
* @return the first menu bar found in the hierarchy that: <ul>
* <li>is showing</li>
* <li>contains at least one visible menu</li>
*/
private JMenuBar getMenuBarWorkaround(Container rootPane) {
JMenuBar menuBar = null;
List menuList = new ArrayList();
collectMenuBarsWorkaround(rootPane, menuList);
Iterator menuIter = menuList.iterator();
while (menuIter.hasNext() && menuBar == null) {
JMenuBar menu = (JMenuBar)menuIter.next();
boolean hasAtLeastOneItem = false;
MenuElement [] subElements = menu.getSubElements();
for (int i = 0;
i < subElements.length && !hasAtLeastOneItem;
i++) {
if (subElements[i] instanceof JMenu) {
JMenu subMenu = (JMenu)subElements[i];
hasAtLeastOneItem =
subMenu != null && subMenu.isShowing();
}
}
if (hasAtLeastOneItem) {
menuBar = menu;
}
}
return menuBar;
}
/**
* Adds all menu bars found in the hierarchy <code>container</code> to
* <code>menuBarList</code>. This is part of a workaround for finding menus
* in AUTs that don't make proper use of
* {@link JFrame#setJMenuBar()} / {@link JDialog#setJMenuBar()}.
*
* @see #getMenuBarWorkaround(Container)
*
* @param container The root container from which to start the search for
* the menu bars.
* @param menuBarList The list to which each menu bar found will be added.
* Only objects of type {@link JMenuBar} will be added
* to this list.
*/
private void collectMenuBarsWorkaround(
Container container, List menuBarList) {
Component [] children = container.getComponents();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof JMenuBar
&& children[i].isShowing()) {
menuBarList.add(children[i]);
}
}
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Container
&& children[i].isVisible()) {
collectMenuBarsWorkaround((Container)children[i], menuBarList);
}
}
}
/**
* @return the component
*/
public IComponent getComponent() {
IComponent component = super.getComponent();
if (component != null && component.getRealComponent()
instanceof JPopupMenu) {
return component;
}
Window activeWindow = WindowHelper.getActiveWindow();
if (activeWindow == null) {
getLog().warn("JMenuBarImplClass.getComponent(): No active window."); //$NON-NLS-1$
} else {
JMenuBar menuBar = null;
Container rootPane = null;
if (activeWindow instanceof JDialog) {
JDialog dialog = (JDialog)activeWindow;
menuBar = dialog.getJMenuBar();
rootPane = dialog.getRootPane();
} else if (activeWindow instanceof JFrame) {
JFrame frame = (JFrame)activeWindow;
menuBar = frame.getJMenuBar();
rootPane = frame.getRootPane();
}
if (menuBar == null) {
menuBar = getMenuBarWorkaround(rootPane);
}
setComponent(menuBar);
}
return super.getComponent();
}
/**
*{@inheritDoc}
*/
protected void closeMenu(IMenuComponent menuBar, String[] textPath,
String operator) {
if (closMacMenus()) {
return;
}
if (menuBar.getRealComponent() instanceof JPopupMenu) {
for (int i = 0; i < textPath.length; i++) {
if (((JPopupMenu)menuBar.getRealComponent()).isVisible()) {
getRobot().keyType(menuBar.getRealComponent(),
KeyEvent.VK_ESCAPE);
}
}
return;
}
super.closeMenu(menuBar, textPath, operator);
}
/**
* This methods closes the opened context menu via the {@link MenuSelectionManager}
* @return returns <code>true</code> if it is mac and has closed the menu
*/
private boolean closMacMenus() {
if (EnvironmentUtils.isMacOS()) {
final MenuSelectionManager manager = MenuSelectionManager
.defaultManager();
if (manager != null) {
getEventThreadQueuer().invokeAndWait("closeMac Menus", //$NON-NLS-1$
new IRunnable<Object>() {
public Rectangle run() {
manager.clearSelectedPath();
return null;
}
});
return true;
}
}
return false;
}
/**
*{@inheritDoc}
*/
protected void closeMenu(IMenuComponent menuBar, int[] path) {
if (closMacMenus()) {
return;
}
if (menuBar.getRealComponent() instanceof JPopupMenu) {
for (int i = 0; i < path.length; i++) {
if (((JPopupMenu)menuBar.getRealComponent()).isVisible()) {
getRobot().keyType(menuBar.getRealComponent(),
KeyEvent.VK_ESCAPE);
}
}
return;
}
super.closeMenu(menuBar, path);
}
/**
* {@inheritDoc}
*/
protected IMenuItemComponent newMenuItemAdapter(Object component) {
return new JMenuItemAdapter(component);
}
}