/*
* @(#)ColorSliderModel.java
*
* Copyright (c) 2005-2010 Werner Randelshofer, Immensee, Switzerland.
* All rights reserved.
*
* You may not use, copy or modify this file, except in compliance with the
* license agreement you entered into with Werner Randelshofer.
* For details see accompanying license terms.
*/
package ch.randelshofer.quaqua.colorchooser;
import java.awt.*;
import java.io.Serializable;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
/**
* Abstract super class for ColorModels which can be used in conjunction with
* ColorSliderUI user interface delegates.
* <p>
* Colors are represented as arrays of color components represented as
* BoundedRangeModel's. Each BoundedRangeModel can be visualized using a JSlider
* having a ColorSliderUI.
*
* @author Werner Randelshofer
* @version $Id: ColorSliderModel.java 363 2010-11-21 17:41:04Z wrandelshofer $
*/
public abstract class ColorSliderModel implements Serializable {
/**
* JSlider's associated to this ColorSliderModel.
*/
private LinkedList sliders = new LinkedList();
/**
* ChangeListener's listening to changes in this ColorSliderModel.
*/
private LinkedList listeners = new LinkedList();
/**
* Components of the color model.
*/
protected DefaultBoundedRangeModel[] components;
/**
* Speed optimization. This way, we do not need to create a new array
* for each invocation of method getInterpolatedRGB().
* Note: This variable must not use in reentrant methods.
*/
protected int[] values;
/**
* Creates a new ColorSliderModel with an array of BoundedRangeModel's
* for the color components.
*/
protected ColorSliderModel(DefaultBoundedRangeModel[] components) {
this.components = components;
values = new int[components.length];
for (int i=0; i < components.length; i++) {
final int componentIndex = i;
components[i].addChangeListener(
new ChangeListener() {
public void stateChanged(ChangeEvent e) {
fireColorChanged(componentIndex);
fireStateChanged();
}
});
}
}
/**
* Configures a JSlider for this ColorSliderModel.
* If the JSlider is already configured for another ColorSliderModel,
* it is unconfigured first.
*/
public void configureColorSlider(int component, JSlider slider) {
if (slider.getClientProperty("ColorSliderModel") != null) {
((ColorSliderModel) slider.getClientProperty("ColorSliderModel"))
.unconfigureColorSlider(slider);
}
if ( ! (slider.getUI() instanceof ColorSliderUI)) {
slider.setUI(new ColorSliderUI(slider));
}
slider.setModel(getBoundedRangeModel(component));
slider.putClientProperty("ColorSliderModel", this);
slider.putClientProperty("ColorComponentIndex", component);
addColorSlider(slider);
}
/**
* Unconfigures a JSlider from this ColorSliderModel.
*/
public void unconfigureColorSlider(JSlider slider) {
if (slider.getClientProperty("ColorSliderModel") == this) {
// XXX - This creates a NullPointerException ??
//slider.setUI((SliderUI) UIManager.getUI(slider));
slider.setModel(new DefaultBoundedRangeModel());
slider.putClientProperty("ColorSliderModel", null);
slider.putClientProperty("ColorComponentIndex", null);
removeColorSlider(slider);
}
}
/**
* Returns the number of components of this color component model.
*/
public int getComponentCount() {
return components.length;
}
/**
* Returns the bounded range model of the specified color component.
*/
public DefaultBoundedRangeModel getBoundedRangeModel(int component) {
return components[component];
}
/**
* Returns the value of the specified color component.
*/
public int getValue(int component) {
return components[component].getValue();
}
/**
* Sets the value of the specified color component.
*/
public void setValue(int component, int value) {
components[component].setValue(value);
}
/**
* Returns an interpolated RGB value by using the values of the color
* components of this ColorSliderModel except for the component specified
* as an argument. For this component the ratio between zero
* and the maximum of its BoundedRangeModel is used.
*/
public int getInterpolatedRGB(int component, float ratio) {
for (int i=0, n = getComponentCount(); i < n; i++) {
values[i] = components[i].getValue();
}
values[component] = (int) (ratio * components[component].getMaximum());
return toRGB(values);
}
protected void addColorSlider(JSlider slider) {
sliders.add(slider);
}
protected void removeColorSlider(JSlider slider) {
sliders.remove(slider);
}
public void addChangeListener(ChangeListener l) {
listeners.add(l);
}
public void removeChangeListener(ChangeListener l) {
listeners.remove(l);
}
protected void fireColorChanged(int componentIndex) {
Integer index = componentIndex;
Color value = getColor();
for (Iterator i = sliders.iterator(); i.hasNext(); ) {
JSlider slider = (JSlider) i.next();
slider.putClientProperty("ColorComponentChange", index);
slider.putClientProperty("ColorComponentValue", value);
}
}
public void fireStateChanged() {
ChangeEvent event = new ChangeEvent(this);
for (Iterator i=listeners.iterator(); i.hasNext(); ) {
ChangeListener l = (ChangeListener) i.next();
l.stateChanged(event);
}
}
public Color getColor() {
return new Color(getRGB());
}
public void setColor(Color color) {
int rgb = color.getRGB();
if (rgb != getRGB()) {
setRGB(rgb);
}
}
public abstract void setRGB(int rgb);
public abstract int getRGB();
public abstract int toRGB(int[] values);
}