org.wings.SAbstractButton.java Source code

Java tutorial

Introduction

Here is the source code for org.wings.SAbstractButton.java

Source

/*
 * $Id$
 * Copyright 2000,2005 wingS development team.
 *
 * This file is part of wingS (http://www.j-wings.org).
 *
 * wingS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * Please see COPYING for the complete licence.
 */
package org.wings;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wings.plaf.ButtonCG;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

/**
 * This is the base class for all components which have a button
 * functionality. This class handles ActionListener notification.
 *
 * @author <a href="mailto:armin.haaf@mercatis.de">Armin Haaf</a>
 * @version $Revision$
 */
public abstract class SAbstractButton extends SAbstractIconTextCompound implements LowLevelEventListener {
    private final transient static Log log = LogFactory.getLog(SAbstractButton.class);

    public static final String SUBMIT_BUTTON = "submit";
    public static final String RESET_BUTTON = "reset";
    public static final String IMAGE_BUTTON = "image";
    public static final String CHECKBOX = "checkbox";
    public static final String RADIOBUTTON = "radio";

    private String type = SUBMIT_BUTTON;

    private SButtonGroup buttonGroup;

    protected String actionCommand;

    private String eventTarget;

    private Action action;

    private PropertyChangeListener actionPropertyChangeListener;

    private String mnemonic;

    /** @see LowLevelEventListener#isEpochCheckEnabled() */
    private boolean epochCheckEnabled = true;

    /**
     * Create a button with given text.
     *
     * @param text the button text
     */
    public SAbstractButton(String text) {
        super(text);
    }

    public SAbstractButton(Action action) {
        setAction(action);
    }

    /**
     * Creates a new Button with the given Text and the given Type.
     *
     * @param text the button text
     * @param type the button type
     * @see #setType
     */
    public SAbstractButton(String text, String type) {
        this(text);
        setType(type);
    }

    /**
     * Creates a new submit button
     */
    public SAbstractButton() {
    }

    /**
     * Sets the action command for this button.
     *
     * @param ac the action command for this button
     */
    public void setActionCommand(String ac) {
        actionCommand = ac;
    }

    /**
     * Returns the action command for this button.
     *
     * @return the action command for this button
     */
    public final String getActionCommand() {
        return actionCommand;
    }

    /**
     * TODO: Return the Button group where this button lies in
     *
     * @return Button Group or null if not in a group
     */
    public final SButtonGroup getGroup() {
        return buttonGroup;
    }

    protected void setParentFrame(SFrame f) {
        if (buttonGroup != null && getDispatcher() != null) {
            getDispatcher().removeLowLevelEventListener(this, buttonGroup.getComponentId());
        } // end of if ()

        super.setParentFrame(f);

        if (buttonGroup != null && getDispatcher() != null) {
            getDispatcher().addLowLevelEventListener(this, buttonGroup.getComponentId());
        } // end of if ()
    }

    /**
     * Add this button to a button group. This influences the event-prefix
     * this button reports to the request dispatcher: it will change to
     * the button group's prefix.
     */
    protected void setGroup(SButtonGroup g) {
        if (isDifferent(buttonGroup, g)) {
            if (buttonGroup != null && getDispatcher() != null) {
                getDispatcher().removeLowLevelEventListener(this, buttonGroup.getComponentId());
            } // end of if ()
            buttonGroup = g;
            if (buttonGroup != null && getDispatcher() != null) {
                getDispatcher().removeLowLevelEventListener(this, buttonGroup.getComponentId());
            } // end of if ()
            reload();
        }
    }

    /**
     * Adds an ActionListener to the button.
     *
     * @param listener the ActionListener to be added
     */
    public void addActionListener(ActionListener listener) {
        addEventListener(ActionListener.class, listener);
    }

    /**
     * Removes the supplied Listener from teh listener list
     */
    public void removeActionListener(ActionListener listener) {
        removeEventListener(ActionListener.class, listener);
    }

    /**
     * Returns an array of all the <code>ActionListener</code>s added
     * to this AbstractButton with addActionListener().
     *
     * @return all of the <code>ActionListener</code>s added or an empty
     *         array if no listeners have been added
     */
    public ActionListener[] getActionListeners() {
        return (ActionListener[]) (getListeners(ActionListener.class));
    }

    /**
     * Fire an ActionEvent at each registered listener.
     *
     * @param event supplied ActionEvent
     */
    protected void fireActionPerformed(ActionEvent event) {
        // Guaranteed to return a non-null array
        Object[] listeners = getListenerList();
        ActionEvent e = null;
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length - 2; i >= 0; i -= 2) {
            if (listeners[i] == ActionListener.class) {
                if (e == null) {
                    String actionCommand = event.getActionCommand();
                    if (actionCommand == null) {
                        actionCommand = getActionCommand();
                    }
                    e = new ActionEvent(SAbstractButton.this, ActionEvent.ACTION_PERFORMED, actionCommand,
                            event.getWhen(), event.getModifiers());
                }
                ((ActionListener) listeners[i + 1]).actionPerformed(e);
            }
        }
    }

    /**
     * Sets the button type. Use one of the following types:
     * <UL>
     * <LI> {@link #SUBMIT_BUTTON}
     * <LI> {@link #RESET_BUTTON}
     * <LI> {@link #CHECKBOX}
     * <LI> {@link #RADIOBUTTON}
     * </UL>
     */
    public void setType(String t) {
        if (isDifferent(type, t)) {
            type = t;
            reload();
        }
    }

    /**
     * Delifers the Button Type
     *
     * @return Button Type
     */
    public final String getType() {
        return type;
    }

    /**
     * Simulates an click on the Button
     */
    public void doClick() {
        setSelected(!isSelected());

        fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, getActionCommand()));
    }

    /**
     * Sets the state of the button.      *
     *
     * @param b true if the button is selected, otherwise false
     */
    public void setSelected(boolean b) {
        if (isSelected() != b) {
            if (buttonGroup != null) {
                buttonGroup.setSelected(this, b);
            }
            super.setSelected(b);
        }
    }

    public void processLowLevelEvent(String action, String[] values) {
        processKeyEvents(values);

        boolean requestSelection = isSelected();

        int eventCount = 0;

        if (buttonGroup != null) {
            // button group prefix is shared, so maybe more than one value is
            // delivered in a form
            for (int i = 0; i < values.length; i++) {

                // with button group the value has a special encoding...
                // this is because in a form the name of a parameter for
                // buttons in a buttongroup must be the same...
                String value = values[i];

                // illegal format
                if (value.length() < 3) {
                    continue;
                }

                // no uid DIVIDER
                // value.charAt(value.length()-2)!=UID_DIVIDER ) { break; }

                // not for me
                if (!value.startsWith(super.getLowLevelEventId())) {
                    continue;
                }

                // last character is indicator, if button should be
                // selected or not
                switch (value.charAt(value.length() - 1)) {
                case '1':
                    requestSelection = true;
                    ++eventCount;
                    break;
                case '0':
                    requestSelection = false;
                    ++eventCount;
                    break;
                }
            }
        } else {
            for (int i = 0; i < values.length; i++) {
                requestSelection = parseSelectionToggle(values[0]);
                ++eventCount;
            }
        }

        /*
         * Checkboxes in HTML-forms write two form components:
         * one hidden input, containing the deselect-command (value='0'),
         * and one <input type="checkbox".. value="1">.
         * This is, because browsers send the checkbox-variable
         * only if it is set, not if it is not set.
         * So, if we get two events with the same name, then the checkbox
         * actually got selected; if we only got one event (from the hidden
         * input), then it was a deselect-event (select event value = '1',
         * deselect value = '0').
         * This is just in case, the browser sends the both events
         * in the wrong order (select and then deselect).
         */
        if (eventCount == 2) {
            requestSelection = true;
        }

        if (isSelected() != requestSelection) {
            delayEvents(true);
            if (buttonGroup != null) {
                buttonGroup.setDelayEvents(true);
                setSelected(requestSelection);
                buttonGroup.setDelayEvents(false);
            } else {
                setSelected(requestSelection);
            }

            SForm.addArmedComponent(this);
        }
    }

    public void fireIntermediateEvents() {
        super.fireIntermediateEvents();
        if (buttonGroup != null) {
            buttonGroup.fireDelayedIntermediateEvents();
        }
    }

    public void fireFinalEvents() {
        requestFocus();
        super.fireFinalEvents();
        fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, getActionCommand()));
        if (buttonGroup != null)
            buttonGroup.fireDelayedFinalEvents();
    }

    public final String getEventTarget() {
        return eventTarget;
    }

    public void setEventTarget(String target) {
        if (isDifferent(eventTarget, target)) {
            eventTarget = target;
            reload();
        }
    }

    protected boolean parseSelectionToggle(String toggleParameter) {
        if ("1".equals(toggleParameter))
            return true;
        else if ("0".equals(toggleParameter))
            return false;

        // don't change...
        return isSelected();
    }

    public String getToggleSelectionParameter() {
        return isSelected() ? getDeselectionParameter() : getSelectionParameter();
    }

    public String getSelectionParameter() {
        return "1";
    }

    public String getDeselectionParameter() {
        return "0";
    }

    /**
     * Sets the action for the ActionEvent source.
     * the new action code will replace the old one but not the one bound to the actionListener
     *
     * @param a the Action for the AbstractButton,
     */

    public void setAction(Action a) {
        Action oldValue = getAction();
        if (action == null || !action.equals(a)) {
            action = a;
            if (oldValue != null) {
                removeActionListener(oldValue);
                oldValue.removePropertyChangeListener(actionPropertyChangeListener);
                actionPropertyChangeListener = null;
            }
            configurePropertiesFromAction(action);
            if (action != null) {
                // Don't add if it is already a listener
                if (!isListener(ActionListener.class, action)) {
                    addActionListener(action);
                }
                // Reverse linkage:
                actionPropertyChangeListener = createActionPropertyChangeListener(action);
                action.addPropertyChangeListener(actionPropertyChangeListener);
            }
            reload();
        }
    }

    private boolean isListener(Class c, ActionListener a) {
        boolean isListener = false;
        Object[] listeners = getListenerList();
        for (int i = listeners.length - 2; i >= 0; i -= 2) {
            if (listeners[i] == c && listeners[i + 1] == a) {
                isListener = true;
            }
        }
        return isListener;
    }

    /**
     * Returns the action for this ActionEvent source, or <code>null</code>
     * if no <code>Action</code> is set.
     *
     * @return the <code>Action</code> for this <code>ActionEvent</code>
     *         source, or <code>null</code>
     */
    public Action getAction() {
        return action;
    }

    public void setCG(ButtonCG cg) {
        super.setCG(cg);
    }

    protected void configurePropertiesFromAction(Action a) {
        // uncomment if compiled against < jdk 1.3
        //   setActionCommand((a != null
        //                  ? (String)a.getValue(Action.ACTION_COMMAND_KEY)
        //                  : null));
        setText((a != null ? (String) a.getValue(Action.NAME) : null));
        setIcon((a != null ? (SIcon) a.getValue(Action.SMALL_ICON) : null));
        setEnabled((a != null ? a.isEnabled() : true));
        setToolTipText((a != null ? (String) a.getValue(Action.SHORT_DESCRIPTION) : null));
    }

    /*
     * if the action changes its name, enabledstatus etc. internally,
     * we have to react on this. So delegate this in case we have an
     * action.
     */

    /**
     * Returns, whether this Button or its action is enabled.
     */
    public boolean isEnabled() {
        return (action == null ? super.isEnabled() : action.isEnabled());
    }

    public String getText() {
        if (action == null)
            return super.getText();
        final String actionText = (String) action.getValue(Action.NAME);
        return (actionText != null ? actionText : super.getText());
    }

    public SIcon getIcon() {
        if (action == null)
            return super.getIcon();
        final SIcon actionIcon = (SIcon) action.getValue(Action.SMALL_ICON);
        return (actionIcon != null) ? actionIcon : super.getIcon();
    }

    public String getToolTipText() {
        if (action == null)
            return super.getToolTipText();
        final String actionTool = (String) action.getValue(Action.SHORT_DESCRIPTION);
        return (actionTool != null) ? actionTool : super.getToolTipText();
    }

    protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
        return new ButtonActionPropertyChangeListener(this, a);
    }

    private static class ButtonActionPropertyChangeListener extends AbstractActionPropertyChangeListener {
        ButtonActionPropertyChangeListener(SAbstractButton b, Action a) {
            super(b, a);
        }

        public void propertyChange(PropertyChangeEvent e) {
            String propertyName = e.getPropertyName();
            SAbstractButton button = (SAbstractButton) getTarget();
            if (button == null) {
                Action action = (Action) e.getSource();
                action.removePropertyChangeListener(this);
            } else {
                if (e.getPropertyName().equals(Action.NAME)) {
                    String text = (String) e.getNewValue();
                    button.setText(text);
                } else if (e.getPropertyName().equals(Action.SHORT_DESCRIPTION)) {
                    String text = (String) e.getNewValue();
                    button.setToolTipText(text);
                } else if (propertyName.equals("enabled")) {
                    Boolean enabled = (Boolean) e.getNewValue();
                    button.setEnabled(enabled.booleanValue());
                } else if (e.getPropertyName().equals(Action.SMALL_ICON)) {
                    SIcon icon = (SIcon) e.getNewValue();
                    button.setIcon(icon);
                }
                // uncomment if compiled against jdk < 1.3
                /*                else if (e.getPropertyName().equals(Action.ACTION_COMMAND_KEY)) {
                              String actionCommand = (String)e.getNewValue();
                              button.setActionCommand(actionCommand);
                              }*/
            }
        }
    }

    public void setMnemonic(String mnemonic) {
        reloadIfChange(this.mnemonic, mnemonic);
        this.mnemonic = mnemonic;
    }

    public String getMnemonic() {
        return mnemonic;
    }

    /** @see LowLevelEventListener#isEpochCheckEnabled() */
    public boolean isEpochCheckEnabled() {
        return epochCheckEnabled;
    }

    /** @see LowLevelEventListener#isEpochCheckEnabled() */
    public void setEpochCheckEnabled(boolean epochCheckEnabled) {
        this.epochCheckEnabled = epochCheckEnabled;
    }
}