package com.limegroup.gnutella.gui.search; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.awt.Component; import java.awt.Graphics; import java.awt.Toolkit; import java.util.MissingResourceException; import javax.swing.JButton; import javax.swing.JInternalFrame; import javax.swing.ImageIcon; import javax.swing.Icon; import com.limegroup.gnutella.util.CommonUtils; import com.limegroup.gnutella.gui.GUIMediator; import com.limegroup.gnutella.gui.ImageManipulator; import com.limegroup.gnutella.gui.themes.ThemeSettings; /** * This class acts as a wrapper around the "kill" icon displayed in the * search tabs. */ //2345678|012345678|012345678|012345678|012345678|012345678|012345678|012345678| final class CancelSearchIconProxy implements Icon { private static final int PLAIN = 0; private static final int SELECTED = 1; private static final int ARMED = 2; private static Icon PLAIN_ICON; private static Icon SELECTED_ICON; private static Icon ARMED_ICON; /** * The <tt>ImageIcon</tt> for our cancel image. */ private Icon _cancelIcon; /** * The width of the icon in pixels. */ private int _width; /** * The height of the icon in pixels. */ private int _height; /** * The x position of the icon within its tab. */ private int _x; /** * The y position of the icon within its tab. */ private int _y; /** * The style of this icon. */ private final int style; static CancelSearchIconProxy createPlain() { return new CancelSearchIconProxy(PLAIN); } static CancelSearchIconProxy createSelected() { return new CancelSearchIconProxy(SELECTED); } static CancelSearchIconProxy createArmed() { return new CancelSearchIconProxy(ARMED); } /** * the constructor loads the image icon and stores the location * and dimensions. */ CancelSearchIconProxy(int style) { this.style = style; setIcon(); } /** * Sets the appropriate icon. */ private void setIcon() { switch(style) { case ARMED: _cancelIcon = ARMED_ICON; break; case SELECTED: _cancelIcon = SELECTED_ICON; break; case PLAIN: _cancelIcon = PLAIN_ICON; break; } _width = _cancelIcon.getIconWidth(); _height = _cancelIcon.getIconHeight(); _x = 0; _y = 0; } // resets the cached icons for each kind of icon static void updateTheme() { if(ThemeSettings.isWindowsTheme() && WindowsXPIcon.isAvailable()) { try { PLAIN_ICON = new WindowsXPIcon(PLAIN); SELECTED_ICON = new WindowsXPIcon(SELECTED); ARMED_ICON = new WindowsXPIcon(ARMED); return; } catch(IllegalArgumentException iae) { // couldn't create image to resize } catch(NullPointerException npe) { // internal windows plaf error } // if construction failed, fall through... } PLAIN_ICON = GUIMediator.getThemeImage("kill"); try { SELECTED_ICON = GUIMediator.getThemeImage("kill_on"); } catch(MissingResourceException mre) { SELECTED_ICON = PLAIN_ICON; } ARMED_ICON = SELECTED_ICON; } /** * implements Icon interface. * Gets the width of the icon. * * @return the width in pixels of this icon */ public int getIconWidth() { return _width; } /** * implements Icon interface. * Gets the height of the icon. * * @return the height in pixels of this icon */ public int getIconHeight() { return _height; } /** * implements Icon interface. * forwards the call to the proxied Icon object and stores the * x and y coordinates of the icon. */ public void paintIcon(Component c, Graphics g, int x, int y) { _x = x; _y = y; _cancelIcon.paintIcon(c, g, x, y); } /** * Determines whether or not a click at the given x, y position * is a "hit" on the kill search icon. * * @param x the x location of the mouse event * * @param y the y location of the mouse event * * @return <tt>true</tt> if the mouse event occurred within the * bounding rectangle of the icon, <tt>false</tt> otherwise. */ boolean shouldKill(int x, int y) { int xMax = _x + _width; int yMax = _y + _height; if(!((x >= _x) && (x <= xMax))) return false; if(!((y >= _y) && (y <= yMax))) return false; return true; } /** * A delegate for the windows xp icon. * * This is necessary because the windows icon requires it be drawn * from a JButton, and its InternalFrame designates if it's drawn * as armed/disarmed/selected. It's also always drawn from 0,0 * so the graphics object needs to be translated. */ private static class WindowsXPIcon implements Icon { // cached windows icon, and a marker null value so we don't // needlessy try to recreate it each time. private static Icon _windowsCloseIcon; private static final Icon NULL = new ImageIcon(); /** * Determines if the Windows icon is available and caches it. */ static boolean isAvailable() { if(!CommonUtils.isJava142OrLater() || !CommonUtils.isWindowsXP() || !Boolean.TRUE.equals( Toolkit.getDefaultToolkit().getDesktopProperty( "win.xpstyle.themeActive")) || System.getProperty("swing.noxp") != null) return false; if(_windowsCloseIcon == NULL) return false; if(_windowsCloseIcon != null) return true; try { Class c = Class.forName("com.sun.java.swing.plaf.windows.WindowsIconFactory"); Method m = c.getDeclaredMethod("createFrameCloseIcon", new Class[0]); _windowsCloseIcon = (Icon)m.invoke(c, new Object[0]); if(_windowsCloseIcon.getIconHeight() == 0 || _windowsCloseIcon.getIconWidth() == 0) { _windowsCloseIcon = NULL; return false; } else { return true; } } catch(ClassNotFoundException cfnfe) { } catch(IllegalAccessException iae) { } catch(ExceptionInInitializerError eiie) { } catch(SecurityException se) { } catch(ClassCastException cce) { } catch(NoSuchMethodException nsme) { } catch(InvocationTargetException ite) { } _windowsCloseIcon = NULL; return false; } /** * The button to use when drawing the icon. */ private Component component; /** * The resized version of the icon. */ private Icon _resizedIcon; /** * Constructs a new icon with the given button. */ WindowsXPIcon(final int style) { JButton button = new JButton(); button.getModel().setArmed(false); button.getModel().setPressed(false); button.getModel().setRollover(style == ARMED); button.getModel().setEnabled(true); JInternalFrame frame = new JInternalFrame() { public boolean isSelected() { return style != PLAIN; } }; frame.getContentPane().add(button); component = button; // set the correct size. Icon icon = ImageManipulator.resize(this, 14, 14); _resizedIcon = icon; // component not needed any more. component = null; } // icon methods. public int getIconHeight() { if(_resizedIcon != null) return _resizedIcon.getIconHeight(); else return _windowsCloseIcon.getIconHeight(); } public int getIconWidth() { if(_resizedIcon != null) return _resizedIcon.getIconWidth(); else return _windowsCloseIcon.getIconWidth(); } /** * Translates the graphics component prior to drawing, since the * icon always draws at 0,0. */ public void paintIcon(Component c, Graphics g, int x, int y) { if(_resizedIcon != null) { _resizedIcon.paintIcon(c, g, x, y); } else { g.translate(x, y); _windowsCloseIcon.paintIcon(component, g, 0, 0); g.translate(-x, -y); } } } }