1 /* Copyright (C) 2005-2011 Fabio Riccardi */
2 
3 package com.lightcrafts.app;
4 
5 import static com.lightcrafts.app.Locale.LOCALE;
6 import com.lightcrafts.image.ImageInfo;
7 import com.lightcrafts.image.metadata.ImageMetadata;
8 import com.lightcrafts.image.types.RawImageType;
9 import com.lightcrafts.platform.Platform;
10 import com.lightcrafts.templates.TemplateKey;
11 import com.lightcrafts.templates.TemplateDatabase;
12 import com.lightcrafts.utils.xml.XMLException;
13 import com.lightcrafts.utils.xml.XmlDocument;
14 
15 import javax.swing.*;
16 import java.awt.*;
17 import java.awt.event.*;
18 import java.io.File;
19 import java.io.FileInputStream;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Set;
23 
24 /**
25  * The save-template dialog is a lot like a JOptionPane with a combo box,
26  * except it uses its own dialog instead of the JOptionPane showXxxDialog()
27  * methods so it can set the initial focus on the combo box instead of a
28  * button.
29  */
30 class SaveTemplateDialog extends JDialog {
31 
32     private XmlDocument originalTemplate;
33     private JComboBox namespaceField;
34     private JComboBox nameField;
35     private TemplateToolSelector selector;
36     private boolean isOkSelected;
37     private boolean isDefaultSelected;
38 
showDialog( ImageMetadata meta, XmlDocument template, String nsDefault, JFrame parent )39     TemplateKey showDialog(
40         ImageMetadata meta,     // offer the always-apply option for RAW images
41         XmlDocument template,   // the template LZN to save
42         String nsDefault,       // the default template namespace
43         JFrame parent           // parent for this dialog
44     ) {
45         originalTemplate = template;
46         nameField = new JComboBox();
47         namespaceField = new JComboBox();
48         try {
49             // Find all distinct namespaces from the TemplateDocuments.
50             List<TemplateKey> keys = TemplateDatabase.getTemplateKeys();
51             Set<String> namespaces = new HashSet<String>();
52             for (TemplateKey key : keys) {
53                 namespaces.add(key.getNamespace());
54             }
55             for (String namespace : namespaces) {
56                 namespaceField.addItem(namespace);
57             }
58             // Update the template names when the namespace changes.
59             namespaceField.addActionListener(
60                 new ActionListener() {
61                     public void actionPerformed(ActionEvent e) {
62                         Object name = nameField.getSelectedItem();
63                         updateNameField();
64                         nameField.setSelectedItem(name);
65                     }
66                 }
67             );
68         }
69         catch (TemplateDatabase.TemplateException e) {
70             // Just don't show existing template names.
71         }
72         try {
73             selector = new TemplateToolSelector(template);
74         }
75         catch (XMLException e) {
76             // Don't include the selector to the layout below.
77             System.err.println("Couldn't initialize TemplateToolSelector");
78             e.printStackTrace();
79         }
80         // Please excuse the GridBag.  I'm just lining up text fields and
81         // labels into columns.
82         JPanel textGrid = new JPanel(new GridBagLayout());
83         GridBagConstraints c = new GridBagConstraints();
84         c.gridx = 0;
85         c.gridy = 0;
86         c.anchor = GridBagConstraints.EAST;
87         c.fill = GridBagConstraints.NONE;
88         textGrid.add(new JLabel(LOCALE.get("TemplateNameLabel") + ':'), c);
89         c.gridx = 1;
90         c.gridy = 0;
91         c.anchor = GridBagConstraints.WEST;
92         c.fill = GridBagConstraints.HORIZONTAL;
93         textGrid.add(nameField, c);
94         c.gridx = 0;
95         c.gridy = 1;
96         c.anchor = GridBagConstraints.EAST;
97         c.fill = GridBagConstraints.NONE;
98         textGrid.add(new JLabel(LOCALE.get("TemplateNamespaceLabel") + ':'), c);
99         c.gridx = 1;
100         c.gridy = 1;
101         c.anchor = GridBagConstraints.WEST;
102         c.fill = GridBagConstraints.HORIZONTAL;
103         textGrid.add(namespaceField, c);
104 
105         // If a camera model is known, then offer the option to associate
106         // all images from this camera with the current template:
107         String camera = meta.getCameraMake(true);
108         boolean isRaw = (meta.getImageType() instanceof RawImageType);
109         JCheckBox defaultCheck;
110         if (isRaw && (camera != null)) {
111             defaultCheck = new JCheckBox(
112                 LOCALE.get("TemplateAlwaysLabel", camera)
113             );
114         }
115         else {
116             defaultCheck = new JCheckBox(
117                 LOCALE.get("TemplateAlwaysDisabledLabel")
118             );
119             defaultCheck.setEnabled(false);
120         }
121         defaultCheck.setAlignmentX(1f);
122 
123         Box defaultBox = Box.createHorizontalBox();
124         defaultBox.add(defaultCheck);
125         defaultBox.add(Box.createHorizontalGlue());
126 
127         // Initialize the text fields with a default template name:
128         if (nsDefault == null) {
129             nsDefault = LOCALE.get("TemplateDefaultNamespace");
130         }
131         int n = 1;
132         String defaultName = null;
133         do {
134             String name = LOCALE.get(
135                 "TemplateDefaultNamePattern", Integer.toString(n++)
136             );
137             TemplateKey key = new TemplateKey(nsDefault, name);
138             try {
139                 TemplateDatabase.getTemplateDocument(key);
140             }
141             catch (TemplateDatabase.TemplateException e) {
142                 // No Template with this name has been defined.
143                 defaultName = name;
144             }
145         } while (defaultName == null);
146 
147         namespaceField.addItem(nsDefault);
148         namespaceField.setSelectedItem(nsDefault);
149         namespaceField.setEditable(true);
150         nameField.setPreferredSize(
151             new Dimension(160, namespaceField.getPreferredSize().height)
152         );
153         nameField.getEditor().selectAll();
154 
155         nameField.addItem(defaultName);
156         nameField.setSelectedItem(defaultName);
157         nameField.setEditable(true);
158         nameField.setPreferredSize(
159             new Dimension(160, nameField.getPreferredSize().height)
160         );
161         nameField.getEditor().selectAll();
162 
163         Box messageBox = Box.createVerticalBox();
164         messageBox.add(textGrid);
165         messageBox.add(defaultBox);
166         messageBox.add(Box.createVerticalStrut(8));
167         if (selector != null) {
168             messageBox.add(selector);
169         }
170         // We use our own OK button, instead of the one generated by
171         // JOptionPane, so we can set it to be the default button for the
172         // dialog.
173         JButton okButton = new JButton(LOCALE.get("TemplateSaveOption"));
174         JButton cancelButton = new JButton(LOCALE.get("TemplateCancelOption"));
175         JOptionPane pane = new JOptionPane(
176             messageBox,
177             JOptionPane.QUESTION_MESSAGE,
178             JOptionPane.OK_CANCEL_OPTION,
179             null,
180             new Object[] { okButton, cancelButton },
181             null
182         );
183         // Set a minimum width for the dialog.
184         Dimension size = pane.getPreferredSize();
185         size = new Dimension(Math.max(size.width, 400), size.height);
186         pane.setPreferredSize(size);
187 
188         // Use a custom dialog instead of the JOptionPane showXxxDialog()
189         // methods so that we can set the initial focus on the combo box
190         // instead of the OK button.
191         final JDialog dialog = new JDialog(parent);
192         dialog.setTitle(LOCALE.get("TemplateSaveDialogTitle"));
193         dialog.setContentPane(pane);
194         dialog.getRootPane().setDefaultButton(okButton);
195 
196         // This causes the dialog to go away when the user presses "ESCAPE".
197         pane.registerKeyboardAction(
198             new ActionListener() {
199                 public void actionPerformed(ActionEvent e) {
200                     dialog.setVisible(false);
201                 }
202             },
203             KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
204             JComponent.WHEN_IN_FOCUSED_WINDOW
205         );
206         // This causes the dialog to go away when the user clicks "OK".
207         okButton.addActionListener(
208             new ActionListener() {
209                 public void actionPerformed(ActionEvent e) {
210 
211                     // In case this happens while the combo box editor is
212                     // active, commit the current text to the combo box model:
213                     ComboBoxEditor editor = nameField.getEditor();
214                     JTextField text = (JTextField) editor.getEditorComponent();
215                     String name = text.getText();
216                     nameField.setSelectedItem(name);
217 
218                     isOkSelected = true;
219                     dialog.setVisible(false);
220                 }
221             }
222         );
223         // This causes the dialog to go away when the user clicks "Cancel".
224         cancelButton.addActionListener(
225             new ActionListener() {
226                 public void actionPerformed(ActionEvent event) {
227                     dialog.setVisible(false);
228                 }
229             }
230         );
231         dialog.setModal(true);
232         dialog.setResizable(true);
233         dialog.pack();
234         dialog.setLocationRelativeTo(parent);
235 
236         dialog.setVisible(true);
237 
238         isDefaultSelected = defaultCheck.isSelected();
239 
240         if (! isOkSelected) {
241             // The dialog was disposed, or the user clicked Cancel.
242             return null;
243         }
244         if (nameField.getEditor().getEditorComponent().isFocusOwner()) {
245             KeyboardFocusManager focus =
246                 KeyboardFocusManager.getCurrentKeyboardFocusManager();
247             focus.upFocusCycle();
248         }
249         return new TemplateKey(getNamespaceText(), getNameText());
250     }
251 
getNameText()252     String getNameText() {
253         Object selected = nameField.getSelectedItem();
254         return (selected != null) ? selected.toString() : "";
255     }
256 
getNamespaceText()257     String getNamespaceText() {
258         Object selected = namespaceField.getSelectedItem();
259         return (selected != null) ? selected.toString() : "";
260     }
261 
isDefaultSelected()262     boolean isDefaultSelected() {
263         return isDefaultSelected;
264     }
265 
getModifiedTemplate()266     XmlDocument getModifiedTemplate() {
267         if (selector != null) {
268             return selector.getModifiedTemplate();
269         }
270         else {
271             return new XmlDocument(originalTemplate);
272         }
273     }
274 
275     // When the namespace changes, update the combo box of Template names.
updateNameField()276     private void updateNameField() {
277         String namespace = getNamespaceText();
278         nameField.removeAllItems();
279         try {
280             List<TemplateKey> descs = TemplateDatabase.getTemplateKeys();
281             for (TemplateKey desc : descs) {
282                 if (namespace.equals(desc.getNamespace())) {
283                     nameField.addItem(desc.getName());
284                 }
285             }
286         }
287         catch (TemplateDatabase.TemplateException e) {
288             // Just leave the name field blank.
289             e.printStackTrace();
290         }
291     }
292 
main(String[] args)293     public static void main(String[] args) throws Exception {
294         UIManager.setLookAndFeel(Platform.getPlatform().getLookAndFeel());
295 
296         XmlDocument doc = new XmlDocument(
297             new FileInputStream(
298                 "/Users/anton/test/1/test.lzn"
299             )
300         );
301         ImageInfo info = ImageInfo.getInstanceFor(
302             new File("/Users/anton/test/1/test.crw")
303         );
304         ImageMetadata meta = info.getMetadata();
305 
306         SaveTemplateDialog dialog = new SaveTemplateDialog();
307         dialog.showDialog(meta, doc, null, null);
308 
309         System.out.println("name=" + dialog.getNameText());
310         System.out.println("namespace=" + dialog.getNamespaceText());
311 
312         System.exit(0);
313     }
314 }
315