/**
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.waveprotocol.wave.client.widget.button;
import org.waveprotocol.wave.client.widget.button.ButtonDisplay.ButtonState;
/**
* Implements the logic for buttons that only have one associated action, that
* is, buttons that immediately return to their original state when they are
* clicked.
*
*/
public class ClickButton implements UniversalButton<ClickButtonController> {
/**
* The visual representation of this button.
*/
protected ButtonDisplay buttonDisplay = null;
/**
* Is the mouse currently over the button?
*/
protected boolean isMouseOver = false;
/**
* Is the mouse button currently down?
*/
protected boolean isMouseDown = false;
/**
* Is this button disabled?
*/
protected boolean isDisabled = false;
/**
* Listener for click events (provided by users to make the button do
* something).
*/
protected ClickButtonListener clickListener;
/**
* Listener for click-when-disabled events.
*/
protected ClickWhenDisabledListener clickWhenDisabledListener;
/**
* Implementation of the public interface for controlling this button.
*/
protected ClickButtonController controller = new ClickButtonController() {
@Override
public void setClickButtonListener(ClickButtonListener listener) {
clickListener = listener;
}
@Override
public void setClickWhenDisabledListener(ClickWhenDisabledListener listener) {
clickWhenDisabledListener = listener;
}
@Override
public void setDisabled(boolean isDisabled) {
if (ClickButton.this.isDisabled != isDisabled) {
ClickButton.this.isDisabled = isDisabled;
updateState();
}
}
@Override
public void setTooltip(String tooltip) {
ClickButton.this.buttonDisplay.setTooltip(tooltip);
}
@Override
public void setText(String text) {
ClickButton.this.buttonDisplay.setText(text);
}
};
/**
* Listener for click events from a button.
*
*/
public interface ClickButtonListener {
/**
* Called when a click event occurs on a button.
*/
void onClick();
}
/**
* Listener for click events from a button when it's disabled.
*
* TODO(kalman): Put in ClickButtonListener, provide vacuous implementation.
*/
public interface ClickWhenDisabledListener {
void onClickWhenDisabled();
}
/**
* Create the listener on object creation so it can be used later
*/
protected MouseListener mouseListener = new MouseListener() {
/** {@inheritDoc} */
public void onMouseDown() {
isMouseDown = true;
updateState();
}
/** {@inheritDoc} */
public void onMouseEnter() {
isMouseOver = true;
updateState();
}
/** {@inheritDoc} */
public void onMouseLeave() {
isMouseOver = false;
isMouseDown = false;
updateState();
}
/** {@inheritDoc} */
public void onMouseUp() {
isMouseDown = false;
updateState();
}
/** {@inheritDoc} */
public void onClick() {
if (isDisabled) {
if (clickWhenDisabledListener != null) {
clickWhenDisabledListener.onClickWhenDisabled();
}
return;
}
if (clickListener != null) {
clickListener.onClick();
}
}
};
public ClickButton(ButtonDisplay button) {
setButtonDisplay(button);
button.setUiListener(getUiEventListener());
}
public ClickButton() { }
/** {@inheritDoc} */
public MouseListener getUiEventListener() {
return mouseListener;
}
/**
* Updates the visual state of the button to reflect the current logical
* state.
*/
protected void updateState() {
if (isDisabled) {
setState(ButtonState.DISABLED);
return;
}
if (isMouseOver) {
setState(isMouseDown ? ButtonDisplay.ButtonState.DOWN : ButtonDisplay.ButtonState.HOVER);
} else {
setState(ButtonDisplay.ButtonState.NORMAL);
}
}
/**
* Sets a new state for this button and notifies the display.
*
* @param state The new state for this button.
*/
private void setState(ButtonDisplay.ButtonState state) {
// NOTE(patcoleman): Does not check here to see whether the new state is the same
// as the current state - possible optimisation can be added to return on NOOP? i.e.
// if(newState.equals(state)) return;
if (buttonDisplay != null) {
buttonDisplay.setState(state);
}
}
/** {@inheritDoc} */
public void setButtonDisplay(ButtonDisplay controlledButton) {
this.buttonDisplay = controlledButton;
updateState();
}
/**
* @param listener Callback to be fired when the button is clicked.
*/
public void setClickButtonListener(ClickButtonListener listener) {
this.clickListener = listener;
}
/** {@inheritDoc} */
public ClickButtonController getController() {
return controller;
}
public static void attachListenerTo(ButtonDisplay view,
ClickButton.ClickButtonListener listener) {
ClickButton buttonLogic = new ClickButton();
buttonLogic.setClickButtonListener(listener);
buttonLogic.setButtonDisplay(view);
view.setUiListener(buttonLogic.getUiEventListener());
}
}