1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.xnap.commons.gui;
22
23 import java.awt.Component;
24 import java.io.File;
25 import java.io.IOException;
26 import javax.swing.Box;
27 import javax.swing.DefaultListCellRenderer;
28 import javax.swing.JCheckBox;
29 import javax.swing.JLabel;
30 import javax.swing.JList;
31 import javax.swing.JOptionPane;
32 import javax.swing.JPasswordField;
33 import javax.swing.JScrollPane;
34 import org.xnap.commons.gui.util.GUIHelper;
35 import org.xnap.commons.i18n.I18n;
36 import org.xnap.commons.i18n.I18nFactory;
37 import org.xnap.commons.settings.BooleanSetting;
38 import org.xnap.commons.util.FileHelper;
39
40 /***
41 * Provides a set of static methods to display common dialogs.
42 */
43 public class Dialogs {
44
45 private static final I18n i18n = I18nFactory.getI18n(Dialogs.class);
46
47 /***
48 * Copies <code>files</code> to <code>target</code>. Shows a dialog
49 * in case of an error.
50 *
51 * @see FileHelper#copy(File, File)
52 * @param files the files to copy
53 * @param target the target directory
54 * @return true, if copy was successful; false, otherwise or if
55 * <code>files</code> is empty
56 * TODO copying could be costly, show progress dialog here too, see DropFileTree..
57 */
58 public static boolean executeCopy(Component parent, File[] files, File target)
59 {
60 if (files != null) {
61 boolean success = true;
62 for (int i = 0; i < files.length; i++) {
63 try {
64 FileHelper.copy(files[i], new File
65 (target, files[i].getName()));
66 }
67 catch (IOException e) {
68 showError
69 (parent,
70 i18n.tr("Could not copy {0} to {1}: {2}.",
71 files[i].getAbsolutePath(),
72 target.getAbsolutePath(),
73 e.getLocalizedMessage()),
74 e);
75 success = false;
76 }
77 }
78 return success;
79 }
80
81 return false;
82 }
83
84 /***
85 * Moves <code>files</code> to <code>target</code>. Shows a dialog
86 * in case of an error. Renames each file in case it already exists
87 * in <code>target</code>.
88 *
89 * @param files the files to copy
90 * @param target the target directory
91 * @return true, if move was successful; false, otherwise or if
92 * <code>files</code> is empty
93 */
94 public static boolean executeMove(Component parent, File[] files, File target)
95 {
96 if (files != null) {
97 boolean success = true;
98 for (int i = 0; i < files.length; i++) {
99 try {
100 FileHelper.moveUnique(files[i], target.getAbsolutePath());
101 }
102 catch (IOException e) {
103 showError
104 (parent,
105 i18n.tr("Could not move {0} to {1}: {2}.",
106 files[i].getAbsolutePath(),
107 target.getAbsolutePath(),
108 e.getLocalizedMessage()),
109 e);
110 success = false;
111 }
112 }
113 return success;
114 }
115
116 return false;
117 }
118
119 /***
120 * Shows an input dialog and returns the entered value or <code>null</code>.
121 * @param parent the parent component the input dialog is centered on
122 * @param message the message giving details about the requested input
123 * @param title the title of the dialog
124 * @return the entered value or <code>null</code> if the dialog was cancelled
125 */
126 public static String requestInput(Component parent, String message, String title)
127 {
128 return JOptionPane.showInputDialog
129 (parent, message, title, JOptionPane.QUESTION_MESSAGE);
130 }
131
132 /***
133 * Shows a password input dialog and returns the entered value or <code>null</code>.
134 * @param parent the parent component the input dialog is centered on
135 * @param message the message giving details about the requested input
136 * @param title the title of the dialog
137 * @return the entered value or <code>null</code> if the dialog was cancelled
138 */
139 public static String requestPassword(Component parent, String message, String title)
140 {
141 JPasswordField passwordField = new JPasswordField();
142 Object[] content = new Object[] {
143 message,
144 passwordField,
145 };
146
147 if (JOptionPane.showConfirmDialog(parent, content, title,
148 JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE)
149 == JOptionPane.OK_OPTION) {
150 return new String(passwordField.getPassword());
151 } else {
152 return null;
153 }
154 }
155
156 /***
157 * Shows a confirmation dialog asking the user if he really wants to quit
158 * the application.
159 * <p>
160 * It also offers a checkbox "Always quit without prompting me." If the user
161 * checks it, the next time this function is called it will return <code>true</code>
162 * without showing the dialog.
163 * @param parent the parent component this dialog is centered on
164 * @param message a message explaining what it means to quit the
165 * application
166 * @param setting the boolean setting that stores the state of the checkbox
167 * @return true, if user presses okay button.
168 */
169 public static boolean showCloseDialog(Component parent, String message, BooleanSetting setting)
170 {
171 JCheckBox alwaysQuitCheckBox
172 = new JCheckBox(i18n.tr("Always quit without prompting me"));
173 if (setting != null) {
174 alwaysQuitCheckBox.setSelected(setting.getValue());
175 }
176
177 Object[] content = new Object[] {
178 message,
179 i18n.tr("Do you really want to quit?"),
180 alwaysQuitCheckBox
181 };
182
183 int response = JOptionPane.showConfirmDialog
184 (parent, content, i18n.tr("Quit"), JOptionPane.OK_CANCEL_OPTION);
185
186 setting.setValue(alwaysQuitCheckBox.isSelected());
187
188 return (response == JOptionPane.OK_OPTION);
189 }
190
191 /***
192 * Shows a confirmation dialog and with a message and check box that can
193 * be selected to not display the dialog in the future anymore.
194 *
195 * <p>If the specified setting is not <code>null</code> and it's value is
196 * <code>false</code> the dialog is not displayed and
197 * <code>JOptionPane.YES_OPTION</code> is returned.
198 *
199 * @param parent parent component used for centering the dialog
200 * @param message the message to show
201 * @param title the title of the message border
202 * @param optionType an int designating the options available on the
203 * dialog: <code>JOptionPane.YES_NO_OPTION</code>, or
204 * <code>JOptionPane.YES_NO_CANCEL_OPTION</code>
205 * @param setting used to store the reverse state of the
206 * <it>Do not ask me again</it> check box; if null, the state is not
207 * saved
208 * @return an int indicating the option selected by user
209 */
210 public static int showConfirmDialog(Component parent,
211 String message,
212 String title,
213 int optionType,
214 BooleanSetting setting)
215 {
216 if (setting != null && !setting.getValue()) {
217 return JOptionPane.YES_OPTION;
218 }
219
220 JCheckBox doNotAskAgainCheckBox = new JCheckBox(i18n.tr("Do not ask again"));
221
222 JLabel messageLabel = new JLabel(GUIHelper.tt(message, 400));
223
224
225 Object[] content = new Object[] {
226 messageLabel,
227 Box.createVerticalStrut(10),
228 doNotAskAgainCheckBox,
229 Box.createVerticalStrut(5),
230 };
231
232 int response = JOptionPane.showConfirmDialog
233 (parent, content, title, optionType);
234
235 if (setting != null) {
236 setting.setValue(!doNotAskAgainCheckBox.isSelected());
237 }
238
239 return response;
240 }
241
242 /***
243 * Displays a dialog that with a list of files asking the user to confirm
244 * a copy operation to the specified target.
245 *
246 * <p>If the specified setting is not <code>null</code> and it's value is
247 * <code>false</code> the dialog is not displayed and the specified
248 * files are returned.
249 *
250 * @param parent the dialog parent
251 * @param files the files that are to be displayed in the list
252 * @param target the destination path
253 * @param setting used to store the reverse state of the
254 * <it>Do not ask me again</it> check box; if null, the state is not
255 * saved
256 * @return the selected files, i.e. the ones that should be copied; if the
257 * user selected cancel an empty array is returned, never returns null
258 *
259 * @see #showFilesActionDialog(Component, File[], String, String, BooleanSetting)
260 */
261 public static File[] showCopyDialog(Component parent, File files[], File target,
262 BooleanSetting setting)
263 {
264 return showFilesActionDialog
265 (parent, files,
266 i18n.trn("Do you really want to copy the selected file to \"{0}\"?",
267 "Do you really want to copy the selected files to \"{0}\"?",
268 files.length,
269 target.getAbsolutePath()),
270 i18n.tr("Copy Files"), setting);
271 }
272
273 /***
274 * Displays a dialog that with a list of files asking the user to confirm
275 * a delete operation.
276 *
277 * <p>If the specified setting is not <code>null</code> and it's value is
278 * <code>false</code> the dialog is not displayed and the specified
279 * files are returned.
280 *
281 * @param parent the dialog parent
282 * @param files the files that are to be displayed in the list
283 * @param setting used to store the reverse state of the
284 * <it>Do not ask me again</it> check box; if null, the state is not
285 * saved
286 * @return the selected files, i.e. the ones that should be copied; if the
287 * user selected cancel an empty array is returned, never returns null
288 *
289 * @see #showFilesActionDialog(Component, File[], String, String, BooleanSetting)
290 */
291 public static File[] showDeleteDialog(Component parent, File files[],
292 BooleanSetting setting)
293 {
294 return showFilesActionDialog
295 (parent, files, i18n.tr("Do you really want to delete the selected files?"),
296 i18n.tr("Delete Files"), setting);
297 }
298
299 /***
300 * Displays a dialog with a message indicating the cause of an error. The
301 * dialog's title is set to <tt>Error</tt>.
302 *
303 * @param parent the parent component
304 * @param message the error message
305 */
306 public static void showError(Component parent, String message)
307 {
308 showError(parent, message, i18n.tr("Error"));
309 }
310
311 /***
312 * Displays a dialog with a message indicating the cause of an error
313 * a stack trace of the specified exception providing details. The dialog's
314 * title is set to <tt>Error</tt>.
315 *
316 * @param parent the parent component
317 * @param message the error message
318 */
319 public static void showError(Component parent, String message, Exception e)
320 {
321 showError(parent, message, i18n.tr("Error"), e);
322 }
323
324 /***
325 * Displays a dialog with a message indicating the cause of an error.
326 *
327 * @param parent the parent component
328 * @param message the error message
329 * @param title the dialog title
330 */
331 public static void showError(Component parent, String message, String title)
332 {
333 JOptionPane.showMessageDialog
334 (parent, message, title, JOptionPane.ERROR_MESSAGE);
335 }
336
337 /***
338 * Displays a dialog with a message indicating the cause of an error
339 * a stack trace of the specified exception providing details.
340 *
341 * @param parent the parent component
342 * @param message the error message
343 * @param title the dialog title
344 * @param exception the exception that caused the error
345 */
346 public static void showError(Component parent, String message, String title,
347 Exception exception)
348 {
349 ErrorDialog.show(parent, message, title, exception
350
351 );
352 }
353
354 /***
355 * Displays a dialog with a message, a list of files and a check box that
356 * can be selected to not display the dialog in the future anymore.
357 *
358 * <p>If the specified setting is not <code>null</code> and it's value is
359 * <code>false</code> the dialog is not displayed and the specified
360 * files are returned.
361 *
362 * @param parent the dialog parent
363 * @param files the files that are to be displayed in the list
364 * @param title the dialog's title
365 * @param message the message
366 * @param setting used to store the reverse state of the
367 * <it>Do not ask me again</it> check box; if null, the state is not
368 * saved
369 * @return the selected files; if the dialog was cancelled an empty array
370 * is returned, never returns null
371 */
372 public static File[] showFilesActionDialog
373 (Component parent, File files[], String message, String title,
374 BooleanSetting setting)
375 {
376 if (setting != null && !setting.getValue()) {
377 return files;
378 }
379
380 JList fileList = new JList(files);
381 fileList.setCellRenderer(new FileListCellRenderer());
382 fileList.setVisibleRowCount(4);
383
384
385 fileList.setSelectionInterval(0, files.length - 1);
386
387 JCheckBox doNotAskAgainCheckBox = new JCheckBox(i18n.tr("Do not ask again"));
388
389 Object[] content = new Object[] {
390 message,
391 Box.createVerticalStrut(10),
392 new JScrollPane(fileList),
393 Box.createVerticalStrut(10),
394 doNotAskAgainCheckBox,
395 Box.createVerticalStrut(5),
396 };
397
398 int response = JOptionPane.showConfirmDialog
399 (parent, content, title, JOptionPane.YES_NO_OPTION);
400
401 if (setting != null) {
402 setting.setValue(!doNotAskAgainCheckBox.isSelected());
403 }
404
405 if (response == JOptionPane.YES_OPTION) {
406 Object rows[] = fileList.getSelectedValues();
407 File selected[] = new File[rows.length];
408 System.arraycopy(rows, 0, selected, 0, selected.length);
409 return selected;
410 }
411
412 return new File[0];
413 }
414
415 /***
416 * Displays a dialog with an information message.
417 *
418 * @param parent the parent component
419 * @param message the error message
420 * @param title the dialog title
421 *
422 * @see JOptionPane#showMessageDialog(java.awt.Component, java.lang.Object, java.lang.String, int)
423 */
424 public static void showInfo(Component parent, String message, String title)
425 {
426 JOptionPane.showMessageDialog
427 (parent, message, title, JOptionPane.INFORMATION_MESSAGE);
428 }
429
430 /***
431 * Displays a dialog that with a list of files asking the user to confirm
432 * a delete operation.
433 *
434 * <p>If the specified setting is not <code>null</code> and it's value is
435 * <code>false</code> the dialog is not displayed and the specified
436 * files are returned.
437 *
438 * @param parent the dialog parent
439 * @param files the files that are to be displayed in the list
440 * @param target the destination path
441 * @param setting used to store the reverse state of the
442 * <it>Do not ask me again</it> check box; if null, the state is not
443 * saved
444 * @return the selected files, i.e. the ones that should be copied; if the
445 * user selected cancel an empty array is returned, never returns null
446 *
447 * @see #showFilesActionDialog(Component, File[], String, String, BooleanSetting)
448 */
449 public static File[] showMoveDialog(Component parent, File files[], File target,
450 BooleanSetting setting)
451 {
452 return showFilesActionDialog
453 (parent, files,
454 i18n.tr("Do you really want to move the selected files to \"{0}\"?",
455 target.getAbsolutePath()),
456 i18n.tr("Move Files"), setting);
457 }
458
459 /***
460 * This class provides a list renderer for <code>File</code> objects. The
461 * path is supressed when showing filenames.
462 */
463 public static class FileListCellRenderer extends DefaultListCellRenderer
464 {
465
466 public FileListCellRenderer()
467 {
468 }
469
470 public Component getListCellRendererComponent(JList list, Object value,
471 int index,
472 boolean isSelected,
473 boolean cellHasFocus)
474 {
475 super.getListCellRendererComponent(list, value, index, isSelected,
476 cellHasFocus);
477
478 if (value instanceof File) {
479 setText(((File)value).getName());
480 }
481
482 return this;
483 }
484
485 }
486
487 }
488