/*
* Copyright (C) 2013 University of Dundee & Open Microscopy Environment.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.openmicroscopy.shoola.keywords;
import java.awt.Component;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import javax.swing.AbstractButton;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JTree;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import org.jdesktop.swingx.JXTaskPane;
import abbot.finder.BasicFinder;
import abbot.finder.ComponentNotFoundException;
import abbot.finder.Matcher;
import abbot.finder.MultipleComponentsFoundException;
import org.robotframework.swing.tree.TreeOperator;
import org.robotframework.swing.tree.TreeSupport;
import com.google.common.collect.ImmutableSet;
/**
* Robot Framework SwingLibrary keyword library offering methods for checking icons.
* @author m.t.b.carroll@dundee.ac.uk
* @since 4.4.9
*/
public class IconCheckLibrary
{
/** Allow Robot Framework to instantiate this library only once. */
public static final String ROBOT_LIBRARY_SCOPE = "GLOBAL";
/* classes with a getIcon() */
private static final Collection<Class<? extends JComponent>> ICON_BEARER_CLASSES =
ImmutableSet.of(AbstractButton.class, JLabel.class, JXTaskPane.class);
/* tree operator factory */
private static final TreeSupport TREE_SUPPORT = new TreeSupport();
/**
* Get the icon name from the given image icon.
* @param icon the image icon
* @return the name of the icon
*/
private static String getIconName(ImageIcon icon) {
final String iconName = ((ImageIcon) icon).getDescription();
final int lastSlash = iconName.lastIndexOf('/');
return lastSlash < 0 ? iconName : iconName.substring(lastSlash + 1);
}
/**
* Get the icon name from the component's icon property's <code>ImageIcon</code> instance value.
* @param iconBearer the component that has an icon
* @return the name of the icon
* @throws NoSuchMethodException if a <code>getIcon()</code> method is not available for calling
* @throws InvocationTargetException if the <code>getIcon()</code> method threw an exception
* @throws IllegalAccessException if a <code>getIcon()</code> method is not available for calling
* @throws SecurityException if a <code>getIcon()</code> method is not available for calling
* @throws IllegalArgumentException if a <code>getIcon()</code> method is not available for calling
*/
private static String getIconName(Component iconBearer)
throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
{
final Object icon = iconBearer.getClass().getMethod("getIcon").invoke(iconBearer);
if (!(icon instanceof ImageIcon)) {
throw new RuntimeException("not an ImageIcon");
}
return getIconName((ImageIcon) icon);
}
/**
* Get the icon name from the component's icon property's <code>ImageIcon</code> instance value.
* @param component iconBearer the component that has an icon
* @return the name of the icon, or <code>null</code> if it cannot be determined
*/
static String getIconNameMaybe(Component component) {
final Class<? extends Component> componentClass = component.getClass();
for (final Class<? extends JComponent> iconBearerClass : ICON_BEARER_CLASSES) {
if (iconBearerClass.isAssignableFrom(componentClass)) {
try {
return getIconName(component);
} catch (Exception e) { }
}
}
return null;
}
/**
* <table>
* <td>Get Image Icon Name</td>
* <td>name of icon-bearing component</td>
* </table>
* @param containerName the name of the component whose <code>ImageIcon</code>'s filename is required
* @return the filename of the <code>ImageIcon</code>
* @throws MultipleComponentsFoundException if multiple suitable components have the given name
* @throws ComponentNotFoundException if no suitable components have the given name
* @throws NoSuchMethodException if a <code>getIcon()</code> method is not available for calling
* @throws InvocationTargetException if the <code>getIcon()</code> method threw an exception
* @throws IllegalAccessException if a <code>getIcon()</code> method is not available for calling
* @throws SecurityException if a <code>getIcon()</code> method is not available for calling
* @throws IllegalArgumentException if a <code>getIcon()</code> method is not available for calling
*/
public String getImageIconName(final String containerName)
throws ComponentNotFoundException, MultipleComponentsFoundException,
IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
final JComponent iconBearer = (JComponent) new BasicFinder().find(new Matcher() {
public boolean matches(Component component) {
if (!containerName.equals(component.getName())) {
return false;
}
final Class<? extends Component> componentClass = component.getClass();
for (final Class<? extends JComponent> iconBearerClass : ICON_BEARER_CLASSES) {
if (iconBearerClass.isAssignableFrom(componentClass)) {
return true;
}
}
return false;
}});
return getIconName(iconBearer);
}
/**
* <table>
* <td>Get Tree Node Image Icon Name</td>
* <td>path to icon-bearing tree node</td>
* <td>name of tree</td>
* </table>
* @param treeName the name of the tree whose node's <code>ImageIcon</code>'s filename is required
* @return the filename of the <code>ImageIcon</code>
* @throws MultipleComponentsFoundException if multiple suitable components have the given name
* @throws ComponentNotFoundException if no suitable components have the given name
* @throws NoSuchMethodException if a <code>getIcon()</code> method is not available for calling
* @throws InvocationTargetException if the <code>getIcon()</code> method threw an exception
* @throws IllegalAccessException if a <code>getIcon()</code> method is not available for calling
* @throws SecurityException if a <code>getIcon()</code> method is not available for calling
* @throws IllegalArgumentException if a <code>getIcon()</code> method is not available for calling
*/
public String getTreeNodeImageIconName(final String nodePath, final String treeName)
throws ComponentNotFoundException, MultipleComponentsFoundException,
IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
final JTree tree = (JTree) new BasicFinder().find(new Matcher() {
public boolean matches(Component component) {
return component instanceof JTree && treeName.equals(component.getName());
}});
final TreeOperator treeOperator = TREE_SUPPORT.treeOperator(treeName);
final TreePath path = treeOperator.findPath(nodePath);
final TreeCellRenderer renderer = treeOperator.getTreeOperator().getCellRenderer();
return getIconName(renderer.getTreeCellRendererComponent(tree, path.getLastPathComponent(),
false, false, false, tree.getRowForPath(path), false));
}
/**
* <table>
* <td>Get Insight Image Icon Name</td>
* <td>name of the Insight agent</td>
* <td>name of the icon index</td>
* </table>
* @param agent the agent as named by the Java package
* @param constantName the icon index in that agent's <code>IconManager</code>
* @return the filename of the <code>ImageIcon</code>
* @throws ClassNotFoundException if the given agent does not have an <code>IconManager</code>
* @throws IllegalArgumentException if the <code>IconManager</code> code is not as expected
* @throws SecurityException if the <code>IconManager</code> code is not as expected
* @throws IllegalAccessException if the <code>IconManager</code> code is not as expected
* @throws InvocationTargetException if the <code>IconManager</code> code is not as expected
* @throws NoSuchMethodException if the <code>IconManager</code> code is not as expected
* @throws NoSuchFieldException if the given icon index is not available from the <code>IconManager</code>
*/
public String getInsightImageIconName(String agent, String constantName)
throws ClassNotFoundException, IllegalArgumentException, SecurityException, IllegalAccessException,
InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
Class<?> iconManagerClass = Class.forName(StaticFieldLibrary.PREFIX + "agents." + agent + ".IconManager");
final int iconIndex = (Integer) iconManagerClass.getField(constantName).get(null);
final Object iconManager = iconManagerClass.getMethod("getInstance").invoke(null);
Method getImageIconMethod = null;
do {
try {
getImageIconMethod = iconManagerClass.getMethod("getImageIcon", int.class);
} catch (NoSuchMethodException e) {
iconManagerClass = iconManagerClass.getSuperclass();
}
} while (getImageIconMethod == null && iconManagerClass != null);
return getIconName((ImageIcon) getImageIconMethod.invoke(iconManager, iconIndex));
}
}