/*
 * ColorButton.java
 *
 * Created on May 14, 2005, 5:13 PM
 */
package edu.oregonstate.cartography.gui;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.colorchooser.AbstractColorChooserPanel;
import javax.swing.colorchooser.ColorSelectionModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * A button to select a color. The currently selected color is displayed by the
 * button.
 *
 * @author Bernhard Jenny, Institute of Cartography, ETH Zurich.
 */
public class ColorButton extends JToggleButton implements ActionListener {

    /**
     * The current color.
     */
    private Color color;

    /**
     * Color to restore when user presses cancel button.
     */
    private Color originalColor;
    
    /**
     * The horizontal width of the icon that displays the color.
     */
    private int iconWidth;

    /**
     * The vertical width of the icon that displays the color.
     */
    private int iconHeight;

    /**
     * The title of the color chooser dialog.
     */
    private String colorChooserTitle;

    //The dialog that the button brings up.
    JColorChooser colorChooser;
    JDialog dialog;

    /**
     * Creates a new instance of ColorButton. Default color is black, default
     * size of the icon is 16 x 16 pixels. This button is registered with itself
     * for receiving action performed calls.
     */
    public ColorButton() {
        this.color = new Color(0, 0, 0);
        this.iconHeight = 16;
        this.iconWidth = 16;
        this.colorChooserTitle = "Choose a Color";

        //Set up the dialog that the button brings up.
        colorChooser = new JColorChooser();

        // replace the ugly and useless preview panel by an empty JPanel
        colorChooser.setPreviewPanel(new JPanel());

        // remove the swatch
        AbstractColorChooserPanel[] choosers = colorChooser.getChooserPanels();
        for (AbstractColorChooserPanel chooser : choosers) {
            String clsName = chooser.getClass().getName();
            if (clsName.equals("javax.swing.colorchooser.DefaultSwatchChooserPanel")) {
                colorChooser.removeChooserPanel(chooser);
            }
        }

        ColorSelectionModel colorSelectionModel = colorChooser.getSelectionModel();
        colorSelectionModel.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent evt) {
                ColorSelectionModel model = (ColorSelectionModel) evt.getSource();
                setColor(model.getSelectedColor());
            }
        });

        this.updateIcon();
    }

    /**
     * Internal utility method that creates a new icon. Called after the user
     * selects a new color, or when the size of the icon changes.
     */
    private void updateIcon() {
        BufferedImage image = new BufferedImage(iconWidth, iconHeight,
                BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = (Graphics2D) image.getGraphics();

        // turn antialiasing off
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_OFF);
        // we want fast rendering
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_SPEED);

        // first draw white background to show semi-transparent color
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, iconWidth, iconHeight);

        g2d.setColor(color);
        g2d.fillRect(0, 0, iconWidth, iconHeight);
        g2d.setColor(Color.GRAY);
        g2d.drawRect(0, 0, iconWidth - 1, iconHeight - 1);
        ImageIcon imageIcon = new ImageIcon(image);
        setIcon(imageIcon);
        g2d.dispose();
    }

    /**
     * Action listener for the OK button in the color chooser.
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        // ok button in color chooser was pressed.
        this.setColor(colorChooser.getColor());
        super.fireActionPerformed(e);
    }

    @Override
    protected void fireActionPerformed(ActionEvent event) {
        try {
            this.setSelected(true);
            
            // create the dialog if this has not been done yet.
            if (this.dialog == null) {
                // Get the top level ancestor as parent for the new dialog.
                // This ensures that on Mac OS X the global menu bar remains 
                // visible while the dialog is open.
                final Container parent = this.getTopLevelAncestor();
                dialog = JColorChooser.createDialog(parent,
                        colorChooserTitle,
                        true, //modal
                        colorChooser,
                        // OK button handler           
                        this,
                        // cancel button handler
                        new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        // restore original color
                        setColor(originalColor);
                    }
                });
                dialog.pack();
                dialog.setResizable(false);
            }

            // show the dialog
            originalColor = new Color(color.getRed(), color.getGreen(), 
                    color.getBlue(), color.getAlpha());
            colorChooser.setColor(color);
            dialog.setVisible(true);

            /* A simpler option that is displaying the ugly preview panel:
            Color newColor = JColorChooser.showDialog(this.getTopLevelAncestor(),
                    colorChooserTitle, color);
            if (newColor != null){
                // only set color and fire an event when user did not cancel.
                this.setColor(newColor);
                super.fireActionPerformed(event);
            }*/
        } catch (Exception e) {
        } finally {
            this.setSelected(false);
        }
    }

    /**
     * Returns the currently selected Color.
     *
     * @return The current color.
     */
    public Color getColor() {
        return color;
    }

    /**
     * Changes the current color.
     *
     * @param color The new color.
     */
    public void setColor(Color color) {
        if (color != null) {
            this.setEnabled(true);
            this.color = color;
            this.updateIcon();
        } else {
            this.setEnabled(false);
        }
    }

    /**
     * Returns the width of the icon used to display the color.
     *
     * @return The width of the icon.
     */
    public int getIconWidth() {
        return iconWidth;
    }

    /**
     * Sets the width of the icon used to display the color.
     *
     * @param iconWidth The new width of the icon.
     */
    public void setIconWidth(int iconWidth) {
        this.iconWidth = iconWidth;
        this.updateIcon();
    }

    /**
     * Returns the height of the icon used to display the color.
     *
     * @return The height of the icon.
     */
    public int getIconHeight() {
        return iconHeight;
    }

    /**
     * Sets the height of the icon used to display the color.
     *
     * @param iconHeight The new height of the icon.
     */
    public void setIconHeight(int iconHeight) {
        this.iconHeight = iconHeight;
        this.updateIcon();
    }

    /**
     * Returns the title of the color chooser dialog.
     *
     * @return The title.
     */
    public String getColorChooserTitle() {
        return colorChooserTitle;
    }

    /**
     * Sets the title of the color chooser dialog
     *
     * @param colorChooserTitle The new title.
     */
    public void setColorChooserTitle(String colorChooserTitle) {
        this.colorChooserTitle = colorChooserTitle;
    }
}