1 | // Jomic - a viewer for comic book archives. |
2 | // Copyright (C) 2004-2011 Thomas Aglassinger |
3 | // |
4 | // This program is free software: you can redistribute it and/or modify |
5 | // it under the terms of the GNU General Public License as published by |
6 | // the Free Software Foundation, either version 3 of the License, or |
7 | // (at your option) any later version. |
8 | // |
9 | // This program is distributed in the hope that it will be useful, |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | // GNU General Public License for more details. |
13 | // |
14 | // You should have received a copy of the GNU General Public License |
15 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | package net.sf.jomic.ui; |
17 | |
18 | import java.awt.Toolkit; |
19 | import java.awt.event.ActionEvent; |
20 | import java.awt.event.ComponentAdapter; |
21 | import java.awt.event.ComponentEvent; |
22 | import java.awt.event.KeyEvent; |
23 | import java.beans.PropertyChangeEvent; |
24 | import java.beans.PropertyChangeListener; |
25 | |
26 | import javax.swing.AbstractAction; |
27 | import javax.swing.JDialog; |
28 | import javax.swing.JFormattedTextField; |
29 | import javax.swing.JOptionPane; |
30 | import javax.swing.JSpinner; |
31 | import javax.swing.KeyStroke; |
32 | import javax.swing.SpinnerNumberModel; |
33 | import javax.swing.SwingUtilities; |
34 | |
35 | import net.sf.jomic.comic.ComicView; |
36 | import net.sf.jomic.common.JomicTools; |
37 | import net.sf.jomic.common.PropertyConstants; |
38 | import net.sf.jomic.common.Settings; |
39 | import net.sf.jomic.tools.LocaleTools; |
40 | |
41 | /** |
42 | * Dialog to ask for a page to go. |
43 | * |
44 | * @author Thomas Aglassinger |
45 | */ |
46 | class GoToPageDialog extends JDialog |
47 | { |
48 | private static final String COMMAND_CANCEL = "cancel"; |
49 | private static final String COMMAND_OK = "ok"; |
50 | |
51 | private JomicTools jomicTools; |
52 | private LocaleTools localeTools; |
53 | private JOptionPane optionPane; |
54 | private JFormattedTextField pageField; |
55 | private JSpinner pageSpinner; |
56 | private SpinnerNumberModel pageSpinnerModel; |
57 | private Settings settings; |
58 | |
59 | public GoToPageDialog(JomicFrame frame) { |
60 | super(frame); |
61 | assert frame != null; |
62 | |
63 | ComicView comicView = frame.getComicView(); |
64 | |
65 | assert comicView != null; |
66 | |
67 | jomicTools = JomicTools.instance(); |
68 | localeTools = LocaleTools.instance(); |
69 | settings = Settings.instance(); |
70 | |
71 | int currentPage = comicView.getPage() + 1; |
72 | int maximumPage = comicView.getPageCount(); |
73 | Integer maximumPageAsInteger = new Integer(maximumPage); |
74 | String title = localeTools.getMessage("dialogs.goToPage.title"); |
75 | String pageLabel = localeTools.getMessage("dialogs.goToPage.pageLabel", maximumPageAsInteger); |
76 | |
77 | pageSpinnerModel = new SpinnerNumberModel(currentPage, 1, maximumPage, 1); |
78 | pageSpinner = new JSpinner(pageSpinnerModel); |
79 | |
80 | // Add keyboard support. |
81 | KeyStroke enterKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); |
82 | KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); |
83 | JSpinner.DefaultEditor spinnerEditor = (JSpinner.DefaultEditor) pageSpinner.getEditor(); |
84 | |
85 | pageField = spinnerEditor.getTextField(); |
86 | pageField.getInputMap().put(escapeKeyStroke, COMMAND_CANCEL); |
87 | pageField.getActionMap().put(COMMAND_CANCEL, new CancelAction()); |
88 | pageField.getInputMap().put(enterKeyStroke, COMMAND_OK); |
89 | pageField.getActionMap().put(COMMAND_OK, new OkAction()); |
90 | |
91 | setTitle(title); |
92 | optionPane = new JOptionPane(new Object[]{pageLabel, pageSpinner}, |
93 | JOptionPane.QUESTION_MESSAGE, |
94 | JOptionPane.OK_CANCEL_OPTION, |
95 | null); |
96 | optionPane.addPropertyChangeListener(JOptionPane.VALUE_PROPERTY, new OptionValueChangedListener(this)); |
97 | setContentPane(optionPane); |
98 | setModal(true); |
99 | setResizable(false); |
100 | pack(); |
101 | settings.applyComponentAreaProperty(PropertyConstants.GO_TO_PAGE_DIALOG_WINDOW, this); |
102 | addComponentListener(new PageFieldSetUp()); |
103 | } |
104 | |
105 | /** |
106 | * Get the number of the page to go. |
107 | */ |
108 | public int getPage() { |
109 | assert pageSelected(); |
110 | |
111 | return pageSpinnerModel.getNumber().intValue(); |
112 | } |
113 | |
114 | /** |
115 | * <code>True</code> if the user entered a page number and clicked "Ok". |
116 | */ |
117 | public boolean pageSelected() { |
118 | boolean result = false; |
119 | Object value = optionPane.getValue(); |
120 | |
121 | if ((value != null) && (value != JOptionPane.UNINITIALIZED_VALUE)) { |
122 | result = ((Integer) value).intValue() == JOptionPane.OK_OPTION; |
123 | } |
124 | return result; |
125 | } |
126 | |
127 | /** |
128 | * Action to click "Cancel". |
129 | */ |
130 | private final class CancelAction extends AbstractAction |
131 | { |
132 | private CancelAction() { |
133 | super(); |
134 | } |
135 | |
136 | public void actionPerformed(ActionEvent event) { |
137 | try { |
138 | optionPane.setValue(new Integer(JOptionPane.CANCEL_OPTION)); |
139 | } catch (Throwable error) { |
140 | jomicTools.showError(event, error); |
141 | } |
142 | } |
143 | } |
144 | |
145 | /** |
146 | * Action to validate page number and click "Ok" or beep. |
147 | */ |
148 | private final class OkAction extends AbstractAction |
149 | { |
150 | private OkAction() { |
151 | super(); |
152 | } |
153 | |
154 | public void actionPerformed(ActionEvent event) { |
155 | try { |
156 | if (pageField.isEditValid()) { |
157 | pageField.commitEdit(); |
158 | optionPane.setValue(new Integer(JOptionPane.OK_OPTION)); |
159 | } else { |
160 | Toolkit.getDefaultToolkit().beep(); |
161 | } |
162 | } catch (Throwable error) { |
163 | jomicTools.showError(event, error); |
164 | } |
165 | } |
166 | } |
167 | |
168 | /** |
169 | * PropertyChangeListener to close a GoToPageDialog when "Ok" or "Cancel" is clicked. |
170 | * |
171 | * @author Thomas Aglassinger |
172 | */ |
173 | private final class OptionValueChangedListener implements PropertyChangeListener |
174 | { |
175 | private JDialog dialog; |
176 | |
177 | private OptionValueChangedListener(JDialog newDialog) { |
178 | assert newDialog != null; |
179 | dialog = newDialog; |
180 | } |
181 | |
182 | public void propertyChange(PropertyChangeEvent event) { |
183 | try { |
184 | assert event != null; |
185 | assert event.getSource() == optionPane; |
186 | String propertyValue = event.getPropertyName(); |
187 | |
188 | assert propertyValue.equals(JOptionPane.VALUE_PROPERTY); |
189 | |
190 | if (dialog.isVisible()) { |
191 | settings.setComponentAreaProperty(PropertyConstants.GO_TO_PAGE_DIALOG_WINDOW, dialog); |
192 | dialog.setVisible(false); |
193 | } |
194 | } catch (Throwable error) { |
195 | jomicTools.showError(event, error); |
196 | } |
197 | } |
198 | } |
199 | |
200 | /** |
201 | * ComponentListerner to focus in <code>pageField</code> and select whole text in it so the |
202 | * user can simply start typing to enter a new page number. |
203 | * |
204 | * @author Thomas Aglassinger |
205 | */ |
206 | private final class PageFieldSetUp extends ComponentAdapter |
207 | { |
208 | private PageFieldSetUp() { |
209 | super(); |
210 | } |
211 | |
212 | public void componentShown(ComponentEvent componentEvent) { |
213 | Runnable setUpRunner = |
214 | new Runnable() |
215 | { |
216 | public void run() { |
217 | pageField.requestFocusInWindow(); |
218 | pageField.selectAll(); |
219 | } |
220 | }; |
221 | |
222 | SwingUtilities.invokeLater(setUpRunner); |
223 | } |
224 | } |
225 | } |