| /******************************************************************************* |
| * Copyright (c) 2000, 2010 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.draw2d; |
| |
| import java.util.Iterator; |
| import java.util.Timer; |
| import java.util.TimerTask; |
| |
| //import org.eclipse.draw2d.internal.Timer; |
| |
| /** |
| * A model for buttons containing several properties, including enabled, |
| * pressed, selected, rollover enabled and mouseover. |
| */ |
| public class ButtonModel { |
| |
| /** Enabled property */ |
| public static final String ENABLED_PROPERTY = "enabled"; //$NON-NLS-1$ |
| /** Pressed property */ |
| public static final String PRESSED_PROPERTY = "pressed"; //$NON-NLS-1$ |
| /** Selected property */ |
| public static final String SELECTED_PROPERTY = "selected"; //$NON-NLS-1$ |
| /** Rollover Enabled property */ |
| public static final String ROLLOVER_ENABLED_PROPERTY = "rollover enabled"; //$NON-NLS-1$ |
| /** Mouseover property */ |
| public static final String MOUSEOVER_PROPERTY = "mouseover"; //$NON-NLS-1$ |
| |
| /** Armed property */ |
| public static final String ARMED_PROPERTY = "armed"; //$NON-NLS-1$ |
| |
| /** Flag for armed button state */ |
| protected static final int ARMED_FLAG = 1; |
| /** Flag for pressed button state */ |
| protected static final int PRESSED_FLAG = 2; |
| /** Flag for mouseOver state */ |
| protected static final int MOUSEOVER_FLAG = 4; |
| /** Flag for selected button state */ |
| protected static final int SELECTED_FLAG = 8; |
| /** Flag for enablement button state */ |
| protected static final int ENABLED_FLAG = 16; |
| /** Flag for rollover enablement button state */ |
| protected static final int ROLLOVER_ENABLED_FLAG = 32; |
| /** Flag that can be used by subclasses to define more states */ |
| protected static final int MAX_FLAG = ROLLOVER_ENABLED_FLAG; |
| |
| private int state = ENABLED_FLAG; |
| private Object data; |
| |
| /** |
| * Action performed events are not fired until the mouse button is released. |
| */ |
| public static final int DEFAULT_FIRING_BEHAVIOR = 0; |
| |
| /** |
| * Action performed events fire repeatedly until the mouse button is |
| * released. |
| */ |
| public static final int REPEAT_FIRING_BEHAVIOR = 1; |
| |
| /** |
| * The name of the action associated with this button. |
| */ |
| protected String actionName; |
| |
| /** |
| * The ButtonGroup this button belongs to (if any). |
| */ |
| protected ButtonGroup group = null; |
| |
| private EventListenerList listeners = new EventListenerList(); |
| |
| /** |
| * Listens to button state transitions and fires action performed events |
| * based on the desired behavior ({@link #DEFAULT_FIRING_BEHAVIOR} or |
| * {@link #REPEAT_FIRING_BEHAVIOR}). |
| */ |
| protected ButtonStateTransitionListener firingBehavior; |
| { |
| installFiringBehavior(); |
| } |
| |
| /** |
| * Registers the given listener as an ActionListener. |
| * |
| * @param listener |
| * The ActionListener to add |
| * @since 2.0 |
| */ |
| public void addActionListener(ActionListener listener) { |
| if (listener == null) |
| throw new IllegalArgumentException(); |
| listeners.addListener(ActionListener.class, listener); |
| } |
| |
| /** |
| * Registers the given listener as a ChangeListener. |
| * |
| * @param listener |
| * The ChangeListener to add |
| * @since 2.0 |
| */ |
| public void addChangeListener(ChangeListener listener) { |
| if (listener == null) |
| throw new IllegalArgumentException(); |
| listeners.addListener(ChangeListener.class, listener); |
| } |
| |
| /** |
| * Registers the given listener as a ButtonStateTransitionListener. |
| * |
| * @param listener |
| * The ButtonStateTransitionListener to add |
| * @since 2.0 |
| */ |
| public void addStateTransitionListener( |
| ButtonStateTransitionListener listener) { |
| if (listener == null) |
| throw new IllegalArgumentException(); |
| listeners.addListener(ButtonStateTransitionListener.class, listener); |
| } |
| |
| /** |
| * Notifies any ActionListeners on this ButtonModel that an action has been |
| * performed. |
| * |
| * @since 2.0 |
| */ |
| protected void fireActionPerformed() { |
| Iterator iter = listeners.getListeners(ActionListener.class); |
| ActionEvent action = new ActionEvent(this); |
| while (iter.hasNext()) |
| ((ActionListener) iter.next()).actionPerformed(action); |
| } |
| |
| /** |
| * Notifies any listening ButtonStateTransitionListener that the pressed |
| * state of this button has been cancelled. |
| * |
| * @since 2.0 |
| */ |
| protected void fireCanceled() { |
| Iterator iter = listeners |
| .getListeners(ButtonStateTransitionListener.class); |
| while (iter.hasNext()) |
| ((ButtonStateTransitionListener) iter.next()).canceled(); |
| } |
| |
| /** |
| * Notifies any listening ButtonStateTransitionListener that this button has |
| * been pressed. |
| * |
| * @since 2.0 |
| */ |
| protected void firePressed() { |
| Iterator iter = listeners |
| .getListeners(ButtonStateTransitionListener.class); |
| while (iter.hasNext()) |
| ((ButtonStateTransitionListener) iter.next()).pressed(); |
| } |
| |
| /** |
| * Notifies any listening ButtonStateTransitionListener that this button has |
| * been released. |
| * |
| * @since 2.0 |
| */ |
| protected void fireReleased() { |
| Iterator iter = listeners |
| .getListeners(ButtonStateTransitionListener.class); |
| while (iter.hasNext()) |
| ((ButtonStateTransitionListener) iter.next()).released(); |
| } |
| |
| /** |
| * Notifies any listening ButtonStateTransitionListeners that this button |
| * has resumed activity. |
| * |
| * @since 2.0 |
| */ |
| protected void fireResume() { |
| Iterator iter = listeners |
| .getListeners(ButtonStateTransitionListener.class); |
| while (iter.hasNext()) |
| ((ButtonStateTransitionListener) iter.next()).resume(); |
| } |
| |
| /** |
| * Notifies any listening ChangeListeners that this button's state has |
| * changed. |
| * |
| * @param property |
| * The name of the property that changed |
| * @since 2.0 |
| */ |
| protected void fireStateChanged(String property) { |
| Iterator iter = listeners.getListeners(ChangeListener.class); |
| ChangeEvent change = new ChangeEvent(this, property); |
| while (iter.hasNext()) |
| ((ChangeListener) iter.next()).handleStateChanged(change); |
| } |
| |
| /** |
| * Notifies any listening ButtonStateTransitionListeners that this button |
| * has suspended activity. |
| * |
| * @since 2.0 |
| */ |
| protected void fireSuspend() { |
| Iterator iter = listeners |
| .getListeners(ButtonStateTransitionListener.class); |
| while (iter.hasNext()) |
| ((ButtonStateTransitionListener) iter.next()).suspend(); |
| } |
| |
| boolean getFlag(int which) { |
| return (state & which) != 0; |
| } |
| |
| /** |
| * Returns the group to which this model belongs. |
| * |
| * @return The ButtonGroup to which this model belongs |
| * @since 2.0 |
| */ |
| public ButtonGroup getGroup() { |
| return group; |
| } |
| |
| /** |
| * Returns an object representing user data. |
| * |
| * @return User data |
| * @since 2.0 |
| */ |
| public Object getUserData() { |
| return data; |
| } |
| |
| /** |
| * Sets the firing behavior for this button. |
| * |
| * @since 2.0 |
| */ |
| protected void installFiringBehavior() { |
| setFiringBehavior(DEFAULT_FIRING_BEHAVIOR); |
| } |
| |
| /** |
| * Returns <code>true</code> if this button is armed. If a button is armed, |
| * it will fire an ActionPerformed when released. |
| * |
| * @return <code>true</code> if this button is armed |
| * @since 2.0 |
| */ |
| public boolean isArmed() { |
| return (state & ARMED_FLAG) != 0; |
| } |
| |
| /** |
| * Returns <code>true</code> if this button is enabled. |
| * |
| * @return <code>true</code> if this button is enabled |
| * @since 2.0 |
| */ |
| public boolean isEnabled() { |
| return (state & ENABLED_FLAG) != 0; |
| } |
| |
| /** |
| * Returns <code>true</code> if the mouse is over this button. |
| * |
| * @return <code>true</code> if the mouse is over this button |
| * @since 2.0 |
| */ |
| public boolean isMouseOver() { |
| return (state & MOUSEOVER_FLAG) != 0; |
| } |
| |
| /** |
| * Returns <code>true</code> if this button is pressed. |
| * |
| * @return <code>true</code> if this button is pressed |
| * @since 2.0 |
| */ |
| public boolean isPressed() { |
| return (state & PRESSED_FLAG) != 0; |
| } |
| |
| /** |
| * Returns the selection state of this model. If this model belongs to any |
| * group, the group is queried for selection state, else the flags are used. |
| * |
| * @return <code>true</code> if this button is selected |
| * @since 2.0 |
| */ |
| public boolean isSelected() { |
| if (group == null) { |
| return (state & SELECTED_FLAG) != 0; |
| } else { |
| return group.isSelected(this); |
| } |
| } |
| |
| /** |
| * Removes the given ActionListener. |
| * |
| * @param listener |
| * The ActionListener to remove |
| * @since 2.0 |
| */ |
| public void removeActionListener(ActionListener listener) { |
| listeners.removeListener(ActionListener.class, listener); |
| } |
| |
| /** |
| * Removes the given ChangeListener. |
| * |
| * @param listener |
| * The ChangeListener to remove |
| * @since 2.0 |
| */ |
| public void removeChangeListener(ChangeListener listener) { |
| listeners.removeListener(ChangeListener.class, listener); |
| } |
| |
| /** |
| * Removes the given ButtonStateTransitionListener. |
| * |
| * @param listener |
| * The ButtonStateTransitionListener to remove |
| * @since 2.0 |
| */ |
| public void removeStateTransitionListener( |
| ButtonStateTransitionListener listener) { |
| listeners.removeListener(ButtonStateTransitionListener.class, listener); |
| } |
| |
| /** |
| * Sets this button to be armed. If a button is armed, it will fire an |
| * ActionPerformed when released. |
| * |
| * @param value |
| * The armed state |
| * @since 2.0 |
| */ |
| public void setArmed(boolean value) { |
| if (isArmed() == value) |
| return; |
| if (!isEnabled()) |
| return; |
| setFlag(ARMED_FLAG, value); |
| fireStateChanged(ARMED_PROPERTY); |
| } |
| |
| /** |
| * Sets this button to be enabled. |
| * |
| * @param value |
| * The enabled state |
| * @since 2.0 |
| */ |
| public void setEnabled(boolean value) { |
| if (isEnabled() == value) |
| return; |
| if (!value) { |
| setMouseOver(false); |
| setArmed(false); |
| setPressed(false); |
| } |
| setFlag(ENABLED_FLAG, value); |
| fireStateChanged(ENABLED_PROPERTY); |
| } |
| |
| /** |
| * Sets the firing behavior for this button. |
| * {@link #DEFAULT_FIRING_BEHAVIOR} is the default behavior, where action |
| * performed events are not fired until the mouse button is released. |
| * {@link #REPEAT_FIRING_BEHAVIOR} causes action performed events to fire |
| * repeatedly until the mouse button is released. |
| * |
| * @param type |
| * The firing behavior type |
| * @since 2.0 |
| * |
| */ |
| public void setFiringBehavior(int type) { |
| if (firingBehavior != null) |
| removeStateTransitionListener(firingBehavior); |
| switch (type) { |
| case REPEAT_FIRING_BEHAVIOR: |
| firingBehavior = new RepeatFiringBehavior(); |
| break; |
| default: |
| firingBehavior = new DefaultFiringBehavior(); |
| } |
| addStateTransitionListener(firingBehavior); |
| } |
| |
| void setFlag(int flag, boolean value) { |
| if (value) |
| state |= flag; |
| else |
| state &= ~flag; |
| } |
| |
| /** |
| * Sets the ButtonGroup to which this model belongs to. Adds this model as a |
| * listener to the group. |
| * |
| * @param bg |
| * The group to which this model belongs. |
| * @since 2.0 |
| */ |
| public void setGroup(ButtonGroup bg) { |
| if (group == bg) |
| return; |
| if (group != null) |
| group.remove(this); |
| group = bg; |
| if (group != null) |
| group.add(this); |
| } |
| |
| /** |
| * Sets the mouseover property of this button. |
| * |
| * @param value |
| * The value the mouseover property will be set to |
| * @since 2.0 |
| */ |
| public void setMouseOver(boolean value) { |
| if (isMouseOver() == value) |
| return; |
| if (isPressed()) |
| if (value) |
| fireResume(); |
| else |
| fireSuspend(); |
| setFlag(MOUSEOVER_FLAG, value); |
| fireStateChanged(MOUSEOVER_PROPERTY); |
| } |
| |
| /** |
| * Sets the pressed property of this button. |
| * |
| * @param value |
| * The value the pressed property will be set to |
| * @since 2.0 |
| */ |
| public void setPressed(boolean value) { |
| if (isPressed() == value) |
| return; |
| setFlag(PRESSED_FLAG, value); |
| if (value) |
| firePressed(); |
| else { |
| if (isArmed()) |
| fireReleased(); |
| else |
| fireCanceled(); |
| } |
| fireStateChanged(PRESSED_PROPERTY); |
| } |
| |
| /** |
| * Sets this button to be selected. |
| * |
| * @param value |
| * The value the selected property will be set to |
| * @since 2.0 |
| */ |
| public void setSelected(boolean value) { |
| if (group == null) { |
| if (isSelected() == value) |
| return; |
| } else { |
| group.setSelected(this, value); |
| if (getFlag(SELECTED_FLAG) == isSelected()) |
| return; |
| } |
| setFlag(SELECTED_FLAG, value); |
| fireStateChanged(SELECTED_PROPERTY); |
| } |
| |
| /** |
| * Sets user data. |
| * |
| * @param data |
| * The user data |
| * @since 2.0 |
| */ |
| public void setUserData(Object data) { |
| this.data = data; |
| } |
| |
| class DefaultFiringBehavior extends ButtonStateTransitionListener { |
| public void released() { |
| fireActionPerformed(); |
| } |
| } |
| |
| class RepeatFiringBehavior extends ButtonStateTransitionListener { |
| protected static final int INITIAL_DELAY = 250, STEP_DELAY = 40; |
| |
| protected int stepDelay = INITIAL_DELAY, initialDelay = STEP_DELAY; |
| |
| protected Timer timer; |
| |
| public void pressed() { |
| fireActionPerformed(); |
| if (!isEnabled()) |
| return; |
| |
| timer = new Timer(); |
| TimerTask runAction = new Task(timer); |
| |
| timer.scheduleAtFixedRate(runAction, INITIAL_DELAY, STEP_DELAY); |
| } |
| |
| public void canceled() { |
| suspend(); |
| } |
| |
| public void released() { |
| suspend(); |
| } |
| |
| public void resume() { |
| timer = new Timer(); |
| |
| TimerTask runAction = new Task(timer); |
| |
| timer.scheduleAtFixedRate(runAction, STEP_DELAY, STEP_DELAY); |
| } |
| |
| public void suspend() { |
| if (timer == null) |
| return; |
| timer.cancel(); |
| timer = null; |
| } |
| } |
| |
| class Task extends TimerTask { |
| |
| private Timer timer; |
| |
| public Task(Timer timer) { |
| this.timer = timer; |
| } |
| |
| public void run() { |
| org.eclipse.swt.widgets.Display.getDefault().syncExec( |
| new Runnable() { |
| public void run() { |
| if (!isEnabled()) |
| timer.cancel(); |
| fireActionPerformed(); |
| } |
| }); |
| } |
| } |
| |
| } |