package de.sick.guicheck.fx;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import javafx.application.Platform;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import de.sick.guicheck.GcAssertException;
import de.sick.guicheck.GcException;
import de.sick.guicheck.GcUtils;
/**
* @author briemla
*/
public class GcContextMenuFX
{
private final ContextMenu m_contextMenu;
public GcContextMenuFX(ContextMenu contextMenu)
{
super();
m_contextMenu = contextMenu;
}
private ArrayList<MenuItem> getMenuPath(String menuPath)
{
return GcUtilsFX.getMenuPath(m_contextMenu.getItems(), menuPath);
}
/**
* Check whether the given menu path exists.
*
* @param menuPath Path of menus and a menu item separated by / chars.
* @throws GcAssertException Thrown if the path does not exist.
*/
public GcContextMenuFX menuPathExists(final String menuPath)
{
GcUtilsFX.menuPathExists(m_contextMenu.getItems(), menuPath);
return this;
}
/**
* Fire the given menu item.
*
* @param menuPath Path of menus and the menu item separated by / chars.
* @throws GcAssertException Thrown if the path does not exist.
*/
public GcContextMenuFX fireMenuItem(final String menuPath)
{
return GcUtilsFX.eval(new GcUtils.IEvaluator<GcContextMenuFX>()
{
@Override
public GcContextMenuFX eval()
{
// Open the menu path ...
final ArrayList<MenuItem> l_path = getMenuPath(menuPath);
for (MenuItem i : l_path)
{
if (i instanceof Menu)
{
final Menu l_menu = (Menu)i;
GcUtilsFX.runLaterAndWait(new Runnable()
{
@Override
public void run()
{
l_menu.show();
}
});
}
if (i.isDisable())
{
throw new GcAssertException("Menu item is disabled: " + i.getId());
}
}
// ... and close the menu path again
//
// If we do not close it again, the next click on the GUI just closes the menu and
// has no other effect
hideContextMenu();
// ... fire the menu item in the FX application thread ...
Platform.runLater(new Runnable()
{
@Override
public void run()
{
l_path.get(l_path.size() - 1).fire();
}
});
return GcContextMenuFX.this;
}
});
}
private void hideContextMenu()
{
GcUtilsFX.runLaterAndWait(new Runnable()
{
@Override
public void run()
{
m_contextMenu.hide();
}
});
}
/**
* Check a property of the given menu entry which can be a menu or a menu item.
*
* @param menuPath Path to the menu entry separated by / chars.
* @throws GcAssertException Thrown if the path does not exist or the property does not have the given value.
*/
public GcContextMenuFX menuPathPropertyIs(final String menuPath, String property, boolean value)
{
ArrayList<MenuItem> l_path = GcUtilsFX.eval(new GcUtils.IEvaluator<ArrayList<MenuItem>>()
{
@Override
public ArrayList<MenuItem> eval()
{
return getMenuPath(menuPath);
}
});
// only last item in path need to be checked
MenuItem l_menuItem = l_path.get(l_path.size() - 1);
propertyIs(l_menuItem, property, value, true);
hideContextMenu();
return this;
}
/**
* Duplicate method
*
* @see GcComponentFX#propertyIs(Object, String, Object, boolean)
*/
@SuppressWarnings("unchecked")
final <TT> GcContextMenuFX propertyIs(final Object obj, final String property, final TT value, final boolean expectedResult)
{
try
{
// Get the property getter method ...
final Class<?> l_clazz = value == null ? null : value.getClass();
final Method l_method = obj.getClass().getMethod(GcComponentFX.getPropertyGetter(property, l_clazz), (Class<?>[])null);
GcUtilsFX.eval(new GcUtils.IEvaluator<Void>()
{
@Override
public Void eval()
{
TT l_value;
try
{
// ... get the value of the property ...
l_value = (TT)l_method.invoke(obj, (Object[])null);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{
throw new GcException("Failed to access property " + property, e);
}
// ... and check it against the expected value
if ((value == l_value || (value != null && value.equals(l_value))) != expectedResult)
{
final StringBuilder l_sb = new StringBuilder("Unexpected value of ");
l_sb.append(property).append(": ").append(expectedResult ? "Expected: " : "Not expected: ").append(value).append(", Actual: ").append(l_value);
throw new GcAssertException(l_sb.toString());
}
return null;
}
});
// Return this instance again according to the fluent API style
return this;
}
catch (NoSuchMethodException e)
{
throw new GcException("Failed to access property " + property, e);
}
}
}