1 /* Copyright (C) 2005-2011 Fabio Riccardi */
2 
3 package com.lightcrafts.ui.operation.generic;
4 
5 import com.lightcrafts.model.GenericOperation;
6 import com.lightcrafts.model.Operation;
7 import com.lightcrafts.model.OperationType;
8 import com.lightcrafts.model.SliderConfig;
9 import com.lightcrafts.ui.help.HelpConstants;
10 import com.lightcrafts.ui.operation.OpControl;
11 import com.lightcrafts.ui.operation.OpStack;
12 import com.lightcrafts.utils.xml.XMLException;
13 import com.lightcrafts.utils.xml.XmlNode;
14 
15 import javax.swing.*;
16 import javax.swing.event.ChangeEvent;
17 import javax.swing.event.ChangeListener;
18 import java.awt.event.*;
19 import java.util.*;
20 
21 public class GenericControl extends OpControl {
22 
23     // This resource bundle holds the user presentable forms of the
24     // GenericOperation slider and checkbox keys.  (Choice keys are still
25     // not localizable.)
26     //
27     // The format for the properties file is:
28     //
29     //     operationTypeName-keyString=userPresentableKeyString
30     //
31     // where "operationTypeName" is the String returned by
32     // GenericOperation.getOperationType().getName().replaceAll(" ", "").
33 
34     private final static ResourceBundle Resources = ResourceBundle.getBundle(
35         "com/lightcrafts/ui/operation/generic/GenericControl"
36     );
37 
38     private GenericOperation op;
39 
40     // GenericOperation settings keys mapped to their control Components:
41 
42     private Map sliders = new HashMap();        // Strings to GenericSliders
43     private Map checkboxes = new HashMap();     // Strings to JCheckBoxes
44     private Map choices = new HashMap();        // Strings to JComboBoxes
45 
GenericControl(GenericOperation op, OpStack stack)46     public GenericControl(GenericOperation op, OpStack stack) {
47         super(op, stack);
48         operationChanged(op);
49         readyForUndo();
50     }
51 
operationChanged(Operation operation)52     protected void operationChanged(Operation operation) {
53         super.operationChanged(operation);
54 
55         this.op = (GenericOperation) operation;
56 
57         Box box = Box.createVerticalBox();
58 
59         box.add(Box.createVerticalStrut(6));
60 
61         // Add all the sliders:
62 
63         // A special layout that aligns the GenericSlider pieces in rows
64         // and columns:
65         GenericSliderContainer sliderContainer = new GenericSliderContainer();
66 
67         List sliderKeys = op.getSliderKeys();
68         for (Iterator i=sliderKeys.iterator(); i.hasNext(); ) {
69             final String key = (String) i.next();
70             final String userKey = getUserPresentableKey(key);
71             final SliderConfig config = op.getSliderConfig(key);
72             final GenericSlider slider = new GenericSlider(userKey, config);
73             slider.addChangeListener(
74                 new ChangeListener() {
75                     public void stateChanged(ChangeEvent event) {
76                         double value = slider.getConfiguredValue();
77                         op.setSliderValue(key, value);
78                     }
79                 }
80             );
81             GenericSlider oldSlider = (GenericSlider) sliders.get(key);
82             if (oldSlider != null) {
83                 slider.setConfiguredValue(oldSlider.getConfiguredValue());
84             }
85             slider.addSliderMouseListener(
86                 new MouseAdapter() {
87                     public void mousePressed(MouseEvent event) {
88                         op.changeBatchStarted();
89                     }
90                     public void mouseReleased(MouseEvent event) {
91                         op.changeBatchEnded();
92                         undoSupport.postEdit(key + " Slider");
93                     }
94                 }
95             );
96             slider.setBackgroundRecurse(Background);
97             slider.setFontRecurse(ControlFont);
98             sliderContainer.addGenericSlider(slider);
99 
100             sliders.put(key, slider);
101         }
102         sliderContainer.setBackground(Background);
103         box.add(sliderContainer);
104 
105         // Add all the checkboxes:
106 
107         List checkboxKeys = op.getCheckboxKeys();
108         for (Iterator i=checkboxKeys.iterator(); i.hasNext(); ) {
109             final String key = (String) i.next();
110             final String userKey = getUserPresentableKey(key);
111             final JCheckBox checkbox = new JCheckBox(userKey);
112             checkbox.addItemListener(
113                 new ItemListener() {
114                     public void itemStateChanged(ItemEvent event) {
115                         boolean value = checkbox.isSelected();
116                         op.setCheckboxValue(key, value);
117                         undoSupport.postEdit(key + " Checkbox");
118                     }
119                 }
120             );
121             JCheckBox oldCheckbox = (JCheckBox) checkboxes.get(key);
122             if (oldCheckbox != null) {
123                 checkbox.setSelected(oldCheckbox.isSelected());
124             }
125             checkbox.setBackground(Background);
126             checkbox.setFont(ControlFont);
127             box.add(checkbox);
128 
129             checkboxes.put(key, checkbox);
130         }
131 
132         // Add all the choices:
133 
134         List choiceKeys = op.getChoiceKeys();
135         for (Iterator i=choiceKeys.iterator(); i.hasNext(); ) {
136             final String key = (String) i.next();
137             Vector values = new Vector(op.getChoiceValues(key));
138             final JComboBox choice = new JComboBox(values);
139             choice.addActionListener(
140                 new ActionListener() {
141                     public void actionPerformed(ActionEvent event) {
142                         String value = (String) choice.getSelectedItem();
143                         op.setChoiceValue(key, value);
144                         undoSupport.postEdit(key + " Choice");
145                     }
146                 }
147             );
148             choice.addMouseWheelListener(
149                 new MouseWheelListener() {
150                     public void mouseWheelMoved(MouseWheelEvent e) {
151                         JComboBox source = (JComboBox) e.getComponent();
152                         if (!source.hasFocus()) {
153                             return;
154                         }
155                         int ni = source.getSelectedIndex() + e.getWheelRotation();
156                         if (ni >= 0 && ni < source.getItemCount()) {
157                             source.setSelectedIndex(ni);
158                         }
159                     }
160                 }
161             );
162             JComboBox oldChoice = (JComboBox) choices.get(key);
163             if (oldChoice != null) {
164                 choice.setSelectedItem(oldChoice.getSelectedItem());
165             }
166             choice.setBackground(Background);
167             choice.setFont(ControlFont);
168             box.add(choice);
169 
170             choices.put(key, choice);
171         }
172         box.add(Box.createVerticalStrut(6));
173 
174         setContent(box);
175 
176         undoSupport.initialize();
177     }
178 
slewSlider(String key, double value)179     protected void slewSlider(String key, double value) {
180         GenericSlider slider = (GenericSlider) sliders.get(key);
181         if (slider != null) {
182             slider.setConfiguredValue(value);
183         }
184     }
185 
186     // Find the user presentable version of the given slider or
187     // checkbox key in the properties.  If none is configured, just
188     // return the given String.
getUserPresentableKey(String key)189     private String getUserPresentableKey(String key) {
190         OperationType type = op.getType();
191         String name = type.getName();
192         name = name.replaceAll(" ", "").replaceAll("V[0-9]+\\Z", "");
193         String propKey = name + "-" + key;
194         try {
195             return Resources.getString(propKey);
196         }
197         catch (MissingResourceException e) {
198             return key;
199         }
200     }
201 
202     private final static String SliderTag = "Slider";
203     private final static String CheckBoxTag = "Checkbox";
204     private final static String ChoiceTag = "Choice";
205 
save(XmlNode node)206     public void save(XmlNode node) {
207         super.save(node);
208         Set keys;
209         XmlNode sliderNode = node.addChild(SliderTag);
210         keys = sliders.keySet();
211         for (Iterator i=keys.iterator(); i.hasNext(); ) {
212             String key = (String) i.next();
213             GenericSlider slider = (GenericSlider) sliders.get(key);
214             double value = slider.getConfiguredValue();
215             sliderNode.setAttribute(key, Double.toString(value));
216         }
217         XmlNode checkboxNode = node.addChild(CheckBoxTag);
218         keys = checkboxes.keySet();
219         for (Iterator i=keys.iterator(); i.hasNext(); ) {
220             String key = (String) i.next();
221             JCheckBox checkbox = (JCheckBox) checkboxes.get(key);
222             boolean value = checkbox.isSelected();
223             checkboxNode.setAttribute(key, value ? "True" : "False");
224         }
225         XmlNode choiceNode = node.addChild(ChoiceTag);
226         keys = choices.keySet();
227         for (Iterator i=keys.iterator(); i.hasNext(); ) {
228             String key = (String) i.next();
229             JComboBox choice = (JComboBox) choices.get(key);
230             String value = (String) choice.getSelectedItem();
231             choiceNode.setAttribute(key, value);
232         }
233     }
234 
restore(XmlNode node)235     public void restore(XmlNode node) throws XMLException {
236         super.restore(node);
237         undoSupport.restoreStart();
238         op.changeBatchStarted();
239         Set keys;
240         if (node.hasChild(SliderTag)) {
241             XmlNode sliderNode = node.getChild(SliderTag);
242             keys = sliders.keySet();
243             for (Iterator i=keys.iterator(); i.hasNext(); ) {
244                 String key = (String) i.next();
245                 GenericSlider slider = (GenericSlider) sliders.get(key);
246                 try {
247                     int version = sliderNode.getVersion();
248                     if ((version >= 3) || (version < 0)) {
249                         double value = Double.parseDouble(
250                             sliderNode.getAttribute(key)
251                         );
252                         slider.setConfiguredValue(value);
253                     }
254                     else {
255                         int value = Integer.parseInt(sliderNode.getAttribute(key));
256                         slider.setSliderPosition(value);
257                     }
258                 }
259                 catch (NumberFormatException e) {
260                     throw new XMLException(
261                         "Value at attribute \"" + key + "\" is not a number", e
262                     );
263                 }
264             }
265         }
266         if (node.hasChild(CheckBoxTag)) {
267             XmlNode checkboxNode = node.getChild(CheckBoxTag);
268             keys = checkboxes.keySet();
269             for (Iterator i=keys.iterator(); i.hasNext(); ) {
270                 String key = (String) i.next();
271                 JCheckBox checkbox = (JCheckBox) checkboxes.get(key);
272                 String value = checkboxNode.getAttribute(key);
273                 checkbox.setSelected(value.equals("True"));
274             }
275         }
276         if (node.hasChild(ChoiceTag)) {
277             XmlNode choiceNode = node.getChild(ChoiceTag);
278             keys = choices.keySet();
279             for (Iterator i=keys.iterator(); i.hasNext(); ) {
280                 String key = (String) i.next();
281                 JComboBox choice = (JComboBox) choices.get(key);
282                 String value = choiceNode.getAttribute(key);
283                 choice.setSelectedItem(value);
284             }
285         }
286         op.changeBatchEnded();
287         undoSupport.restoreEnd();
288     }
289 
290     // This is a crude mapping from GenericOperation OperationType names
291     // (as found, for instance, in opActions.properties) into help topics
292     // (as defined in HelpConstants).
293     //
294     // This mapping needs maintenance, as tools come and go.
getHelpTopic()295     protected String getHelpTopic() {
296         OperationType type = op.getType();
297         String name = type.getName();
298         if (name.startsWith("ZoneMapper")) {
299             return HelpConstants.HELP_TOOL_ZONEMAPPER;
300         }
301         if (name.startsWith("UnSharp Mask")) {
302             return HelpConstants.HELP_TOOL_SHARPEN;
303         }
304         if (name.startsWith("Gaussian Blur")) {
305             return HelpConstants.HELP_TOOL_BLUR;
306         }
307         if (name.startsWith("Hue/Saturation")) {
308             return HelpConstants.HELP_TOOL_HUE_SATURATION;
309         }
310         if (name.startsWith("Color Balance")) {
311             return HelpConstants.HELP_TOOL_COLOR_BALANCE;
312         }
313         if (name.startsWith("White Point")) {
314             return HelpConstants.HELP_TOOL_WHITE_BALANCE;
315         }
316         if (name.startsWith("Channel Mixer")) {
317             return HelpConstants.HELP_TOOL_BLACK_AND_WHITE;
318         }
319         if (name.startsWith("Advanced Noise Reduction")) {
320             return HelpConstants.HELP_TOOL_NOISE_REDUCTION;
321         }
322         if (name.startsWith("Clone")) {
323             return HelpConstants.HELP_TOOL_CLONE;
324         }
325         if (name.startsWith("Spot")) {
326             return HelpConstants.HELP_TOOL_SPOT;
327         }
328         if (name.startsWith("RAW Adjustments")) {
329             return HelpConstants.HELP_TOOL_RAW_ADJUSTMENTS;
330         }
331         if (name.startsWith("Relight") || name.startsWith("Tone")) {
332             return HelpConstants.HELP_TOOL_RELIGHT;
333         }
334         if (name.startsWith("Red Eyes")) {
335             return HelpConstants.HELP_TOOL_RED_EYE;
336         }
337         // This null leads to the help home page.
338         return null;
339     }
340 }
341