/*
 * [TestJButton.java]
 *
 * Summary: Demonstrate use of java.swing.JButton.
 *
 * Copyright: (c) 2009-2017 Roedy Green, Canadian Mind Products, http://mindprod.com
 *
 * Licence: This software may be copied and used freely for any purpose but military.
 *          http://mindprod.com/contact/nonmil.html
 *
 * Requires: JDK 1.8+
 *
 * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
 *
 * Version History:
 *  1.0 2009-01-01 initial version
 */
package com.mindprod.example;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.border.Border;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Font;
import java.awt.Image;
import java.awt.Insets;
import java.awt.MediaTracker;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.ImageProducer;
import java.io.IOException;
import java.net.URL;

import static java.lang.System.*;

/**
 * Demonstrate use of java.swing.JButton.
 *
 * @author Roedy Green, Canadian Mind Products
 * @version 1.0 2009-01-01 initial version
 * @since 2009-01-01
 */
public final class TestJButton
    {
    private static final Border buttonBevelBorder;

    static
        {
        final Border innerBorder =
                BorderFactory.createEmptyBorder( 2, 5, 2, 5 );
        final Border outerBorder = BorderFactory.createRaisedBevelBorder();
        buttonBevelBorder =
                BorderFactory.createCompoundBorder( outerBorder, innerBorder );
        }

    /**
     * Simple way to create an ImageIcon
     * Read a png, gif or jpg from the archive resource jar file.
     *
     * @param imageResourceName fully resource name of the image in the jar. if leave off off lead / will be relative to
     *                          com.mindprod.example.
     *
     * @return ImageIcon corresponding to the png/gif/jpg.
     */
    private static ImageIcon createImageIcon( String imageResourceName )
        {
        URL url = TestButton.class.getResource( imageResourceName );
        if ( url == null )
            {
            return null;
            }
        return new ImageIcon( url );
        }

    /**
     * Debugging tool. Get name of a component in an Event
     *
     * @param e Event
     *
     * @return name of the Component
     */
    private static String getName( AWTEvent e )
        {
        try
            {
            final String result = ( ( Component ) e.getSource() ).getName();
            if ( result == null || result.length() == 0 )
                {
                return "unknown" + e.getSource().getClass().toString() + " Component";
                }
            else
                {
                return result;
                }
            }
        catch ( ClassCastException ex )
            {
            return "unknown " + e.getSource().getClass().toString() + " source";
            }
        }

    /**
     * Long-Winded way to read a png, gif or jpg from the archive resource jar file.
     * Not used.
     *
     * @param imageResourceName fully resource name of the image in the jar. if leave off off lead / will be relative to
     *                          com.mindprod.example.
     * @param target            Component where this image will end up.
     *
     * @return ImageIcon corresponding to the png/gif/jpg.
     */
    @SuppressWarnings( { "EmptyCatchBlock" } )
    public static ImageIcon createImageIcon( String imageResourceName, Component target )
        {
        try
            {
            URL url = TestButton.class.getResource( imageResourceName );
            if ( url == null )
                {
                err.println( "createImageIcon cannot find resource "
                             + imageResourceName );
                return null;
                }
            Image image = target.getToolkit()
                    .createImage( ( ImageProducer ) url.getContent() );
            // wait till item is loaded
            MediaTracker tracker;
            try
                {
                // wait until image is fully loaded.
                // MediaTracker arranges repaint via ImageObsever interface
                tracker = new MediaTracker( target );
                tracker.addImage( image, 0 );
                tracker.waitForID( 0 );
                }
            catch ( InterruptedException e )
                {
                }
            return new ImageIcon( image );
            }
        catch ( IOException e )
            {
            err.println();
            err.println();
            e.printStackTrace( System.err );
            err.println();
            return null;
            }
        }

    /**
     * Debugging harness for a Frame
     *
     * @param args command line arguments are ignored.
     */
    public static void main( String args[] )
        {
        final JFrame frame = new JFrame();
        Container contentPane = frame.getContentPane();
        contentPane.setLayout( new BorderLayout() );
        // create JButton with text label.
        JButton jButton1 = new JButton( "Alert" );
        jButton1.setBorder( BorderFactory.createRaisedBevelBorder() );
        jButton1.setFocusPainted( false );
        jButton1.setToolTipText( "Alert homeland security" );
        // Leaving off colours gets you a pretty
        // gradient metal button.
        jButton1.setBackground( Color.BLACK );
        jButton1.setForeground( Color.YELLOW );
        jButton1.setFont( new Font( "Dialog", Font.BOLD, 15 ) );
        jButton1.setEnabled( true );
        jButton1.addActionListener( new ActionListener()
            {
            /**
             * Invoked when a button pressed
             */
            public void actionPerformed( ActionEvent e )
                {
                out.println( "Alert button pressed" );
                }
            } );
        // ---------------------------------
        JButton jButton2 = new JButton( "CMP Standard Button" );
        jButton2.setName( "Standard Button" );
        jButton2.setFocusPainted( false );
        jButton2.setBorder( buttonBevelBorder );
        jButton2.setFont( new Font( "Dialog", Font.BOLD, 16 ) );
        jButton2.setToolTipText(
                "This is the way I have standardised all my buttons." );
        // set up keystroke shortcut Alt-F2
        jButton2.setMnemonic( KeyEvent.VK_F2 );
        jButton2.requestFocus();
        // setMargin does not work, when you have a Border, because
        // the margin is an implemented as a species of Border.
        // Leave foreground and background alone to get gradient.
        CommonListener cl = new CommonListener();
        jButton2.addActionListener( cl );
        // --------------------------------
        // Create JButton with custom icon
        JButton jButton3 = new JButton();
        jButton3.setName( "frog button" );
        // suppress borders
        jButton3.setBorderPainted( false );
        // suppress press decoration
        jButton3.setContentAreaFilled( false );
        // suppress the ability of the jButton1 to be triggered by enter
        jButton3.setDefaultCapable( false );
        // hide focus rectangle
        jButton3.setFocusPainted( false );
        // set how wide the space must be around the text to the buttonBevelBorder. Also use ipadx/ejbd
        jButton3.setMargin( new Insets( 3, 3, 3, 3 ) );
        // ignore clicks that come too fast
        jButton3.setMultiClickThreshhold( 100/* millis */ );
        // the images have transparent background
        jButton3.setOpaque( false );
        // hover help
        jButton3.setToolTipText( "Launch frog bioterror missiles" );
        // Various icon images live in the jar as resources in directory
        // com/mindprod/example/buttonimages/frog
        // What button looks like normally.
        jButton3.setIcon( createImageIcon( "buttonimages/frog/normal.png" ) );
        // What button looks like normally after setSelected( true ).
        jButton3.setSelectedIcon( createImageIcon( "buttonimages/frog/selected.png" ) );
        // what button looks like pressed.
        jButton3.setPressedIcon( createImageIcon( "buttonimages/frog/pressed.png" ) );
        // what jButton1 looks like when mouse hovers over item.
        jButton3.setRolloverIcon( createImageIcon( "buttonimages/frog/rollover.png" ) );
        // what button looks like when mouse hovers over item after setSelected( true ).
        jButton3.setRolloverSelectedIcon( createImageIcon( "buttonimages/frog/rolloverselected.png" ) );
        // what button looks like when item has been grayed out.
        jButton3.setDisabledIcon( createImageIcon( "buttonimages/frog/disabled.png" ) );
        // what jButton1 looks like when item has been grayed out after setSelected( true ).
        jButton3.setDisabledSelectedIcon( createImageIcon( "buttonimages/frog/disabledselected.png" ) );
        jButton3.addActionListener( cl );
        frame.add( jButton1, BorderLayout.NORTH );
        frame.add( jButton2, BorderLayout.CENTER );
        frame.add( jButton3, BorderLayout.SOUTH );
        frame.setSize( 300, 200 );
        frame.addWindowListener( new WindowAdapter()
            {
            /**
             * Handle request to shutdown.
             * @param e event giving details of closing.
             */
            public void windowClosing( WindowEvent e )
                {
                System.exit( 0 );
                } // end WindowClosing
            } // end anonymous class
        );// end addWindowListener line
        frame.validate();
        frame.setVisible( true );
        } // end main

    /**
     * common ActionListever for several Buttons. Could potentially implement several interfaces.
     * Usually an inner class, not a static nested class.
     */
    private static class CommonListener implements ActionListener
        {
        /**
         * Invoked when some button is  pressed
         */
        public void actionPerformed( ActionEvent e )
            {
            out.println( getName( e ) );
            }
        }
    }