com.vaadin.ui.AbstractColorPicker Maven / Gradle / Ivy
/*
* Copyright (C) 2000-2024 Vaadin Ltd
*
* This program is available under Vaadin Commercial License and Service Terms.
*
* See for the full
* license.
*/
package com.vaadin.ui;
import java.io.Serializable;
import java.util.Collection;
import java.util.Locale;
import java.util.Objects;
import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;
import com.vaadin.shared.ui.colorpicker.AbstractColorPickerState;
import com.vaadin.shared.ui.colorpicker.Color;
import com.vaadin.shared.ui.colorpicker.ColorPickerServerRpc;
import com.vaadin.ui.components.colorpicker.ColorPickerPopup;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
/**
* An abstract class that defines default implementation for a color picker
* component.
*
* @since 7.0.0
*/
public abstract class AbstractColorPicker extends AbstractField {
/**
* Interface for converting 2d-coordinates to a Color.
*/
public interface Coordinates2Color extends Serializable {
/**
* Calculates a color from coordinates.
*
* @param x
* the x-coordinate
* @param y
* the y-coordinate
*
* @return the color
*/
public Color calculate(int x, int y);
/**
* Calculates coordinates from a color.
*
* @param c
* the c
*
* @return the integer array with the coordinates
*/
public int[] calculate(Color c);
}
/**
* The style of the color picker popup.
*/
public enum PopupStyle {
/** A full popup with all tabs visible. */
POPUP_NORMAL("normal"),
/** A simple popup with only the swatches (palette) tab. */
POPUP_SIMPLE("simple");
private final String style;
PopupStyle(String styleName) {
style = styleName;
}
@Override
public String toString() {
return style;
}
}
protected static final String STYLENAME_DEFAULT = "v-colorpicker";
protected static final String STYLENAME_BUTTON = "v-button";
protected static final String STYLENAME_AREA = "v-colorpicker-area";
protected PopupStyle popupStyle = PopupStyle.POPUP_NORMAL;
private ColorPickerPopup window;
/** The currently selected color. */
protected Color color;
private UI parent;
private String popupCaption = null;
private int positionX = 0;
private int positionY = 0;
protected boolean rgbVisible = true;
protected boolean hsvVisible = true;
protected boolean swatchesVisible = true;
protected boolean historyVisible = true;
protected boolean textfieldVisible = true;
private boolean modal;
private ColorPickerServerRpc rpc = new ColorPickerServerRpc() {
@Override
public void openPopup(boolean openPopup) {
showPopup(openPopup);
}
@Override
public void changeColor(String col) {
Color valueC = new Color(
Integer.parseInt(col.substring(1, col.length()), 16));
color = valueC;
setValue(color, true);
}
};
/**
* Instantiates a new color picker.
*/
public AbstractColorPicker() {
this("Colors", Color.WHITE);
}
/**
* Instantiates a new color picker.
*
* @param popupCaption
* the caption of the popup window
*/
public AbstractColorPicker(String popupCaption) {
this(popupCaption, Color.WHITE);
}
/**
* Instantiates a new color picker.
*
* @param popupCaption
* the caption of the popup window
* @param initialColor
* the initial color
*/
public AbstractColorPicker(String popupCaption, Color initialColor) {
super();
registerRpc(rpc);
setValue(initialColor);
this.popupCaption = popupCaption;
setDefaultStyles();
setCaption("");
}
/**
* Returns the current selected color of this color picker.
*
* @return the selected color, not null
*/
@Override
public Color getValue() {
return color;
}
/**
* Sets the selected color of this color picker. If the new color is not
* equal to getValue(), fires a {@link ValueChangeEvent}.
*
* @param color
* the new selected color, not null
* @throws NullPointerException
* if {@code color} is {@code null}
*/
@Override
public void setValue(Color color) {
Objects.requireNonNull(color, "color cannot be null");
super.setValue(color);
if (window != null) {
window.setValue(color);
}
}
/**
* Set true if the component should show a default caption (css-code for the
* currently selected color, e.g. #ffffff) when no other caption is
* available.
*
* @param enabled
* {@code true} to enable the default caption, {@code false} to
* disable
*/
public void setDefaultCaptionEnabled(boolean enabled) {
getState().showDefaultCaption = enabled;
}
/**
* Returns true if the component shows the default caption (css-code for the
* currently selected color, e.g. #ffffff) if no other caption is available.
*
* @return {@code true} if the default caption is enabled, {@code false}
* otherwise
*/
public boolean isDefaultCaptionEnabled() {
return getState(false).showDefaultCaption;
}
/**
* Sets the position of the popup window.
*
* @param x
* the x-coordinate
* @param y
* the y-coordinate
*/
public void setPosition(int x, int y) {
positionX = x;
positionY = y;
if (window != null) {
window.setPositionX(x);
window.setPositionY(y);
}
}
/**
* Sets the style of the popup window.
*
* @param style
* the popup window style
*/
public void setPopupStyle(PopupStyle style) {
popupStyle = style;
switch (style) {
case POPUP_NORMAL:
setRGBVisibility(true);
setHSVVisibility(true);
setSwatchesVisibility(true);
setHistoryVisibility(true);
setTextfieldVisibility(true);
break;
case POPUP_SIMPLE:
setRGBVisibility(false);
setHSVVisibility(false);
setSwatchesVisibility(true);
setHistoryVisibility(false);
setTextfieldVisibility(false);
break;
default:
assert false : "Unknown popup style " + style;
}
}
/**
* Gets the style for the popup window.
*
* @since 7.5.0
* @return popup window style
*/
public PopupStyle getPopupStyle() {
return popupStyle;
}
/**
* Sets the visibility of the RGB tab.
*
* @param visible
* {@code true} to display the RGB tab, {@code false} to hide it
*/
public void setRGBVisibility(boolean visible) {
if (!visible && !hsvVisible && !swatchesVisible) {
throw new IllegalArgumentException("Cannot hide all tabs.");
}
rgbVisible = visible;
if (window != null) {
window.setRGBTabVisible(visible);
}
}
/**
* Gets the visibility of the RGB Tab.
*
* @since 7.5.0
* @return visibility of the RGB tab
*/
public boolean getRGBVisibility() {
return rgbVisible;
}
/**
* Sets the visibility of the HSV Tab.
*
* @param visible
* {@code true} to display the HSV tab, {@code false} to hide it
*/
public void setHSVVisibility(boolean visible) {
if (!visible && !rgbVisible && !swatchesVisible) {
throw new IllegalArgumentException("Cannot hide all tabs.");
}
hsvVisible = visible;
if (window != null) {
window.setHSVTabVisible(visible);
}
}
/**
* Gets the visibility of the HSV tab.
*
* @since 7.5.0
* @return {@code true} if the HSV tab is currently displayed, {@code false}
* otherwise
*/
public boolean getHSVVisibility() {
return hsvVisible;
}
/**
* Sets the visibility of the Swatches (palette) tab.
*
* @param visible
* {@code true} to display the Swatches tab, {@code false} to
* hide it
*/
public void setSwatchesVisibility(boolean visible) {
if (!visible && !hsvVisible && !rgbVisible) {
throw new IllegalArgumentException("Cannot hide all tabs.");
}
swatchesVisible = visible;
if (window != null) {
window.setSwatchesTabVisible(visible);
}
}
/**
* Gets the visibility of the Swatches (palette) tab.
*
* @since 7.5.0
* @return {@code true} if the Swatches tab is currently displayed,
* {@code false} otherwise
*/
public boolean getSwatchesVisibility() {
return swatchesVisible;
}
/**
* Sets the visibility of the color history, displaying recently picked
* colors.
*
* @param visible
* {@code true} to display the history, {@code false} to hide it
*/
public void setHistoryVisibility(boolean visible) {
historyVisible = visible;
if (window != null) {
window.setHistoryVisible(visible);
}
}
/**
* Gets the visibility of the Color history.
*
* @since 7.5.0
* @return {@code true} if the history is currently displayed, {@code false}
* otherwise
*/
public boolean getHistoryVisibility() {
return historyVisible;
}
/**
* Sets the visibility of the CSS color code text field.
*
* @param visible
* {@code true} to display the CSS text field, {@code false} to
* hide it
*/
public void setTextfieldVisibility(boolean visible) {
textfieldVisible = visible;
if (window != null) {
window.setPreviewVisible(visible);
}
}
/**
* Gets the visibility of CSS color code text field.
*
* @since 7.5.0
* @return {@code true} if the CSS text field is currently displayed,
* {@code false} otherwise
*/
public boolean getTextfieldVisibility() {
return textfieldVisible;
}
@Override
protected AbstractColorPickerState getState() {
return (AbstractColorPickerState) super.getState();
}
@Override
protected AbstractColorPickerState getState(boolean markAsDirty) {
return (AbstractColorPickerState) super.getState(markAsDirty);
}
/**
* Sets the default styles of the component.
*/
protected abstract void setDefaultStyles();
/**
* Shows a popup-window for color selection.
*/
public void showPopup() {
showPopup(true);
}
/**
* Hides a popup-window for color selection.
*/
public void hidePopup() {
showPopup(false);
}
/**
* Shows or hides the popup window depending on the given parameter. If
* there is no such window yet, one is created.
*
* @param open
* {@code true} to display the popup, {@code false} to hide it
*/
protected void showPopup(boolean open) {
if (open && !isReadOnly()) {
if (parent == null) {
parent = getUI();
}
Color color = getValue();
if (window == null) {
window = new ColorPickerPopup(color);
window.setCaption(popupCaption);
window.setRGBTabVisible(rgbVisible);
window.setHSVTabVisible(hsvVisible);
window.setSwatchesTabVisible(swatchesVisible);
window.setHistoryVisible(historyVisible);
window.setPreviewVisible(textfieldVisible);
window.addCloseListener(
event -> getState().popupVisible = false);
window.addValueChangeListener(
event -> setValue(event.getValue(), true));
// wait for the attach so that existing history can be fetched
// from the session
window.addAttachListener(
event -> window.getHistory().setValue(getValue()));
window.setPositionX(positionX);
window.setPositionY(positionY);
window.setVisible(true);
window.setValue(color);
window.setModal(modal);
parent.addWindow(window);
window.focus();
} else if (!parent.equals(window.getParent())) {
window.setRGBTabVisible(rgbVisible);
window.setHSVTabVisible(hsvVisible);
window.setSwatchesTabVisible(swatchesVisible);
window.setHistoryVisible(historyVisible);
window.setPreviewVisible(textfieldVisible);
window.setValue(color);
window.setVisible(true);
window.setModal(modal);
parent.addWindow(window);
window.focus();
}
window.setValue(color);
} else if (window != null) {
if (!isReadOnly()) {
window.getHistory().setValue(color);
}
window.setVisible(false);
parent.removeWindow(window);
}
getState().popupVisible = open;
}
@Override
public void readDesign(Element design, DesignContext designContext) {
super.readDesign(design, designContext);
Attributes attributes = design.attributes();
if (design.hasAttr("color")) {
// Ignore the # character
String hexColor = DesignAttributeHandler
.readAttribute("color", attributes, String.class)
.substring(1);
doSetValue(new Color(Integer.parseInt(hexColor, 16)));
}
if (design.hasAttr("popup-style")) {
setPopupStyle(PopupStyle.valueOf("POPUP_"
+ attributes.get("popup-style").toUpperCase(Locale.ROOT)));
}
if (design.hasAttr("position")) {
String[] position = attributes.get("position").split(",");
setPosition(Integer.parseInt(position[0]),
Integer.parseInt(position[1]));
}
}
@Override
public void writeDesign(Element design, DesignContext designContext) {
super.writeDesign(design, designContext);
Attributes attribute = design.attributes();
DesignAttributeHandler.writeAttribute("color", attribute,
getValue().getCSS(), Color.WHITE.getCSS(), String.class,
designContext);
DesignAttributeHandler.writeAttribute("popup-style", attribute,
popupStyle == PopupStyle.POPUP_NORMAL ? "normal" : "simple",
"normal", String.class, designContext);
DesignAttributeHandler.writeAttribute("position", attribute,
positionX + "," + positionY, "0,0", String.class,
designContext);
}
@Override
protected Collection getCustomAttributes() {
Collection result = super.getCustomAttributes();
result.add("color");
result.add("position");
result.add("popup-style");
return result;
}
@Override
protected void doSetValue(Color color) {
this.color = color;
getState().color = color.getCSS();
}
@Override
public Color getEmptyValue() {
return Color.WHITE;
}
/**
* Sets ColorPicker modality. When a modal ColorPicker is open, components
* outside that ColorPicker cannot be accessed.
*
* Note: It must be set to {@code true} if ColorPicker is a child of modal
* {@link Window}
*
*
* @see Window#setModal
* @since 8.4.1
* @param modal
* true if modality is to be turned on
*/
public void setModal(boolean modal) {
this.modal = modal;
}
/**
* Checks the modality of the dialog.
*
* @see #setModal(boolean)
* @since 8.4.1
* @return true if the dialog is modal, false otherwise
*/
public boolean isModal() {
return this.modal;
}
}