/**
* Copyright (C) 2015 Valkyrie RCP
*
* 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.valkyriercp.form.builder;
import org.jdesktop.swingx.JXDatePicker;
import org.valkyriercp.binding.form.FormModel;
import org.valkyriercp.core.Messagable;
import org.valkyriercp.core.Message;
import org.valkyriercp.core.Severity;
import org.valkyriercp.form.HasValidationComponent;
import javax.swing.*;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;
/**
* Adds an "overlay" to a component that is triggered by a validation event for
* JTextComponents. When an error is triggered, the background color of the
* component is changed to the color set in {@link #setErrorColor(java.awt.Color)}. (The
* default color is a very light red.)
*
* @author oliverh
*/
public class ColorValidationInterceptorFactory implements FormComponentInterceptorFactory
{
private static final Color DEFAULT_ERROR_COLOR = new Color(255, 220, 220);
private static final Color DEFAULT_WARNING_COLOR = new Color(255, 255, 160);
private Map<Severity, Color> colorMap = new HashMap<Severity, Color>();
public ColorValidationInterceptorFactory()
{
colorMap.put(Severity.ERROR, DEFAULT_ERROR_COLOR);
colorMap.put(Severity.WARNING, DEFAULT_WARNING_COLOR);
}
public void setColorMap(Map<Severity, Color> colorMap)
{
this.colorMap = colorMap;
}
public void setErrorColor(Color color)
{
colorMap.put(Severity.ERROR, color);
}
public void setWarningColor(Color color)
{
colorMap.put(Severity.WARNING, color);
}
public FormComponentInterceptor getInterceptor(FormModel formModel)
{
return new ColorValidationInterceptor(formModel);
}
private class ColorValidationInterceptor extends ValidationInterceptor
{
public ColorValidationInterceptor(FormModel formModel)
{
super(formModel);
}
public void processComponent(String propertyName, JComponent component) {
JComponent innerComponent = getInnerComponent(component);
if (innerComponent instanceof JTextComponent) {
ColorChanger colorChanger = new ColorChanger((JTextComponent)innerComponent);
registerMessageReceiver(propertyName, colorChanger);
}
}
@Override
protected JComponent getInnerComponent(JComponent component)
{
if (component instanceof JXDatePicker)
return ((JXDatePicker)component).getEditor();
if (component instanceof HasValidationComponent)
return ((HasValidationComponent)component).getValidationComponent();
return super.getInnerComponent(component);
}
}
/**
* The colors used with each component are set by a ComponentUI class. When
* the state of a component changes, the ComponentUI class will react on
* this and set the appropriate colors <b>if and only if</b> the current
* color on the component is implementing ResourceUI. (~ was created by the
* ComponentUI itself)
*
* That's why we have to remember this color instead of defining our own
* "normal" color which wouldn't be replaced by the inactive/active color
* scheme used with editable/enabled.
*
* The only thing to check actually is when the enable/editable states are
* changed (should be after this colorChanger).
*
* @see javax.swing.plaf.basic.BasicTextFieldUI#update(java.awt.Graphics, JComponent)
*
* @author jh
*
*/
private class ColorChanger implements Messagable
{
/**
* Reference to the component to switch colors.
*/
private JTextComponent component;
/**
* Constructor.
*
* @param component
* component on which to change color.
*/
public ColorChanger(JTextComponent component)
{
this.component = component;
}
/**
* Set the color according to the enabled state. When enabled, check
* component's enabled and editable state for correct background color.
*/
public void setMessage(Message message)
{
Color colorToSet = message == null ? null : colorMap.get(message.getSeverity());
if (colorToSet != null)
component.setBackground(colorToSet);
else if (!component.isEnabled())
component.setBackground( UIManager.getColor("TextField.disabledBackground"));
else if (!component.isEditable())
component.setBackground( UIManager.getColor("TextField.inactiveBackground"));
else
component.setBackground( UIManager.getColor("TextField.background"));
}
public void addPropertyChangeListener(PropertyChangeListener listener)
{
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)
{
}
public void removePropertyChangeListener(PropertyChangeListener listener)
{
}
public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener)
{
}
}
}