001: /*
002: * $Revision: 1.1 $
003: * $Date: 2006/06/10 13:32:32 $
004: * $Author: fdietz $
005: *
006: * Copyright (C) 2001 C. Scott Willy
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License
010: * as published by the Free Software Foundation; either version 2
011: * of the License, or any later version.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public License
019: * along with this program; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
021: *
022: * Modified 2004/09/24
023: * By: Kelvin Eldridge
024: * Changes: Changed Title to 004.
025: * Changed buttons to all be the same size 85xpreferred component height.
026: * Add a space in front of labels to shift text from window border.
027: *
028: *
029: */
030:
031: package org.columba.mail.spellcheck.cswilly;
032:
033: import java.awt.Component;
034: import java.awt.Dialog;
035: import java.awt.Dimension;
036: import java.awt.Frame;
037: import java.awt.Point;
038: import java.awt.event.ActionEvent;
039: import java.awt.event.ActionListener;
040: import java.awt.event.KeyEvent;
041: import java.util.List;
042:
043: import javax.swing.AbstractAction;
044: import javax.swing.Box;
045: import javax.swing.JButton;
046: import javax.swing.JComponent;
047: import javax.swing.JDialog;
048: import javax.swing.JLabel;
049: import javax.swing.JList;
050: import javax.swing.JOptionPane;
051: import javax.swing.JPanel;
052: import javax.swing.JRootPane;
053: import javax.swing.JScrollPane;
054: import javax.swing.JTextField;
055: import javax.swing.KeyStroke;
056: import javax.swing.ListSelectionModel;
057: import javax.swing.event.ListSelectionEvent;
058: import javax.swing.event.ListSelectionListener;
059:
060: /**
061: * Dialog to the user to determine what to do about a misspelled word.
062: * <p>
063: * <p>
064: * Features of the dialog box:
065: * </p>
066: * <ul>
067: * <li>the dialog box is modal</li>
068: * <li>the title of the dialog box is set to "Spell Check"</li>
069: * <li>the user action change be determined using the getUserAction() method</li>
070: * <li>the possible user actions are modelled using the instances of the class
071: * UserAction (which is an enum-like thingy). The possible instances are give by
072: * public static text fields (e.g. ADD, and CANCEL) of type UserAction.</li>
073: * <li>the dialog box can be closed using the escape key (user action is
074: * CANCEL)</li>
075: * <li>there is a default button (<cite>Ignore</cite>)</li>
076: * <li>the buttons all have mnemonic keys</li>
077: * <li>??? todo set focus to <cite>Change to</cite> text field when dialog is
078: * opened</li>
079: * <li>??? todo add tool tips to all visual components</li>
080: * <li>??? todo move text to properties file</li>
081: * </ul>
082: * <p>
083: * Escape closes dialog
084: * (http://www.javaworld.com/javaworld/javatips/jw-javatip72.html)
085: */
086:
087: public class ValidationDialog extends JDialog {
088:
089: // ??? bad to have release hardocoded here. Fix later...right.
090:
091: private static Point _location = new Point(100, 100);
092:
093: public static final UserAction ADD = new UserAction("Add");
094:
095: public static final UserAction CANCEL = new UserAction("Cancel");
096:
097: public static final UserAction CHANGE = new UserAction("Change");
098:
099: public static final UserAction CHANGE_ALL = new UserAction(
100: "Change All");
101:
102: public static final UserAction IGNORE = new UserAction("Ignore");
103:
104: public static final UserAction IGNORE_ALL = new UserAction(
105: "Ignore All");
106:
107: private JTextField _changeToTextField;
108:
109: private final String _originalWord;
110:
111: private final List _suggestions;
112:
113: private JList _suggestionsJList;
114:
115: private UserAction _userAction = CANCEL;
116:
117: private String _title = "Spell Check, Release R004";
118:
119: public ValidationDialog(Frame owner, String originalWord,
120: List suggestions) {
121:
122: super (owner);
123:
124: _originalWord = originalWord;
125:
126: _suggestions = suggestions;
127:
128: _init();
129:
130: }
131:
132: public ValidationDialog(Dialog owner, String originalWord,
133: List suggestions) {
134:
135: super (owner);
136:
137: _originalWord = originalWord;
138:
139: _suggestions = suggestions;
140:
141: _init();
142:
143: }
144:
145: public ValidationDialog(String originalWord, List suggestions) {
146:
147: super ();
148:
149: _originalWord = originalWord;
150:
151: _suggestions = suggestions;
152:
153: _init();
154:
155: }
156:
157: public void dispose() {
158:
159: // save current location statically for next time
160:
161: _location = getLocation();
162:
163: super .dispose();
164:
165: }
166:
167: public UserAction getUserAction() {
168:
169: return _userAction;
170:
171: }
172:
173: /**
174: * Returns the replacement word selected by the user
175: * <p>
176: * The returned value only makes sense if the user action is either CHANGE
177: * or CHANGE_ALL. Should be ignored for any other action.
178: * <p>
179: *
180: * @return the replacement word selected by the user as a String
181: */
182:
183: public String getSelectedWord() {
184:
185: return _changeToTextField.getText();
186:
187: }
188:
189: /**
190: * Overriden to register {@link CloseDialogActionListener} to be called when
191: * the escape key is pressed.
192: */
193:
194: protected JRootPane createRootPane() {
195:
196: KeyStroke stroke = KeyStroke
197: .getKeyStroke(KeyEvent.VK_ESCAPE, 0);
198:
199: JRootPane rootPane = new JRootPane();
200:
201: ActionListener actionListener = new CloseDialogActionListener();
202:
203: rootPane.registerKeyboardAction(actionListener, stroke,
204:
205: JComponent.WHEN_IN_FOCUSED_WINDOW);
206:
207: return rootPane;
208:
209: }
210:
211: /**
212: * Convenience method add lableled component
213: */
214:
215: private void _addRow(Box mainBox, JComponent labelComponent,
216:
217: Component component) {
218:
219: Box hBox = Box.createHorizontalBox();
220:
221: mainBox.add(hBox);
222:
223: Dimension labelComponentDim = new Dimension(100,
224:
225: labelComponent.getPreferredSize().height);
226:
227: labelComponent.setPreferredSize(labelComponentDim);
228:
229: labelComponent.setMinimumSize(labelComponentDim);
230:
231: labelComponent.setMaximumSize(labelComponentDim);
232:
233: hBox.add(labelComponent);
234:
235: hBox.add(Box.createHorizontalGlue());
236:
237: hBox.add(component);
238:
239: hBox.add(Box.createHorizontalGlue());
240:
241: }
242:
243: /**
244: * Convenience method to create and config buttons from an action
245: * <p>
246: * After creating the JButton, sets the Mnemonic and ToolTipText by looking
247: * for the AbstractFilterAction.MNEMONIC_KEY and
248: * AbstractFilterAction.SHORT_DESCRIPTION keys in <code>action</code>.
249: * <p>
250: *
251: * @return a new, freshly configured JButton
252: */
253:
254: private static JButton _configButton(AbstractAction action) {
255:
256: JButton retButton = new JButton(action);
257:
258: Object value;
259:
260: value = action.getValue(AbstractAction.MNEMONIC_KEY);
261:
262: if (value != null) {
263:
264: int MnemonicKey = ((Integer) value).intValue();
265:
266: retButton.setMnemonic(MnemonicKey);
267:
268: }
269:
270: value = action.getValue(AbstractAction.SHORT_DESCRIPTION);
271:
272: if (value != null) {
273:
274: String toolTip = (String) value;
275:
276: retButton.setToolTipText(toolTip);
277:
278: }
279:
280: retButton.setMinimumSize(new Dimension(85, retButton
281: .getPreferredSize().height));
282:
283: retButton.setMaximumSize(new Dimension(85, retButton
284: .getPreferredSize().height));
285:
286: retButton.setPreferredSize(new Dimension(85, retButton
287: .getPreferredSize().height));
288:
289: return retButton;
290:
291: }
292:
293: /**
294: * Initializes the dialog box
295: */
296:
297: private void _init() {
298:
299: setModal(true);
300:
301: setTitle(_title);
302:
303: // --
304:
305: // -- Buttons
306:
307: // --
308:
309: JButton aboutButton = _configButton(new AboutAction());
310:
311: JButton addButton = _configButton(new AddAction());
312:
313: addButton.setEnabled(false);
314:
315: JButton cancelButton = _configButton(new CancelAction());
316:
317: JButton changeButton = _configButton(new ChangeAction());
318:
319: JButton changeAllButton = _configButton(new ChangeAllAction());
320:
321: JButton ignoreButton = _configButton(new IgnoreAction());
322:
323: JButton ignoreAllButton = _configButton(new IgnoreAllAction());
324:
325: // --
326:
327: // -- Text Fields
328:
329: // --
330:
331: _changeToTextField = new JTextField();
332:
333: _changeToTextField.setMinimumSize(new Dimension(200,
334:
335: _changeToTextField.getPreferredSize().height));
336:
337: _changeToTextField.setMaximumSize(new Dimension(
338: Integer.MAX_VALUE,
339:
340: _changeToTextField.getPreferredSize().height));
341:
342: JTextField originalWordTextField = new JTextField(_originalWord);
343:
344: originalWordTextField.setMinimumSize(new Dimension(200,
345:
346: originalWordTextField.getPreferredSize().height));
347:
348: originalWordTextField.setMaximumSize(new Dimension(
349: Integer.MAX_VALUE,
350:
351: originalWordTextField.getPreferredSize().height));
352:
353: // --
354:
355: // -- Other components
356:
357: // --
358:
359: _suggestionsJList = new JList(_suggestions.toArray());
360:
361: _suggestionsJList
362: .setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
363:
364: _suggestionsJList
365: .addListSelectionListener(new MyListSelectionListener());
366:
367: _suggestionsJList.setMinimumSize(new Dimension(200, 300));
368:
369: _suggestionsJList.setMaximumSize(new Dimension(
370: Integer.MAX_VALUE,
371:
372: Integer.MAX_VALUE));
373:
374: _suggestionsJList.setPreferredSize(new Dimension(200, 300));
375:
376: JScrollPane suggestionsJScrollPane = new JScrollPane(
377: _suggestionsJList);
378:
379: // suggestionsJScrollPane.setPreferredSize(
380:
381: // new Dimension( suggestionsJScrollPane.getPreferredSize().width, 75 )
382: // );
383:
384: // --
385:
386: // -- Overall Dialog box
387:
388: // --
389:
390: Box mainBox = Box.createVerticalBox();
391:
392: getContentPane().add(mainBox);
393:
394: Box hBox;
395:
396: JLabel jLabel;
397:
398: jLabel = new JLabel(" Not in Dictionary:");
399:
400: _addRow(mainBox, jLabel, originalWordTextField);
401:
402: jLabel = new JLabel(" Change to:");
403:
404: _addRow(mainBox, jLabel, _changeToTextField);
405:
406: jLabel = new JLabel(" Suggestions:");
407:
408: hBox = Box.createHorizontalBox();
409:
410: // suggestionsJScrollPane.setMinimumSize( new Dimension( 200, 300 ) );
411:
412: // suggestionsJScrollPane.setMaximumSize( new Dimension(
413: // Integer.MAX_VALUE, Integer.MAX_VALUE ) );
414:
415: hBox.add(suggestionsJScrollPane);
416:
417: hBox.add(Box.createHorizontalGlue());
418:
419: getRootPane().setDefaultButton(ignoreButton);
420:
421: JPanel buttonPanel = new JPanel();
422:
423: buttonPanel.setPreferredSize(new Dimension(200, 100));
424:
425: buttonPanel.add(ignoreButton);
426:
427: buttonPanel.add(ignoreAllButton);
428:
429: buttonPanel.add(changeButton);
430:
431: buttonPanel.add(changeAllButton);
432:
433: buttonPanel.add(addButton);
434:
435: buttonPanel.add(cancelButton);
436:
437: buttonPanel.add(aboutButton);
438:
439: hBox.add(buttonPanel);
440:
441: hBox.add(Box.createHorizontalGlue());
442:
443: _addRow(mainBox, jLabel, hBox);
444:
445: if (_location != null) {
446:
447: setLocation(_location);
448:
449: }
450:
451: pack();
452:
453: _suggestionsJList.setSelectedIndex(0);
454:
455: _suggestionsJList.grabFocus();
456:
457: // setSize( 750, getPreferredSize().height );
458:
459: }
460:
461: /**
462: * Models a enum of UserActions
463: */
464:
465: public static class UserAction {
466:
467: private final String _name;
468:
469: private UserAction(String name) {
470:
471: _name = name;
472:
473: }
474:
475: public String toString() {
476:
477: return _name;
478:
479: }
480:
481: }
482:
483: // --
484:
485: // -- Availables Actions
486:
487: // --
488:
489: private class AboutAction extends AbstractAction {
490:
491: private AboutAction() {
492:
493: super ("About...");
494:
495: }
496:
497: public void actionPerformed(ActionEvent event) {
498:
499: String msg = "Based on interfacing Java with Aspell.\n" +
500:
501: "Hacked by C. Scott Willy to scratch an itch.\n" +
502:
503: "Copyright 2001 Scott Willy\n" +
504:
505: "http://www.geocities.com/cswilly/spellcheck/";
506:
507: String title = "About " + _title;
508:
509: JOptionPane.showMessageDialog(ValidationDialog.this , msg,
510: title,
511:
512: JOptionPane.INFORMATION_MESSAGE);
513:
514: }
515:
516: }
517:
518: private class AddAction extends AbstractAction {
519:
520: private AddAction() {
521:
522: super ("Add");
523:
524: putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_A));
525:
526: putValue(ACCELERATOR_KEY, new Integer(KeyEvent.VK_A));
527:
528: }
529:
530: public void actionPerformed(ActionEvent event) {
531:
532: _userAction = ADD;
533:
534: dispose();
535:
536: }
537:
538: }
539:
540: private class CancelAction extends AbstractAction {
541:
542: private CancelAction() {
543:
544: super ("Cancel");
545:
546: }
547:
548: public void actionPerformed(ActionEvent event) {
549:
550: _userAction = CANCEL;
551:
552: dispose();
553:
554: }
555:
556: }
557:
558: private class ChangeAction extends AbstractAction {
559:
560: private ChangeAction() {
561:
562: super ("Change");
563:
564: putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_C));
565:
566: putValue(ACCELERATOR_KEY, new Integer(KeyEvent.VK_C));
567:
568: putValue(
569: SHORT_DESCRIPTION,
570:
571: "Replaces the word not in the Not in Dictionary text field with the word in the Change to text field.");
572:
573: }
574:
575: public void actionPerformed(ActionEvent event) {
576:
577: _userAction = CHANGE;
578:
579: dispose();
580:
581: }
582:
583: }
584:
585: private class ChangeAllAction extends AbstractAction {
586:
587: private ChangeAllAction() {
588:
589: super ("Change All");
590:
591: putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_L));
592:
593: putValue(ACCELERATOR_KEY, new Integer(KeyEvent.VK_L));
594:
595: }
596:
597: public void actionPerformed(ActionEvent event) {
598:
599: _userAction = CHANGE_ALL;
600:
601: dispose();
602:
603: }
604:
605: }
606:
607: private class IgnoreAction extends AbstractAction {
608:
609: private IgnoreAction() {
610:
611: super ("Ignore");
612:
613: putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_I));
614:
615: putValue(ACCELERATOR_KEY, new Integer(KeyEvent.VK_I));
616:
617: }
618:
619: public void actionPerformed(ActionEvent event) {
620:
621: _userAction = IGNORE;
622:
623: dispose();
624:
625: }
626:
627: }
628:
629: private class IgnoreAllAction extends AbstractAction {
630:
631: private IgnoreAllAction() {
632:
633: super ("Ignore All");
634:
635: // putValue( MNEMONIC_KEY, new Integer(KeyEvent.VK_G) );
636:
637: // putValue( ACCELERATOR_KEY, new Integer(KeyEvent.VK_G) );
638:
639: putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_G));
640:
641: putValue(ACCELERATOR_KEY, new Integer(KeyEvent.VK_G));
642:
643: }
644:
645: public void actionPerformed(ActionEvent event) {
646:
647: _userAction = IGNORE_ALL;
648:
649: dispose();
650:
651: }
652:
653: }
654:
655: private class CloseDialogActionListener implements ActionListener {
656:
657: public void actionPerformed(ActionEvent actionEvent) {
658:
659: _userAction = CANCEL;
660:
661: dispose();
662:
663: }
664:
665: }
666:
667: private class MyListSelectionListener implements
668: ListSelectionListener {
669:
670: public void valueChanged(ListSelectionEvent e) {
671:
672: int selectedIndex = _suggestionsJList.getSelectedIndex();
673:
674: if (selectedIndex >= 0) {
675:
676: _changeToTextField.setText((String) _suggestions.get(
677:
678: selectedIndex));
679:
680: }
681:
682: }
683:
684: }
685:
686: }
|