gwt.material.design.addins.client.rating.MaterialRating Maven / Gradle / Ivy
package gwt.material.design.addins.client.rating;
/*
* #%L
* GwtMaterial
* %%
* Copyright (C) 2015 - 2017 GwtMaterialDesign
* %%
* 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.
* #L%
*/
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.HasValue;
import gwt.material.design.addins.client.base.constants.AddinsCssName;
import gwt.material.design.client.base.MaterialWidget;
import gwt.material.design.client.constants.Color;
import gwt.material.design.client.constants.IconType;
import gwt.material.design.client.ui.MaterialIcon;
import java.util.LinkedList;
import java.util.List;
/**
*
* MaterialRating is the component used by the 5-star rating system, for
* example, allowing users to easily express their opinion about a product,
* review, video and so on.
*
*
* By default, it uses the {@link IconType#STAR} to represent the selected
* rating, but other icons can be set using the
* {@link #setSelectedRatingIcon(IconType)} method.
*
*
*
XML Namespace Declaration
*
*
* {@code
* xmlns:ma='urn:import:gwt.material.design.addins.client'
* }
*
*
*
UiBinder Usage:
*
*
* {@code
*
* }
*
*
* To use different icons, for instance, hearts, you can set:
*
*
* {@code
*
* }
*
*
* You can also set the maximum rating (the default is 5):
*
*
* {@code
*
* }
*
*
*
Example Java Usage:
*
*
* {@code
* MaterialRating rating = ... //create using new or using UiBinder
* rating.addValueChangeHandler(...); // MaterialRating implements HasValue
* rating.setEditable(false); // disables user interaction
* rating.setValue(2); // directly sets the desired rating
* int selectedValue = rating.getValue(); // retrieves the selected rating
* }
*
*
*
Custom styling:
*
* You use change the MaterialRating style by using the
* material-rating
CSS class. Selected rating icons have the
* material-rating-selected
CSS class, and unselected the
* material-rating-unselected
CSS class.
*
*
* @author gilberto-torrezan
*/
public class MaterialRating extends MaterialWidget implements HasValue {
private boolean editable = true;
private int currentRating = 0;
private int maxRating = 5;
private IconType selectedRatingIcon = IconType.STAR;
private IconType unselectedRatingIcon = IconType.STAR_BORDER;
private List iconList = new LinkedList<>();
/**
* Default constructor.
*/
public MaterialRating() {
super(DOM.createDiv(), AddinsCssName.MATERIAL_RATING);
}
public MaterialRating(IconType selectedRatingIcon, IconType unselectedRatingIcon, Color textColor) {
this();
setSelectedRatingIcon(selectedRatingIcon);
setUnselectedRatingIcon(unselectedRatingIcon);
}
public MaterialRating(IconType selectedRatingIcon, IconType unselectedRatingIcon, Color textColor, Integer value) {
this(selectedRatingIcon, unselectedRatingIcon, textColor);
setValue(value);
}
public MaterialRating(IconType selectedRatingIcon, IconType unselectedRatingIcon, Color textColor, Integer value, Integer maxRating) {
this(selectedRatingIcon, unselectedRatingIcon, textColor, value);
setMaxRating(maxRating);
}
@Override
protected void onLoad() {
super.onLoad();
revalidateLayout();
}
/**
* Sets the maximum number of icons to show - which represents the maximum
* selectable rating. The default is 5.
*
* @param maxRating The maximum selectable rating for this component
*/
public void setMaxRating(int maxRating) {
this.maxRating = maxRating;
revalidateLayout();
}
/**
* Returns the maximum selectable rating in this component.
* The default is 5.
*
* @return The maximum rating
*/
public int getMaxRating() {
return maxRating;
}
/**
* Sets the {@link IconType} to be used to represent the selected ratings.
* The default is {@link IconType#STAR}.
*
* @param selectedRatingIcon The icon of the selected ratings
*/
public void setSelectedRatingIcon(IconType selectedRatingIcon) {
this.selectedRatingIcon = selectedRatingIcon;
revalidateLayout();
}
/**
* Returns the {@link IconType} used to represent the selected ratings. The
* default is {@link IconType#STAR}.
*
* @return The icon for selected ratings
*/
public IconType getSelectedRatingIcon() {
return selectedRatingIcon;
}
/**
* Sets the {@link IconType} to be used to represent the not selected
* ratings. The default is {@link IconType#STAR_BORDER}.
*
* @param unselectedRatingIcon The icon of the unselected ratings
*/
public void setUnselectedRatingIcon(IconType unselectedRatingIcon) {
this.unselectedRatingIcon = unselectedRatingIcon;
revalidateLayout();
}
/**
* Returns the {@link IconType} used to represent the not selected ratings.
* The default is {@link IconType#STAR_BORDER}.
*
* @return The icon for unselected ratings
*/
public IconType getUnselectedRatingIcon() {
return unselectedRatingIcon;
}
@Override
public void clear() {
iconList.clear();
super.clear();
}
/**
* Method called internally by the component to re-validate the number of
* icons when the maximum rating is changed.
*/
protected void revalidateLayout() {
for (MaterialIcon icon : iconList) {
icon.removeFromParent();
}
iconList.clear();
// same mouse-out handler for all icons
MouseOutHandler outHandler = event -> {
if (!isEnabled() || !isEditable()) {
return;
}
revalidateSelection(currentRating);
};
for (int i = 0; i < maxRating; i++) {
final int rating = i + 1;
MaterialIcon icon = new MaterialIcon(unselectedRatingIcon);
registerHandler(icon.addClickHandler(event -> {
if (!isEnabled() || !isEditable()) {
return;
}
setValue(rating, true);
}));
registerHandler(icon.addMouseOverHandler(event -> {
if (!isEnabled() || !isEditable()) {
return;
}
revalidateSelection(rating);
}));
registerHandler(icon.addMouseOutHandler(outHandler));
add(icon);
iconList.add(icon);
}
revalidateSelection(currentRating);
}
/**
* Method called internally by the component to revalidade selections by the
* user, switching the icons accordingly.
*/
protected void revalidateSelection(int rating) {
for (MaterialIcon icon : iconList) {
icon.removeStyleName(AddinsCssName.MATERIAL_RATING_UNSELECTED);
icon.removeStyleName(AddinsCssName.MATERIAL_RATING_SELECTED);
}
for (int i = 0; i < rating && i < iconList.size(); i++) {
MaterialIcon icon = iconList.get(i);
icon.setIconType(selectedRatingIcon);
icon.addStyleName(AddinsCssName.MATERIAL_RATING_SELECTED);
}
for (int i = rating; i < iconList.size(); i++) {
MaterialIcon icon = iconList.get(i);
icon.setIconType(unselectedRatingIcon);
icon.addStyleName(AddinsCssName.MATERIAL_RATING_UNSELECTED);
}
}
@Override
public Integer getValue() {
return currentRating;
}
@Override
public void setValue(Integer value) {
setValue(value, false);
}
@Override
public void setValue(Integer value, boolean fireEvents) {
currentRating = value;
revalidateSelection(currentRating);
if (fireEvents) {
ValueChangeEvent.fire(this, value);
}
}
/**
* Sets whether the user can interact with the component or not.
* Non-editable MaterialRatings can only show values, not allowing users to
* change them. The default is true
(editable).
*
* @param editable true
to allow the user change the state of the component,
* false
otherwise.
*/
public void setEditable(boolean editable) {
this.editable = editable;
}
/**
* Returns whether the component is editable by the user. The default is
* true
(editable).
*
* @return true
if the component is editable by the user,
* false
otherwise'
*/
public boolean isEditable() {
return editable;
}
@Override
public HandlerRegistration addValueChangeHandler(ValueChangeHandler handler) {
return addHandler(handler, ValueChangeEvent.getType());
}
}