/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.widget.utility.gwt.client.ribbon;
import org.geomajas.gwt.client.action.toolbar.parameter.ButtonLayoutStyle;
import org.geomajas.widget.utility.common.client.action.RibbonColumnAware;
import org.geomajas.widget.utility.common.client.event.DisabledEvent;
import org.geomajas.widget.utility.common.client.event.EnabledEvent;
import org.geomajas.widget.utility.common.client.event.EnabledHandler;
import org.geomajas.widget.utility.common.client.event.HasEnabledHandlers;
import org.geomajas.widget.utility.common.client.ribbon.RibbonColumn;
import org.geomajas.widget.utility.gwt.client.action.ButtonAction;
import org.geomajas.widget.utility.gwt.client.action.RadioAction;
import org.geomajas.widget.utility.gwt.client.util.GuwLayout;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.Cursor;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.types.SelectionType;
import com.smartgwt.client.widgets.Img;
import com.smartgwt.client.widgets.StatefulCanvas;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.layout.HStack;
import com.smartgwt.client.widgets.layout.Layout;
import com.smartgwt.client.widgets.layout.VStack;
/**
* Implementation of the RibbonColumn interface that displays a single button. Instances of this class are initialized
* using a {@link ButtonAction} that determines the icon, title, tool-tip and click action. If the {@link ButtonAction}
* implements {@link RibbonColumnAware}, it will be passed a reference to this class. If the {@link ButtonAction}
* implements {@link HasEnabledHandlers}, the enabled/disabled state of this class will follow the enabled/disabled
* state of the action.
*
* @author Pieter De Graef
* @author Jan De Moerloose
*/
public class RibbonButton extends StatefulCanvas implements RibbonColumn {
public static final String PARAMETER_RADIOGROUP = "radioGroup";
public static final String PARAMETER_SELECTED = "selected";
public static final String PARAMETER_SHOWDISABLEDICON = "showDisabledIcon";
private boolean showTitles = true;
private TitleAlignment titleAlignment;
private int iconSize;
private ButtonAction buttonAction;
private Layout outer;
private Img icon;
private StatefulCanvas titleLabel;
private StatefulCanvas description;
// ------------------------------------------------------------------------
// Constructors:
// ------------------------------------------------------------------------
/**
* Initialize this object using a {@link ButtonAction}. This button will use the icon, title, tool-tip and click
* action that this {@link ButtonAction} provides. By default, an icon size of 24px will be used in combination with
* a BOTTOM title alignment.
*
* @param buttonAction
* The {@link ButtonAction} to use as template.
*/
public RibbonButton(final ButtonAction buttonAction) {
this(buttonAction, GuwLayout.ribbonColumnButtonIconSize, TitleAlignment.BOTTOM);
}
/**
* Initialize this object using a {@link ButtonAction}. This button will use the icon, title, tool-tip and click
* action that this {@link ButtonAction} provides.
*
* @param buttonAction
* The {@link ButtonAction} to use as template.
* @param iconSize
* The size (width & height) for the icon - in pixels.
* @param titleAlignment
* The alignment for the title (BOTTOM, RIGHT).
*/
public RibbonButton(final ButtonAction buttonAction, int iconSize, TitleAlignment titleAlignment) {
this.buttonAction = buttonAction;
this.iconSize = iconSize;
this.titleAlignment = titleAlignment;
setCanHover(true);
setShowHover(true);
setHoverWrap(false);
setHoverWidth(1);
setTooltip(buttonAction.getTooltip());
setShowRollOver(true);
setShowDown(true);
setShowDisabled(true);
setShowDisabledIcon(false);
String iconBaseUrl = buttonAction.getIcon();
icon = new Img(iconBaseUrl, iconSize, iconSize);
icon.setOverflow(Overflow.HIDDEN);
icon.setLayoutAlign(Alignment.CENTER);
titleLabel = new StatefulCanvas();
titleLabel.setContents(prepareTitle());
titleLabel.setOverflow(Overflow.VISIBLE);
description = new StatefulCanvas();
description.setContents(buttonAction.getTooltip());
description.setOverflow(Overflow.VISIBLE);
description.setAutoHeight();
description.setWidth100();
setBaseStyle("ribbonButton");
setCursor(Cursor.HAND);
if (buttonAction instanceof RadioAction) {
final RadioAction radioAction = (RadioAction) buttonAction;
setActionType(SelectionType.CHECKBOX);
setRadioGroup(radioAction.getRadioGroup());
addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
radioAction.setSelected(isSelected());
}
});
} else {
addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
buttonAction.onClick(null);
}
});
}
if (buttonAction instanceof RibbonColumnAware) {
((RibbonColumnAware) buttonAction).setRibbonColumn(this);
}
if (isEnabled()) {
if (buttonAction instanceof HasEnabledHandlers) {
HasEnabledHandlers h = (HasEnabledHandlers) buttonAction;
h.addEnabledHandler(new ActionEnabler());
setEnabled(h.isEnabled());
}
}
}
@Override
protected void onDraw() {
updateGui();
addChild(outer);
}
// ------------------------------------------------------------------------
// RibbonColumn implementation:
// ------------------------------------------------------------------------
@Override
public void setTitle(String title) {
buttonAction.setTitle(title);
titleLabel.setContents(prepareTitle());
}
@Override
public void setIcon(String iconUrl) {
buttonAction.setIcon(iconUrl);
icon.setSrc(iconUrl);
}
@Override
public void setDisabled(boolean disabled) {
super.setDisabled(disabled);
if (null != icon) {
icon.setDisabled(disabled);
}
if (null != titleLabel) {
titleLabel.setDisabled(disabled);
}
if (null != description) {
description.setDisabled(disabled);
}
}
@Override
public void setButtonBaseStyle(String buttonBaseStyle) {
setBaseStyle(buttonBaseStyle);
}
@Override
public void setShowTitles(boolean showTitles) {
this.showTitles = showTitles;
}
@Override
public boolean isShowTitles() {
return showTitles;
}
@Override
public void setTitleAlignment(TitleAlignment titleAlignment) {
this.titleAlignment = titleAlignment;
}
@Override
public TitleAlignment getTitleAlignment() {
return titleAlignment;
}
/**
* Get the {@link Layout} that is directly added to this button as a child (in {@link RibbonButton#onDraw()}).
*
* @return a {@link VStack} or {@link HStack} depending on the layout settings.
*/
public Layout getOuter() {
return outer;
}
@Override
public boolean isEnabled() {
return !isDisabled();
}
@Override
public void setEnabled(boolean enabled) {
setDisabled(!enabled);
}
@Override
public void configure(String key, String value) {
if (PARAMETER_SELECTED.equalsIgnoreCase(key)) {
if (buttonAction instanceof RadioAction) {
boolean selected = Boolean.parseBoolean(value);
setSelected(selected);
RadioAction ra = (RadioAction) buttonAction;
ra.setSelected(selected);
}
} else if (PARAMETER_RADIOGROUP.equalsIgnoreCase(key)) {
if (buttonAction instanceof RadioAction) {
addToRadioGroup(value);
RadioAction ra = (RadioAction) buttonAction;
ra.setRadioGroup(value);
}
} else if (PARAMETER_SHOWDISABLEDICON.equalsIgnoreCase(key)) {
icon.setShowDisabled(Boolean.parseBoolean(value));
} else {
buttonAction.configure(key, value);
}
}
// ------------------------------------------------------------------------
// Class specific getters and setters:
// ------------------------------------------------------------------------
@Override
public int getIconSize() {
return iconSize;
}
@Override
public void setIconSize(int iconSize) {
this.iconSize = iconSize;
icon.setHeight(iconSize);
icon.setWidth(iconSize);
}
/**
* Return the button action that is used as a template for this button.
*
* @return The button action that is used as a template for this button.
*/
public ButtonAction getButtonAction() {
return buttonAction;
}
// ------------------------------------------------------------------------
// Private methods:
// ------------------------------------------------------------------------
/**
* Update the GUI to reflect the settings.
*/
protected void updateGui() {
ButtonLayoutStyle buttonButtonLayoutStyle = buttonAction.getButtonLayoutStyle();
if (ButtonLayoutStyle.ICON_TITLE_AND_DESCRIPTION.equals(buttonButtonLayoutStyle)) {
buildGuiWithDescription();
} else { // LayoutParameter.Layout.ICON_AND_TITLE || null || ...
setWidth(50);
if (titleAlignment.equals(TitleAlignment.BOTTOM)) {
setHeight100();
outer = new VStack();
outer.setOverflow(Overflow.VISIBLE);
outer.setWidth(GuwLayout.ribbonButtonWidth);
outer.setAutoHeight();
outer.addMember(icon);
if (showTitles && !GuwLayout.hideRibbonTitles) {
titleLabel.setBaseStyle(getBaseStyle() + "LargeTitle");
titleLabel.setAutoHeight();
titleLabel.setWidth(GuwLayout.ribbonButtonWidth);
outer.addMember(titleLabel);
}
outer.setAlign(Alignment.CENTER);
} else {
setAutoHeight();
outer = new HStack(GuwLayout.ribbonButtonInnerMargin);
outer.setOverflow(Overflow.VISIBLE);
outer.setWidth100();
outer.setAutoHeight();
outer.addMember(icon);
if (showTitles) {
titleLabel.setBaseStyle(getBaseStyle() + "SmallTitle");
titleLabel.setAutoHeight();
titleLabel.setAutoWidth();
outer.addMember(titleLabel);
}
}
}
}
private void buildGuiWithDescription() {
setCanHover(false);
description.setBaseStyle(getBaseStyle() + "Description");
description.setAutoHeight();
description.setWidth100();
VStack inner = new VStack();
inner.setWidth("*");
inner.setOverflow(Overflow.VISIBLE);
inner.setAutoHeight();
if (showTitles) {
titleLabel.setBaseStyle(getBaseStyle() + "SmallTitle");
titleLabel.setAutoHeight();
titleLabel.setWidth100();
inner.addMember(titleLabel);
}
inner.addMember(description);
outer = new HStack(GuwLayout.ribbonButtonInnerMargin);
outer.setOverflow(Overflow.VISIBLE);
outer.setWidth100();
outer.setAutoHeight();
outer.setLayoutAlign(Alignment.CENTER);
outer.addMember(icon);
outer.addMember(inner);
}
private String prepareTitle() {
String title = buttonAction.getTitle() == null ? buttonAction.getTooltip() : buttonAction.getTitle();
if (title == null) {
title = "??";
} else {
title = title.trim();
}
return title;
}
/**
* Applies state changes of the action to this widget.
*
* @author Jan De Moerloose
*/
class ActionEnabler implements EnabledHandler {
@Override
public void onEnabled(EnabledEvent event) {
setEnabled(true);
}
@Override
public void onDisabled(DisabledEvent event) {
setEnabled(false);
}
}
}