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.common; |
17 | |
18 | import java.awt.Image; |
19 | import java.awt.Toolkit; |
20 | import java.awt.event.ActionEvent; |
21 | import java.beans.PropertyChangeEvent; |
22 | import java.io.IOException; |
23 | import java.net.URL; |
24 | import java.text.ParseException; |
25 | import java.text.SimpleDateFormat; |
26 | import java.util.Date; |
27 | |
28 | import javax.imageio.ImageIO; |
29 | import javax.swing.Icon; |
30 | import javax.swing.ImageIcon; |
31 | import javax.swing.JFrame; |
32 | import javax.swing.JOptionPane; |
33 | import javax.swing.SwingUtilities; |
34 | |
35 | import net.sf.jomic.tools.ErrorTools; |
36 | import net.sf.jomic.tools.FileTools; |
37 | import net.sf.jomic.tools.LocaleTools; |
38 | import net.sf.jomic.tools.StringTools; |
39 | |
40 | import org.apache.commons.logging.Log; |
41 | import org.apache.commons.logging.LogFactory; |
42 | |
43 | /** |
44 | * Jomic-specific tools. |
45 | * |
46 | * @author Thomas Aglassinger |
47 | */ |
48 | public final class JomicTools |
49 | { |
50 | private static final String LOGO_RESOURCE = "logo.gif"; |
51 | private static /*@ spec_public nullable @*/ JomicTools instance; |
52 | private Log logger; |
53 | private FileTools fileTools; |
54 | private /*@ spec_public nullable @*/ FullScreenCancelabel fullScreenCancelabel; |
55 | private ErrorTools errorTools; |
56 | private LocaleTools localeTools; |
57 | private StringTools stringTools; |
58 | |
59 | private JomicTools() { |
60 | logger = LogFactory.getLog(JomicTools.class); |
61 | fileTools = FileTools.instance(); |
62 | errorTools = ErrorTools.instance(); |
63 | stringTools = StringTools.instance(); |
64 | localeTools = LocaleTools.instance(); |
65 | errorTools.setTitle(JOptionPane.WARNING_MESSAGE, localeTools.getMessage("dialogs.warning.title")); |
66 | errorTools.setTitle(JOptionPane.WARNING_MESSAGE, localeTools.getMessage("dialogs.error.title")); |
67 | errorTools.setShowStackTraceText(localeTools.getMessage("dialogs.error.showInternalCallStack")); |
68 | errorTools.setCannotChangePropertyText(localeTools.getMessage("errors.cannotChangePropertyFromXToY")); |
69 | } |
70 | |
71 | /** |
72 | * Make a beep, which is mostly useful to give an audible cue that some action |
73 | * could not be performed. |
74 | */ |
75 | public void beep() { |
76 | Toolkit.getDefaultToolkit().beep(); |
77 | } |
78 | |
79 | /** |
80 | * Show error message for being unable to process <code>event</code> (which may be null). |
81 | */ |
82 | public void showError(/*@ nullable @*/ ActionEvent event, Throwable error) { |
83 | // TODO: Disable full screen if neccessary. |
84 | errorTools.showError(event, error); |
85 | } |
86 | |
87 | public void setFullScreenCancelabel(/*@ nullable @*/ FullScreenCancelabel newFullScreebCancelabel) { |
88 | fullScreenCancelabel = newFullScreebCancelabel; |
89 | } |
90 | |
91 | /** |
92 | * Set icon of <code>frame</code> to the Jomic logo. |
93 | * |
94 | * @see JFrame#setIconImage(Image) |
95 | */ |
96 | public void setIconToJomicLogo(JFrame frame) { |
97 | try { |
98 | Image logoImage = ImageIO.read(getLogoImageUrl()); |
99 | |
100 | frame.setIconImage(logoImage); |
101 | } catch (IOException error) { |
102 | // TODO: change error message to something like "cannot read internal resource" |
103 | IllegalStateException error2 = new IllegalStateException(localeTools.getMessage( |
104 | "errors.cannotFindResourceForLogoImage", LOGO_RESOURCE)); |
105 | |
106 | error2.initCause(error); |
107 | throw error2; |
108 | } |
109 | } |
110 | |
111 | /** |
112 | * Get icon with the Jomic logo. |
113 | */ |
114 | public Icon getJomicLogo() { |
115 | URL imageUrl = getLogoImageUrl(); |
116 | Icon result = new ImageIcon(imageUrl); |
117 | |
118 | return result; |
119 | } |
120 | |
121 | /** |
122 | * Get the date the current version of Jomic was released. |
123 | * |
124 | * @see Version#DATE |
125 | */ |
126 | public Date getVersionDate() { |
127 | SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd"); |
128 | Date result; |
129 | |
130 | try { |
131 | result = dateFormatter.parse(Version.DATE); |
132 | } catch (ParseException error) { |
133 | Object[] options = new Object[]{Version.class.getName(), Version.DATE}; |
134 | String message = localeTools.getMessage("errors.cannotParseVersionDate", options); |
135 | IllegalStateException tunneledError = new IllegalStateException(message); |
136 | |
137 | tunneledError.initCause(error); |
138 | throw tunneledError; |
139 | } |
140 | return result; |
141 | } |
142 | |
143 | /** |
144 | * Get URL of Jomic logo image. |
145 | */ |
146 | private URL getLogoImageUrl() { |
147 | URL imageUrl = fileTools.getImageResource(LOGO_RESOURCE); |
148 | |
149 | if (imageUrl == null) { |
150 | throw new IllegalStateException(localeTools.getMessage( |
151 | "errors.cannotFindResourceForLogoImage", LOGO_RESOURCE)); |
152 | } |
153 | return imageUrl; |
154 | } |
155 | |
156 | //@ ensures instance != null; |
157 | public static synchronized JomicTools instance() { |
158 | if (instance == null) { |
159 | instance = new JomicTools(); |
160 | } |
161 | return instance; |
162 | } |
163 | |
164 | /** |
165 | * Show error message relative to <code>owner</code>, with localized message built from <code>key</code> |
166 | * , caused by <code>error</code>. |
167 | */ |
168 | //@ requires key.length > 0; |
169 | public void showError(/*@ nullable @*/ JFrame owner, String key, /*@ nullable @*/ Throwable error) { |
170 | showError(owner, key, null, error); |
171 | } |
172 | |
173 | /** |
174 | * Show error message relative to <code>owner</code>, with localized message built from <code>key</code> |
175 | * and <code>option</code>, caused by <code>error</code>. |
176 | */ |
177 | //@ requires key.length > 0; |
178 | public void showError(/*@ nullable @*/ JFrame owner, String key, Object option, |
179 | /*@ nullable @*/ Throwable error) { |
180 | Object[] options = new Object[]{option}; |
181 | |
182 | showError(owner, key, options, error); |
183 | } |
184 | |
185 | /** |
186 | * Show error message relative to <code>owner</code>, with localized message built from <code>key</code> |
187 | * and <code>options</code>, caused by <code>error</code>. |
188 | */ |
189 | //@ requires key.length > 0; |
190 | public void showError(/*@ nullable @*/ JFrame owner, String key, Object[] options, |
191 | /*@ nullable @*/ Throwable error) { |
192 | String message = localeTools.getMessage(key, options); |
193 | |
194 | showErrorMessage(owner, key, message, error); |
195 | } |
196 | |
197 | /** |
198 | * Show error message for being unable to change property according to <code>event</code>. |
199 | */ |
200 | public void showError(PropertyChangeEvent event, Throwable error) { |
201 | // TODO: Disable full screen. |
202 | errorTools.showError(event, error); |
203 | } |
204 | |
205 | /** |
206 | * Show warning message relative to <code>owner</code>, with localized message built from |
207 | * <code>key</code> and <code>option</code>, caused by <code>error</code>. |
208 | */ |
209 | //@ requires key.length > 0; |
210 | public void showWarning(/*@ nullable @*/ JFrame owner, String key, Object option, |
211 | /*@ nullable @*/ Throwable error) { |
212 | Object[] options = new Object[]{option}; |
213 | |
214 | showWarning(owner, key, options, error); |
215 | } |
216 | |
217 | /** |
218 | * Show warning message relative to <code>owner</code>, with localized message built from |
219 | * <code>key</code> and <code>options</code>, caused by <code>error</code>. |
220 | */ |
221 | //@ requires key.length > 0; |
222 | public void showWarning(/*@ nullable @*/ JFrame owner, String key, Object[] options, |
223 | /*@ nullable @*/ Throwable error) { |
224 | String message = localeTools.getMessage(key, options); |
225 | |
226 | showWarningMessage(owner, key, message, error); |
227 | } |
228 | |
229 | /** |
230 | * Show warning message relative to <code>owner</code>, with localized message built from |
231 | * <code>key</code>, caused by <code>error</code>. |
232 | */ |
233 | //@ requires key.length > 0; |
234 | public void showWarning(/*@ nullable @*/ JFrame owner, String key, /*@ nullable @*/ Throwable error) { |
235 | String message = localeTools.getMessage(key); |
236 | |
237 | showWarningMessage(owner, key, message, error); |
238 | } |
239 | |
240 | //@ requires key.length > 0; |
241 | private void showErrorMessage(/*@ nullable @*/ JFrame owner, String key, String message, |
242 | /*@ nullable @*/ Throwable error) { |
243 | showMessage(owner, JOptionPane.ERROR_MESSAGE, key, message, error); |
244 | } |
245 | |
246 | //@ requires key.length > 0; |
247 | private void showMessage(final /*@ nullable @*/ JFrame owner, final int messageType, String key, String message, |
248 | /*@ nullable @*/ final Throwable error) { |
249 | String messageText = message + "[key=" + key + "]"; |
250 | |
251 | if (messageType == JOptionPane.WARNING_MESSAGE) { |
252 | logger.warn(messageText, error); |
253 | } else { |
254 | assert messageType == JOptionPane.ERROR_MESSAGE : "messageType=" + messageType; |
255 | logger.error(messageText, error); |
256 | } |
257 | |
258 | final String errorMessage = stringTools.titled(message); |
259 | |
260 | if ((fullScreenCancelabel != null) && fullScreenCancelabel.isVisible()) { |
261 | SwingUtilities.invokeLater(new Runnable() { |
262 | public void run() { |
263 | try { |
264 | fullScreenCancelabel.performCancelAndWait(); |
265 | } catch (Exception fullScreenCancelError) { |
266 | logger.warn("cannot cancel full screen properly to show some message", fullScreenCancelError); |
267 | } |
268 | errorTools.showMessage(owner, messageType, errorMessage, error, true); |
269 | } |
270 | }); |
271 | } else { |
272 | errorTools.showMessage(owner, messageType, errorMessage, error, true); |
273 | } |
274 | } |
275 | |
276 | //@ requires key.length > 0; |
277 | private void showWarningMessage(/*@ nullable @*/ JFrame owner, String key, String message, |
278 | /*@ nullable @*/ Throwable error) { |
279 | showMessage(owner, JOptionPane.WARNING_MESSAGE, key, message, error); |
280 | } |
281 | } |