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