/*
 * @(#)BooleanView.java    1.2  5 January 2002
 *
 * Copyright 2005
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.gui;

import edu.neu.ccs.*;
import edu.neu.ccs.util.*;

import java.awt.*;
import javax.swing.*;
import java.text.ParseException;

/**
 * <P>A <CODE>{@link TypedView TypedView}</CODE> 
 * for the input of a <CODE>boolean</CODE> value.</P>
 *
 * @author  Jeff Raab
 * @author  Richard Rasala
 * @version 2.3.3
 * @since   1.0
 */
public class BooleanView 
    extends JCheckBox 
    implements TypedView, JPTConstants
{
    /** Bound property name for the boolean value property. */
    public static final String BOOLEAN_VALUE = "boolean.value";
    
    /** The default value for this input object. */
    protected boolean defaultValue = true;
    
    /** Property list for this view object. */
    protected InputProperties properties = new InputProperties();
    
    
    //////////////////
    // Constructors //
    //////////////////
    
    /**
     * Constructs a view with the given label
     * and a default value of <CODE>true</CODE>.
     *
     * @param labelText the text for the label
     * @see #BooleanView(String, boolean)
     * @see #BooleanView(String, Action)
     * @see #BooleanView(String, Action, boolean)
     */
    public BooleanView(String labelText) {
        this(labelText, null, true);
    }
    
    
    /**
     * Constructs a view with the given label
     * and the given default value.
     *
     * @param labelText the text for the label
     * @param b the default value
     * @see #BooleanView(String)
     * @see #BooleanView(String, Action)
     * @see #BooleanView(String, Action, boolean)
     */
    public BooleanView(String labelText, boolean b) {
        this(labelText, null, b);
    }
    
    
    /**
     * Constructs a view with the given label
     * and a default value of <CODE>true</CODE>
     * that will execute the given action when clicked.
     *
     * @param labelText the text for the label
     * @param action the action to execute when the button is clicked
     * @see #BooleanView(String)
     * @see #BooleanView(String, boolean)
     * @see #BooleanView(String, Action, boolean)
     */
    public BooleanView(String labelText, Action action) {
        this(labelText, action, true);
    }
    
    
    /**
     * Constructs a view with the given label
     * and the given default value
     * that will execute the given action when clicked.
     *
     * @param labelText the text for the label
     * @param action the action to execute when the button is clicked
     * @param b the default value
     * @see #BooleanView(String)
     * @see #BooleanView(String, boolean)
     * @see #BooleanView(String, Action)
     */
    public BooleanView(String labelText, Action action, boolean b) {
        super(labelText, b);
        defaultValue = b;
        
        if (action != null)
            addActionListener(action);
    }
    
    
    ///////////////
    // TypedView //
    ///////////////
    
    /**
     * Returns an <CODE>XBoolean</CODE> object 
     * whose state is set to the view state of this view.
     *
     * @see #requestObject()
     * @see TypedView
     */
    public Stringable demandObject() {
        return new XBoolean(getBooleanValue());
    }
    
    
    /**
     * Returns an <CODE>XBoolean</CODE> object 
     * whose state is set to the view state of this view.
     *
     * @see #demandObject()
     * @see TypedView
     */
    public Stringable requestObject() {
        return demandObject();
    }
    
    
    public void setInputProperties(InputProperties p) {
        if (p == null)
            p = InputProperties.BASE_PROPERTIES;
    
        InputProperties oldProperties = getInputProperties();

        properties = p;

        // if the input properties have changed
        if ((getInputProperties() != null) &&
            !getInputProperties().equals(oldProperties)) {
            
            // notify listeners of property change
            firePropertyChange(
                INPUT_PROPERTIES,
                oldProperties,
                getInputProperties());
        }
    }
    
    
    public InputProperties getInputProperties() {
        return properties;
    }
    
    
    /**
     * Returns the <CODE>XBoolean</CODE> class object.
     *
     * @see TypedView
     */ 
    public Class getDataType() {
        return XBoolean.class;
    }
    
    
    /////////////////
    // Displayable //
    /////////////////
    
    /**
     * Sets the view state for this view 
     * to the <CODE>boolean</CODE> value represented
     * by the given <CODE>String</CODE> data.
     *
     * @param data the new view state
     * @see #getViewState()
     * @see Displayable
     */
    public void setViewState(String data) {
        setBooleanValue(BooleanView.parseBoolean(
            data, "setViewState"));
        
        // notify listeners of the property change
        firePropertyChange(
            VIEW_STATE, 
            null, 
            data);
    }
    
    
    /**
     * Returns the <CODE>String</CODE> <CODE>"true"</CODE> 
     * or the <CODE>String</CODE> <CODE>"false"</CODE>, 
     * corresponding with the view state of this object.
     *
     * @see #setViewState(String)
     * @see Displayable
     */
    public String getViewState() {
        return getBooleanValue() + "";
    }
    
    
    /**
     * Sets the default view state for this view 
     * to the <CODE>boolean</CODE> value represented
     * by the given <CODE>String</CODE> data.
     *
     * @param data the new default view state
     * @see #reset()
     * @see Displayable
     */
    public void setDefaultViewState(String data) {
        defaultValue = BooleanView.parseBoolean(
            data, "setDefaultViewState");

        // notify listeners of property change
        firePropertyChange(DEFAULT_VIEW_STATE, null, data);
    }
    
    
    /**
     * Returns the <CODE>String</CODE> <CODE>"true"</CODE> 
     * or the <CODE>String</CODE> <CODE>"false"</CODE>
     * corresponding with the default view state of this object.
     *
     * @see #setDefaultViewState(String)
     * @see #reset()
     */
    public String getDefaultViewState() {
        return "" + defaultValue;
    }
    
    
    public void reset() {
        setBooleanValue(defaultValue);
    }
    
    
    ////////////////
    // Public API //
    ////////////////

    /**
     * <p>Sets the <CODE>boolean</CODE> value that is the model
     * for this view to the given value.</p>
     *
     * <p>Fires property change BOOLEAN_VALUE.</p>
     *
     * @param b the new value
     * @see #getBooleanValue()
     */
    public void setBooleanValue(boolean b) {
        boolean oldValue = getBooleanValue();

        setSelected(b);

        // if the boolean value has changed
        if (getBooleanValue() != oldValue) {
            
            // notify listeners of property change
            firePropertyChange(
                BOOLEAN_VALUE,
                oldValue,
                getBooleanValue());
        }
    }    
    
    
    /**
     * Returns the <CODE>boolean</CODE> value
     * that is the model for this view.
     *
     * @see #setBooleanValue(boolean)
     */
    public boolean getBooleanValue() {
        return isSelected();
    }    
    
    
    /**
     * <p>Sets the font for this component.</p>
     *
     * <p>If the given font is <code>null</code> then it is set to
     * <code>getDefaultFont()</code>.</p>
     *
     * <p>Calls the super <code>setFont</code> method and
     * then refreshes the component in its parent view.</p>
     *
     * <p>Fires property change FONT.</p>
     *
     * @param font the font to set for this view
     */
    public void setFont(Font font) {
        if (font == null)
            font = getDefaultFont();
    
        super.setFont(font);
        
        refreshComponent();
        
        // notify listeners of property change
        firePropertyChange(FONT, null, null);
    }
    
    
    /**
     * Returns the default font for a JCheckBox.
     *
     * @since 2.3.3
     */
    public static Font getDefaultFont() {
        return new JCheckBox("Xy").getFont();
    }
    
    
    /** Refreshes the component by repacking the parent window. */
    public void refreshComponent() {
        Refresh.packParentWindow(this);
    }
    
    
    ///////////////////////
    // Protected methods //
    ///////////////////////
    
    /**
     * Returns the <CODE>boolean</CODE> value
     * represented by the given <CODE>String</CODE> data.
     *
     * @param data the data <CODE>String</CODE> to be parsed
     * @param caller the name of the method that requires parsing
     * @throws JPTError if there is an error parsing the data
     */
    protected static boolean parseBoolean(
        String data, 
        String caller) 
    {
        try {
            return (new XBoolean(data)).getValue();
        }
        catch (ParseException ex) {
            throw new JPTError(
                "Malformed data in BooleanView." + 
                caller + ": " + data);
        }
    }
    
}
