/*
* This file is part of FTB Launcher.
*
* Copyright © 2012-2014, FTB Launcher Contributors <https://github.com/Slowpoke101/FTBLaunch/>
* FTB Launcher is 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.
*/
package net.ftb.gui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.IllegalComponentStateException;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.Locale;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleIcon;
import javax.accessibility.AccessibleRole;
import javax.accessibility.AccessibleState;
import javax.accessibility.AccessibleStateSet;
import javax.swing.Icon;
public class ImageAndTextIcon implements Icon {
/*
* Keep references to the filename and location so that alternate
* persistence schemes have the option to archive images symbolically rather
* than including the image data in the archive.
*/
transient Image image;
transient int loadStatus = 0;
ImageObserver imageObserver;
String description = null;
protected final static Component component = new Component() {
};
protected final static MediaTracker tracker = new MediaTracker(component);
/**
* Id used in loading images from MediaTracker.
*/
private static int mediaTrackerID;
int width = -1;
int height = -1;
/**
* Creates an ImageIcon from the specified file. The image will be preloaded
* by using MediaTracker to monitor the loading state of the image.
*
* @param filename
* the name of the file containing the image
* @param desc
* a brief textual description of the image
* @see #ImageIcon(String)
*/
public ImageAndTextIcon (URL filename, String desc) {
image = Toolkit.getDefaultToolkit().getImage(filename);
if (image == null) {
return;
}
this.description = desc;
loadImage(image);
}
/**
* Loads the image, returning only when the image is loaded.
*
* @param image
* the image
*/
protected void loadImage (Image image) {
synchronized (tracker) {
int id = getNextID();
tracker.addImage(image, id);
try {
tracker.waitForID(id, 0);
} catch (InterruptedException e) {
System.out.println("INTERRUPTED while loading Image");
}
loadStatus = tracker.statusID(id, false);
tracker.removeImage(image, id);
width = image.getWidth(imageObserver);
height = image.getHeight(imageObserver);
}
}
/**
* Returns an ID to use with the MediaTracker in loading an image.
*/
private int getNextID () {
synchronized (tracker) {
return ++mediaTrackerID;
}
}
/**
* Returns the status of the image loading operation.
*
* @return the loading status as defined by java.awt.MediaTracker
* @see java.awt.MediaTracker#ABORTED
* @see java.awt.MediaTracker#ERRORED
* @see java.awt.MediaTracker#COMPLETE
*/
public int getImageLoadStatus () {
return loadStatus;
}
/**
* Returns this icon's <code>Image</code>.
*
* @return the <code>Image</code> object for this <code>ImageIcon</code>
*/
public Image getImage () {
return image;
}
/**
* Sets the image displayed by this icon.
*
* @param image
* the image
*/
public void setImage (Image image) {
this.image = image;
loadImage(image);
}
/**
* Gets the description of the image. This is meant to be a brief textual
* description of the object. For example, it might be presented to a blind
* user to give an indication of the purpose of the image. The description
* may be null.
*
* @return a brief textual description of the image
*/
public String getDescription () {
return description;
}
/**
* Sets the description of the image. This is meant to be a brief textual
* description of the object. For example, it might be presented to a blind
* user to give an indication of the purpose of the image.
*
* @param description
* a brief textual description of the image
*/
public void setDescription (String description) {
this.description = description;
}
/**
* Paints the icon. The top-left corner of the icon is drawn at the point (
* <code>x</code>, <code>y</code>) in the coordinate space of the graphics
* context <code>g</code>. If this icon has no image observer, this method
* uses the <code>c</code> component as the observer.
*
* @param c
* the component to be used as the observer if this icon has no
* image observer
* @param g
* the graphics context
* @param x
* the X coordinate of the icon's top-left corner
* @param y
* the Y coordinate of the icon's top-left corner
*/
public synchronized void paintIcon (Component c, Graphics g, int x, int y) {
if (description.length() == 1) {
g.drawImage(image, x, y, c);
g.setColor(Color.WHITE);
g.setFont(new Font("SansSerif", Font.BOLD, 12));
g.drawString(description, x + image.getWidth(imageObserver) - 15, y + 15);
} else {
g.drawImage(image, x, y, c);
g.setColor(Color.WHITE);
g.setFont(new Font("SansSerif", Font.BOLD, 12));
g.drawString(description, x + image.getWidth(imageObserver) - 25, y + 15);
}
}
/**
* Gets the width of the icon.
*
* @return the width in pixels of this icon
*/
public int getIconWidth () {
return width;
}
/**
* Gets the height of the icon.
*
* @return the height in pixels of this icon
*/
public int getIconHeight () {
return height;
}
/**
* Sets the image observer for the image. Set this property if the ImageIcon
* contains an animated GIF, so the observer is notified to update its
* display. For example:
*
* <pre>
* icon = new ImageIcon(...)
* button.setIcon(icon);
* icon.setImageObserver(button);
* </pre>
*
* @param observer
* the image observer
*/
public void setImageObserver (ImageObserver observer) {
imageObserver = observer;
}
/**
* Returns the image observer for the image.
*
* @return the image observer, which may be null
*/
public ImageObserver getImageObserver () {
return imageObserver;
}
/**
* Returns a string representation of this image.
*
* @return a string representing this image
*/
public String toString () {
if (description != null) {
return description;
}
return super.toString();
}
private void readObject (ObjectInputStream s) throws ClassNotFoundException, IOException {
s.defaultReadObject();
int w = s.readInt();
int h = s.readInt();
int[] pixels = (int[]) (s.readObject());
if (pixels != null) {
Toolkit tk = Toolkit.getDefaultToolkit();
ColorModel cm = ColorModel.getRGBdefault();
image = tk.createImage(new MemoryImageSource(w, h, cm, pixels, 0, w));
loadImage(image);
}
}
private void writeObject (ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
int w = getIconWidth();
int h = getIconHeight();
int[] pixels = image != null ? new int[w * h] : null;
if (image != null) {
try {
PixelGrabber pg = new PixelGrabber(image, 0, 0, w, h, pixels, 0, w);
pg.grabPixels();
if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
throw new IOException("failed to load image contents");
}
} catch (InterruptedException e) {
throw new IOException("image load interrupted");
}
}
s.writeInt(w);
s.writeInt(h);
s.writeObject(pixels);
}
/**
* --- Accessibility Support ---
*/
private AccessibleImageIcon accessibleContext = null;
/**
* Gets the AccessibleContext associated with this ImageIcon. For image
* icons, the AccessibleContext takes the form of an AccessibleImageIcon. A
* new AccessibleImageIcon instance is created if necessary.
*
* @return an AccessibleImageIcon that serves as the AccessibleContext of
* this ImageIcon
* @beaninfo expert: true description: The AccessibleContext associated with
* this ImageIcon.
* @since 1.3
*/
public AccessibleContext getAccessibleContext () {
if (accessibleContext == null) {
accessibleContext = new AccessibleImageIcon();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>ImageIcon</code> class. It provides an implementation of the Java
* Accessibility API appropriate to image icon user-interface elements.
* <p>
* <strong>Warning:</strong> Serialized objects of this class will not be
* compatible with future Swing releases. The current serialization support
* is appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage of
* all JavaBeans<sup><font size="-2">TM</font></sup> has been added to the
* <code>java.beans</code> package. Please see {@link java.beans.XMLEncoder}.
*
* @since 1.3
*/
protected class AccessibleImageIcon extends AccessibleContext implements AccessibleIcon, Serializable {
/*
* AccessibleContest implementation -----------------
*/
/**
* Gets the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole () {
return AccessibleRole.ICON;
}
/**
* Gets the state of this object.
*
* @return an instance of AccessibleStateSet containing the current
* state set of the object
* @see AccessibleState
*/
public AccessibleStateSet getAccessibleStateSet () {
return null;
}
/**
* Gets the Accessible parent of this object. If the parent of this
* object implements Accessible, this method should simply return
* getParent().
*
* @return the Accessible parent of this object -- can be null if this
* object does not have an Accessible parent
*/
public Accessible getAccessibleParent () {
return null;
}
/**
* Gets the index of this object in its accessible parent.
*
* @return the index of this object in its parent; -1 if this object
* does not have an accessible parent.
* @see #getAccessibleParent
*/
public int getAccessibleIndexInParent () {
return -1;
}
/**
* Returns the number of accessible children in the object. If all of
* the children of this object implement Accessible, than this method
* should return the number of children of this object.
*
* @return the number of accessible children in the object.
*/
public int getAccessibleChildrenCount () {
return 0;
}
/**
* Returns the nth Accessible child of the object.
*
* @param i
* zero-based index of child
* @return the nth Accessible child of the object
*/
public Accessible getAccessibleChild (int i) {
return null;
}
/**
* Returns the locale of this object.
*
* @return the locale of this object
*/
public Locale getLocale () throws IllegalComponentStateException {
return null;
}
/*
* AccessibleIcon implementation -----------------
*/
/**
* Gets the description of the icon. This is meant to be a brief textual
* description of the object. For example, it might be presented to a
* blind user to give an indication of the purpose of the icon.
*
* @return the description of the icon
*/
public String getAccessibleIconDescription () {
return ImageAndTextIcon.this.getDescription();
}
/**
* Sets the description of the icon. This is meant to be a brief textual
* description of the object. For example, it might be presented to a
* blind user to give an indication of the purpose of the icon.
*
* @param description
* the description of the icon
*/
public void setAccessibleIconDescription (String description) {
ImageAndTextIcon.this.setDescription(description);
}
/**
* Gets the height of the icon.
*
* @return the height of the icon
*/
public int getAccessibleIconHeight () {
return ImageAndTextIcon.this.height;
}
/**
* Gets the width of the icon.
*
* @return the width of the icon
*/
public int getAccessibleIconWidth () {
return ImageAndTextIcon.this.width;
}
private void readObject (ObjectInputStream s) throws ClassNotFoundException, IOException {
s.defaultReadObject();
}
private void writeObject (ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
}
} // AccessibleImageIcon
}