/* Copyright (C) 2005-2011 Fabio Riccardi */
package com.lightcrafts.ui.operation.generic;
import com.lightcrafts.model.GenericOperation;
import com.lightcrafts.model.Operation;
import com.lightcrafts.model.OperationType;
import com.lightcrafts.model.SliderConfig;
import com.lightcrafts.ui.help.HelpConstants;
import com.lightcrafts.ui.layout.Box;
import com.lightcrafts.ui.operation.OpControl;
import com.lightcrafts.ui.operation.OpStack;
import com.lightcrafts.utils.xml.XMLException;
import com.lightcrafts.utils.xml.XmlNode;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.event.*;
import java.util.*;
public class GenericControl extends OpControl {
// This resource bundle holds the user presentable forms of the
// GenericOperation slider and checkbox keys. (Choice keys are still
// not localizable.)
//
// The format for the properties file is:
//
// operationTypeName-keyString=userPresentableKeyString
//
// where "operationTypeName" is the String returned by
// GenericOperation.getOperationType().getName().replaceAll(" ", "").
private final static ResourceBundle Resources = ResourceBundle.getBundle(
"com/lightcrafts/ui/operation/generic/GenericControl"
);
private GenericOperation op;
// GenericOperation settings keys mapped to their control Components:
private Map sliders = new HashMap(); // Strings to GenericSliders
private Map checkboxes = new HashMap(); // Strings to JCheckBoxes
private Map choices = new HashMap(); // Strings to JComboBoxes
public GenericControl(GenericOperation op, OpStack stack) {
super(op, stack);
operationChanged(op);
readyForUndo();
}
protected void operationChanged(Operation operation) {
super.operationChanged(operation);
this.op = (GenericOperation) operation;
Box box = Box.createVerticalBox();
box.add(Box.createVerticalStrut(6));
// Add all the sliders:
// A special layout that aligns the GenericSlider pieces in rows
// and columns:
GenericSliderContainer sliderContainer = new GenericSliderContainer();
List sliderKeys = op.getSliderKeys();
for (Iterator i=sliderKeys.iterator(); i.hasNext(); ) {
final String key = (String) i.next();
final String userKey = getUserPresentableKey(key);
final SliderConfig config = op.getSliderConfig(key);
final GenericSlider slider = new GenericSlider(userKey, config);
slider.addChangeListener(
new ChangeListener() {
public void stateChanged(ChangeEvent event) {
double value = slider.getConfiguredValue();
op.setSliderValue(key, value);
}
}
);
GenericSlider oldSlider = (GenericSlider) sliders.get(key);
if (oldSlider != null) {
slider.setConfiguredValue(oldSlider.getConfiguredValue());
}
slider.addSliderMouseListener(
new MouseAdapter() {
public void mousePressed(MouseEvent event) {
op.changeBatchStarted();
}
public void mouseReleased(MouseEvent event) {
op.changeBatchEnded();
undoSupport.postEdit(key + " Slider");
}
}
);
slider.setBackgroundRecurse(Background);
slider.setFontRecurse(ControlFont);
sliderContainer.addGenericSlider(slider);
sliders.put(key, slider);
}
sliderContainer.setBackground(Background);
box.add(sliderContainer);
// Add all the checkboxes:
List checkboxKeys = op.getCheckboxKeys();
for (Iterator i=checkboxKeys.iterator(); i.hasNext(); ) {
final String key = (String) i.next();
final String userKey = getUserPresentableKey(key);
final JCheckBox checkbox = new JCheckBox(userKey);
checkbox.addItemListener(
new ItemListener() {
public void itemStateChanged(ItemEvent event) {
boolean value = checkbox.isSelected();
op.setCheckboxValue(key, value);
undoSupport.postEdit(key + " Checkbox");
}
}
);
JCheckBox oldCheckbox = (JCheckBox) checkboxes.get(key);
if (oldCheckbox != null) {
checkbox.setSelected(oldCheckbox.isSelected());
}
checkbox.setBackground(Background);
checkbox.setFont(ControlFont);
box.add(checkbox);
checkboxes.put(key, checkbox);
}
// Add all the choices:
List choiceKeys = op.getChoiceKeys();
for (Iterator i=choiceKeys.iterator(); i.hasNext(); ) {
final String key = (String) i.next();
Vector values = new Vector(op.getChoiceValues(key));
final JComboBox choice = new JComboBox(values);
choice.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent event) {
String value = (String) choice.getSelectedItem();
op.setChoiceValue(key, value);
undoSupport.postEdit(key + " Choice");
}
}
);
JComboBox oldChoice = (JComboBox) choices.get(key);
if (oldChoice != null) {
choice.setSelectedItem(oldChoice.getSelectedItem());
}
choice.setBackground(Background);
choice.setFont(ControlFont);
box.add(choice);
choices.put(key, choice);
}
box.add(Box.createVerticalStrut(6));
setContent(box);
undoSupport.initialize();
}
protected void slewSlider(String key, double value) {
GenericSlider slider = (GenericSlider) sliders.get(key);
if (slider != null) {
slider.setConfiguredValue(value);
}
}
// Find the user presentable version of the given slider or
// checkbox key in the properties. If none is configured, just
// return the given String.
private String getUserPresentableKey(String key) {
OperationType type = op.getType();
String name = type.getName();
name = name.replaceAll(" ", "");
String propKey = name + "-" + key;
try {
return Resources.getString(propKey);
}
catch (MissingResourceException e) {
return key;
}
}
private final static String SliderTag = "Slider";
private final static String CheckBoxTag = "Checkbox";
private final static String ChoiceTag = "Choice";
public void save(XmlNode node) {
super.save(node);
Set keys;
XmlNode sliderNode = node.addChild(SliderTag);
keys = sliders.keySet();
for (Iterator i=keys.iterator(); i.hasNext(); ) {
String key = (String) i.next();
GenericSlider slider = (GenericSlider) sliders.get(key);
double value = slider.getConfiguredValue();
sliderNode.setAttribute(key, Double.toString(value));
}
XmlNode checkboxNode = node.addChild(CheckBoxTag);
keys = checkboxes.keySet();
for (Iterator i=keys.iterator(); i.hasNext(); ) {
String key = (String) i.next();
JCheckBox checkbox = (JCheckBox) checkboxes.get(key);
boolean value = checkbox.isSelected();
checkboxNode.setAttribute(key, value ? "True" : "False");
}
XmlNode choiceNode = node.addChild(ChoiceTag);
keys = choices.keySet();
for (Iterator i=keys.iterator(); i.hasNext(); ) {
String key = (String) i.next();
JComboBox choice = (JComboBox) choices.get(key);
String value = (String) choice.getSelectedItem();
choiceNode.setAttribute(key, value);
}
}
public void restore(XmlNode node) throws XMLException {
super.restore(node);
undoSupport.restoreStart();
op.changeBatchStarted();
Set keys;
if (node.hasChild(SliderTag)) {
XmlNode sliderNode = node.getChild(SliderTag);
keys = sliders.keySet();
for (Iterator i=keys.iterator(); i.hasNext(); ) {
String key = (String) i.next();
GenericSlider slider = (GenericSlider) sliders.get(key);
try {
int version = sliderNode.getVersion();
if ((version >= 3) || (version < 0)) {
double value = Double.parseDouble(
sliderNode.getAttribute(key)
);
slider.setConfiguredValue(value);
}
else {
int value = Integer.parseInt(sliderNode.getAttribute(key));
slider.setSliderPosition(value);
}
}
catch (NumberFormatException e) {
throw new XMLException(
"Value at attribute \"" + key + "\" is not a number", e
);
}
}
}
if (node.hasChild(CheckBoxTag)) {
XmlNode checkboxNode = node.getChild(CheckBoxTag);
keys = checkboxes.keySet();
for (Iterator i=keys.iterator(); i.hasNext(); ) {
String key = (String) i.next();
JCheckBox checkbox = (JCheckBox) checkboxes.get(key);
String value = checkboxNode.getAttribute(key);
checkbox.setSelected(value.equals("True"));
}
}
if (node.hasChild(ChoiceTag)) {
XmlNode choiceNode = node.getChild(ChoiceTag);
keys = choices.keySet();
for (Iterator i=keys.iterator(); i.hasNext(); ) {
String key = (String) i.next();
JComboBox choice = (JComboBox) choices.get(key);
String value = choiceNode.getAttribute(key);
choice.setSelectedItem(value);
}
}
op.changeBatchEnded();
undoSupport.restoreEnd();
}
// This is a crude mapping from GenericOperation OperationType names
// (as found, for instance, in opActions.properties) into help topics
// (as defined in HelpConstants).
//
// This mapping needs maintenance, as tools come and go.
protected String getHelpTopic() {
OperationType type = op.getType();
String name = type.getName();
if (name.startsWith("ZoneMapper")) {
return HelpConstants.HELP_TOOL_ZONEMAPPER;
}
if (name.startsWith("UnSharp Mask")) {
return HelpConstants.HELP_TOOL_SHARPEN;
}
if (name.startsWith("Gaussian Blur")) {
return HelpConstants.HELP_TOOL_BLUR;
}
if (name.startsWith("Hue/Saturation")) {
return HelpConstants.HELP_TOOL_HUE_SATURATION;
}
if (name.startsWith("Color Balance")) {
return HelpConstants.HELP_TOOL_COLOR_BALANCE;
}
if (name.startsWith("White Point")) {
return HelpConstants.HELP_TOOL_WHITE_BALANCE;
}
if (name.startsWith("Channel Mixer")) {
return HelpConstants.HELP_TOOL_BLACK_AND_WHITE;
}
if (name.startsWith("Advanced Noise Reduction")) {
return HelpConstants.HELP_TOOL_NOISE_REDUCTION;
}
if (name.startsWith("Clone")) {
return HelpConstants.HELP_TOOL_CLONE;
}
if (name.startsWith("Spot")) {
return HelpConstants.HELP_TOOL_SPOT;
}
if (name.startsWith("RAW Adjustments")) {
return HelpConstants.HELP_TOOL_RAW_ADJUSTMENTS;
}
if (name.startsWith("Relight") || name.startsWith("Tone")) {
return HelpConstants.HELP_TOOL_RELIGHT;
}
if (name.startsWith("Red Eyes")) {
return HelpConstants.HELP_TOOL_RED_EYE;
}
// This null leads to the help home page.
return null;
}
}