//*****************************************************************************
/*
** FILE:   xu_MenuButtonGroupElement.java
**
** (c) 1998 Steve Withall.
**
** HISTORY:
**    10May98  stevew  Created.
*/
package xu;

import xg.xg_Element;
import xg.xg_Node;
import xg.xg_VerificationException;

import eh.eh_Debug;

import com.sun.java.swing.Action;
import com.sun.java.swing.ButtonGroup;
import com.sun.java.swing.JMenuItem;
import com.sun.java.swing.JRadioButtonMenuItem;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

//*****************************************************************************
/** <p>An XML element to represent a Swing button group. It represents a
 *  collection of radio buttons within a menu, only one of which can be
 *  selected at once.</p>
 *
 *  <p>It also supports associating an Action with the group, which is invoked
 *  (ie. its actionPerformed method is called) when the currently-selected
 *  button is changed. This behaviour means it is possible for a frame to use a
 *  button group without having to deal with the relatively large number of
 *  classes used here to implement them.</p>
 *
 *  <p>The xu_ButtonGroupAction class exists for this purpose (although any class
 *  derived from Action can be used). xu_ButtonGroupAction is able to keep track
 *  of which item in the group is currently selected. Thus a button group can be
 *  used while seeing only the xu_ButtonGroupAction and xu_FrameConfigManager
 *  classes.</p>
 */
public class xu_MenuButtonGroupElement extends xg_Element
{
    /** The button group created by this element. */
    protected ButtonGroup      TheButtonGroup = new ButtonGroup();

    /** The action associated with this element. */
    protected Action           GroupAction    = null;

    /** The element type name normally used in XML for this sort of element. */
    public final static String RegisteredName = "MenuButtonGroup";

    /** The name of the attribute which holds the ID of this button group. */
    public final static String IdAttName      = "Name";

    //*****************************************************************************
    /** Construct a menu button group with no type and no name.
     */
    public xu_MenuButtonGroupElement()
    {
    }

    //*****************************************************************************
    /** Construct a menu button group with a name.
     *
     *  @param  InputNodeName  The name of the element
     */
    public xu_MenuButtonGroupElement(String InputNodeName)
    {
        super(InputNodeName);
    }

    //*****************************************************************************
    /** Verify that this node is correct (ie. internally correct and/or consistent
     *  with other nodes - such as its parent). The node is OK if each of its
     *  children is an xu_MenuItemElement or not an xg_Element.
     *
     * @exception  xg_VerificationException  Description of verification problem
     */
    public void verify() throws xg_VerificationException
    {
        eh_Debug.add(8, "xu_MenuButtonGroupElement.verify: Verify '" + toString() + "'");

        // See if there is an Action associated with this button group.
        String  NameValue = getAttributeValue(IdAttName);
        if (NameValue != null)
        {
            // Retrieve the document this button group belongs to.
            xg_Node  RootNode = getRootNode();
            if (    RootNode == null
                 || !(RootNode instanceof xu_FrameConfigDocument) )
                eh_Debug.add(2, "xu_MenuButtonGroupElement.verify: button group '"
                                      + NameValue + "' not within a 'xu_FrameConfigDocument', so cannot retieve associated Action");
            else
            {
                xu_FrameConfigDocument  TheFrameConfigDocument = (xu_FrameConfigDocument)RootNode;

                GroupAction = TheFrameConfigDocument.getAction(NameValue);
   	            if (GroupAction == null)
                    eh_Debug.add(2, "xu_MenuButtonGroupElement.verify: No action associated with button group" + NameValue);
   	        }
   	    }

        // Check the children are the right sort, and add them to the group if so.
        xg_Node             CurrentChild           = null;
        xu_MenuItemElement  CurrentMenuItemElement = null;
        JMenuItem           CurrentMenuItem        = null;
        boolean             AnItemSelectedFlag     = false;

        for (int ChildIndex = 0; ChildIndex < getChildCount(); ChildIndex++)
        {
            CurrentChild = (xg_Node)getChildAt(ChildIndex);

            // Check this child is of an acceptable type.
            if (CurrentChild instanceof xg_Element)
            {
                if (CurrentChild instanceof xu_MenuItemElement)
                {
                    // Add the menu item in this element to the Menu.
                    CurrentMenuItemElement = (xu_MenuItemElement)CurrentChild;
                    CurrentMenuItem        = CurrentMenuItemElement.getMenuItem();
                    if (CurrentMenuItem instanceof JRadioButtonMenuItem)
                    {
                        TheButtonGroup.add((JRadioButtonMenuItem)CurrentMenuItem);
                        if (GroupAction instanceof xu_ButtonGroupAction)
                        {
                            // Store the attributes of this item in the group.
                            ((xu_ButtonGroupAction)GroupAction).addAttList(CurrentMenuItemElement.getAttList() );

                            // If checked, recognise this as the selected item.
                            if (CurrentMenuItemElement.getState() == true)
                            {
                                if (AnItemSelectedFlag)
                                    eh_Debug.add(2, "Warning: More than one radio button is checked");
//                                    throw new xg_VerificationException("More than one radio button is checked",
//                                                                       CurrentChild.getStartOffset(),
//                                                                       CurrentChild.getEndOffset() );
                                else
                                {
                                    ((xu_ButtonGroupAction)GroupAction).setIndex(ChildIndex);
                                    AnItemSelectedFlag = true;
                                }
                            }
                        }
                    }
	                CurrentMenuItem.addItemListener(new RadioListener(ChildIndex) );
                }
                else
                    throw new xg_VerificationException("Child element '" + CurrentChild.getName()
                                                          + "' not of correct type to include in a button group",
                                                       CurrentChild.getStartOffset(),
                                                       CurrentChild.getEndOffset() );
            }
        }
    }

    //*****************************************************************************
    /** Get the button group created by this element.
     *
     *  @return  The button group itself.
     */
    public ButtonGroup getButtonGroup()
    {
        return TheButtonGroup;
    }

    //*****************************************************************************
    /** Get a summary descriptive string suitable for display in the tree view or
     *  elsewhere.
     *
     *  @return  A description suitable for display in the tree view
     */
    public String toString()
    {
        return("Button group element '" + NodeName + "'");
    }

    //*****************************************************************************
    //***Inner*classes*************************************************************
    //*****************************************************************************
    /** Listener to be notified when a radio button within a button group is pressed.
     *  Each button in the group is expected to have its own RadioListener object.
     */
    class RadioListener implements ItemListener
    {
        /** Index expected to hold the relative position of the button in the button
         *  group. */
        int  ButtonGroupIndex = 0;

        //*****************************************************************************
        /** Default constructor.
         */
        public RadioListener(int  InputButtonGroupIndex)
        {
            ButtonGroupIndex = InputButtonGroupIndex;
        }

        //*****************************************************************************
        /** The button has been pressed.
         */
	    public void itemStateChanged(ItemEvent  InputItemEvent)
	    {
	        JRadioButtonMenuItem  CurrentRadioButton = (JRadioButtonMenuItem)InputItemEvent.getSource();
            try
            {
	            if (CurrentRadioButton.isSelected() )
	            {
                    eh_Debug.add(7, "RadioListener.itemStateChanged: Change selected option to number "
                                       + ButtonGroupIndex);
                    if (GroupAction != null)
                    {
                        // Invoke the associated Action.
                        ActionEvent  RadioActionEvent = new ActionEvent(CurrentRadioButton,
                                                                        ButtonGroupIndex,
                                                                        null);
                        GroupAction.actionPerformed(RadioActionEvent);
                    }
	            }
            }
            catch (Exception  InputException)
            {
		        CurrentRadioButton.setEnabled(false);
                eh_Debug.add(2, "RadioListener.itemStateChanged: '"
                                   + CurrentRadioButton.getText() + "' unsupported:"
                                   + InputException);
            }
	    }
    }
}

//*****************************************************************************
