1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.sf.firemox.tools;
21
22 import java.awt.Color;
23 import java.awt.Dimension;
24 import java.awt.Graphics;
25 import java.awt.Graphics2D;
26 import java.awt.Image;
27 import java.awt.RenderingHints;
28 import java.awt.image.BufferedImage;
29 import java.io.BufferedInputStream;
30 import java.io.BufferedOutputStream;
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.FileOutputStream;
34 import java.io.IOException;
35 import java.net.MalformedURLException;
36 import java.net.URL;
37 import java.net.URLConnection;
38
39 import javax.swing.JComponent;
40
41 import net.sf.firemox.clickable.target.card.CardFactory;
42 import net.sf.firemox.database.DatabaseFactory;
43 import net.sf.firemox.management.MonitoredCheckContent;
44 import net.sf.firemox.token.IdConst;
45 import net.sf.firemox.ui.MagicUIComponents;
46 import net.sf.firemox.ui.ToolKit;
47 import net.sf.firemox.ui.component.LoaderConsole;
48 import net.sf.firemox.ui.i18n.LanguageManager;
49
50 import org.apache.commons.io.FileUtils;
51 import org.apache.commons.io.IOUtils;
52
53 import sun.awt.image.ToolkitImage;
54
55 /***
56 * A JComponent displaying an image. The picture is sized to suit to the
57 * component size.<br>
58 * <ul>
59 * TODO Add context menu to this component to:
60 * <li>display the picture with right size</li>
61 * <li>obtain more information about illustrator</li>
62 * </ul>
63 *
64 * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
65 * @author brius for http proxy configuration
66 * @since 0.83 Empty file are deleted to force file to be downloaded.
67 */
68 public class Picture extends JComponent {
69
70 /***
71 * The string delimiting the jar/zip content.
72 */
73 public static final String STR_ZIP_PATH = "!/";
74
75 /***
76 * Creates a new instance of Picture <br>
77 * The displayed picture will be the back picture of current TBS game. If no
78 * TBS game is loaded, no picture would be drawn. The [preferred]size of this
79 * component will be set to the given dimensions.
80 *
81 * @param width
82 * the fixed width of this picture
83 * @param height
84 * the fixed height of this picture
85 */
86 public Picture(int width, int height) {
87 setPreferredSize(new Dimension(width, height));
88 setSize(width, height);
89 setImage(DatabaseFactory.backImage, null);
90 }
91
92 /***
93 * Set the image and card's name to display. Repaint method is called
94 * immediately.
95 *
96 * @param cardImage
97 * the new card's image to display.
98 * @param cardName
99 * the new card's name to use as tooltip.
100 */
101 public void setImage(Image cardImage, String cardName) {
102 if (cardImage != this.cardImage || cardName != this.cardName) {
103 this.cardImage = cardImage;
104 this.cardName = cardName;
105 if (cardName == null) {
106 setToolTipText("??");
107 } else {
108 setToolTipText(cardName);
109 }
110 repaint();
111 }
112 }
113
114 /***
115 * Download a file from the specified URL to the specified local file.
116 *
117 * @param localFile
118 * is the new card's picture to try first
119 * @param remoteFile
120 * is the URL where this picture will be downloaded in case of the
121 * specified card name has not been found locally.
122 * @since 0.83 Empty file are deleted to force file to be downloaded.
123 */
124 public static void download(String localFile, URL remoteFile) {
125 download(localFile, remoteFile, null);
126 }
127
128 /***
129 * Download a file from the specified URL to the specified local file.
130 *
131 * @param localFile
132 * is the new card's picture to try first
133 * @param remoteFile
134 * is the URL where this picture will be downloaded in case of the
135 * specified card name has not been found locally.
136 * @param listener
137 * the component waiting for this picture.
138 * @since 0.83 Empty file are deleted to force file to be downloaded.
139 */
140 public static synchronized void download(String localFile, URL remoteFile,
141 MonitoredCheckContent listener) {
142 BufferedOutputStream out = null;
143 BufferedInputStream in = null;
144 final File toDownload = MToolKit.getFile(localFile, false);
145 if (toDownload.exists() && toDownload.length() == 0
146 && toDownload.canWrite()) {
147 toDownload.delete();
148 }
149 if (!toDownload.exists()
150 || (toDownload.length() == 0 && toDownload.canWrite())) {
151
152 try {
153 if ("file".equals(remoteFile.getProtocol())) {
154 File localRemoteFile = MToolKit.getFile(remoteFile.toString()
155 .substring(7).replaceAll("%20", " "), false);
156 int contentLength = (int) localRemoteFile.length();
157 Log.info("Copying from " + localRemoteFile.getAbsolutePath());
158 LoaderConsole.beginTask(LanguageManager.getString("downloading")
159 + " " + localRemoteFile.getAbsolutePath() + "("
160 + FileUtils.byteCountToDisplaySize(contentLength) + ")");
161
162
163 in = new BufferedInputStream(new FileInputStream(localRemoteFile));
164 byte[] buf = new byte[2048];
165 int currentLength = 0;
166 boolean succeed = false;
167 for (int bufferLen = in.read(buf); bufferLen >= 0; bufferLen = in
168 .read(buf)) {
169 if (!succeed) {
170 toDownload.getParentFile().mkdirs();
171 out = new BufferedOutputStream(new FileOutputStream(localFile));
172 succeed = true;
173 }
174 currentLength += bufferLen;
175 if (out != null) {
176 out.write(buf, 0, bufferLen);
177 }
178 if (listener != null) {
179 listener.updateProgress(contentLength, currentLength);
180 }
181 }
182
183
184 IOUtils.closeQuietly(in);
185 IOUtils.closeQuietly(out);
186 in = null;
187 out = null;
188 return;
189 }
190
191
192 if (!MagicUIComponents.isUILoaded()) {
193 return;
194 }
195
196
197 final URLConnection connection = MToolKit.getHttpConnection(remoteFile);
198 int contentLength = connection.getContentLength();
199 in = new BufferedInputStream(connection.getInputStream());
200 Log.info("Download from " + remoteFile + "("
201 + FileUtils.byteCountToDisplaySize(contentLength) + ")");
202 LoaderConsole.beginTask(LanguageManager.getString("downloading") + " "
203 + remoteFile + "("
204 + FileUtils.byteCountToDisplaySize(contentLength) + ")");
205
206
207 byte[] buf = new byte[2048];
208 int currentLength = 0;
209 boolean succeed = false;
210 for (int bufferLen = in.read(buf); bufferLen >= 0; bufferLen = in
211 .read(buf)) {
212 if (!succeed) {
213 toDownload.getParentFile().mkdirs();
214 out = new BufferedOutputStream(new FileOutputStream(localFile));
215 succeed = true;
216 }
217 currentLength += bufferLen;
218 if (out != null) {
219 out.write(buf, 0, bufferLen);
220 }
221 if (listener != null) {
222 listener.updateProgress(contentLength, currentLength);
223 }
224 }
225
226
227 IOUtils.closeQuietly(in);
228 IOUtils.closeQuietly(out);
229 in = null;
230 out = null;
231 return;
232 } catch (IOException e1) {
233 if (MToolKit.getFile(localFile) != null) {
234 MToolKit.getFile(localFile).delete();
235 }
236 if (remoteFile.getFile().equals(remoteFile.getFile().toLowerCase())) {
237 Log.fatal("could not load picture " + localFile + " from URL "
238 + remoteFile + ", " + e1.getMessage());
239 }
240 String tmpRemote = remoteFile.toString().toLowerCase();
241 try {
242 download(localFile, new URL(tmpRemote), listener);
243 } catch (MalformedURLException e) {
244 Log.fatal("could not load picture " + localFile + " from URL "
245 + tmpRemote + ", " + e.getMessage());
246 }
247 }
248 }
249 }
250
251 /***
252 * Load the file picture and return the Image object.
253 *
254 * @param localFile
255 * is the new card's picture to try first
256 * @return the Image object representing this fileName picture
257 * @throws MalformedURLException
258 */
259 public static Image loadImage(String localFile) throws MalformedURLException {
260 if (localFile == null) {
261 return null;
262 }
263 MonitoredCheckContent res = loadImage(localFile, null);
264 if (res != null) {
265 return res.getContent();
266 }
267 return null;
268 }
269
270 /***
271 * Load the file picture and return the Image object. If the specified
272 * filename did not exist, the specified URL is used to download it.
273 *
274 * @param localFile
275 * is the new card's picture to try first
276 * @param remoteFile
277 * is the URL where this picture will be downloaded in case of the
278 * specified card name has not been found locally.
279 * @return the Image object representing this fileName picture
280 * @throws MalformedURLException
281 */
282 public static MonitoredCheckContent loadImage(String localFile, URL remoteFile)
283 throws MalformedURLException {
284 return loadImage(localFile, remoteFile, null);
285 }
286
287 /***
288 * Load the file picture and return the Image object. If the specified
289 * filename did not exist, the specified URL is used to download it.
290 *
291 * @param localFile
292 * is the new card's picture to try first
293 * @param remoteFile
294 * is the URL where this picture will be downloaded in case of the
295 * specified card name has not been found locally.
296 * @param listener
297 * the component waiting for this picture.
298 * @return the Image object representing this fileName picture
299 * @throws MalformedURLException
300 * @since 0.83 Empty file are deleted to force file to be downloaded.
301 * @since 0.90 zipped files are managed.
302 */
303 public static MonitoredCheckContent loadImage(String localFile,
304 URL remoteFile, MonitoredCheckContent listener)
305 throws MalformedURLException {
306 File toDownload = null;
307 try {
308
309 if (localFile.contains(STR_ZIP_PATH)) {
310 final String zipName = localFile.substring(0, localFile
311 .indexOf(STR_ZIP_PATH));
312 toDownload = MToolKit.getFile(zipName);
313 if (toDownload == null) {
314
315 toDownload = MToolKit.getFile(zipName, false);
316 if (toDownload.exists() && toDownload.isFile()
317 && toDownload.length() == 0) {
318
319 toDownload.delete();
320 }
321
322 if (!toDownload.exists()) {
323
324 if (remoteFile == null) {
325 return null;
326 }
327 download(zipName, new URL(remoteFile.toString().substring(0,
328 remoteFile.toString().indexOf(STR_ZIP_PATH))), listener);
329 }
330 }
331 return new MonitoredCheckContent(MToolKit.getLocalPicture("jar:"
332 + MToolKit.getFile(zipName, false).toURI().toURL()
333 + localFile.substring(localFile.indexOf(STR_ZIP_PATH))));
334 }
335
336 toDownload = MToolKit.getFile(localFile);
337 if (toDownload == null)
338 toDownload = MToolKit.getFile(localFile, false);
339 if (toDownload.exists() && toDownload.isFile()
340 && toDownload.length() == 0) {
341
342 toDownload.delete();
343 }
344
345 if (!toDownload.exists()) {
346
347 if (remoteFile == null) {
348 return null;
349 }
350 download(localFile, remoteFile, listener);
351 }
352
353 return new MonitoredCheckContent(MToolKit.getLocalPicture(localFile));
354 } catch (InterruptedException e) {
355
356 return null;
357 }
358 }
359
360 @Override
361 public void paint(Graphics g) {
362 Graphics2D g2d = (Graphics2D) g;
363 g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
364 RenderingHints.VALUE_INTERPOLATION_BILINEAR);
365 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
366 RenderingHints.VALUE_ANTIALIAS_ON);
367 g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
368 RenderingHints.VALUE_RENDER_QUALITY);
369 if (cardImage != null) {
370 g.drawImage(cardImage, 0, 0, getWidth(), getHeight(), this);
371 }
372 }
373
374 /***
375 * Return a scaled picture of the given one suiting to card dimension.
376 *
377 * @param image
378 * the original card picture.
379 * @return a scaled picture of the given one suiting to card dimension.
380 */
381 public static BufferedImage getScaledImage(Image image) {
382 BufferedImage buffImage = ((ToolkitImage) image).getBufferedImage();
383 return ToolKit
384 .getScaledInstance(buffImage, CardFactory.cardWidth,
385 CardFactory.cardHeight, IdConst.BORDER_WIDTH,
386 getBorderColor(buffImage));
387 }
388
389 /***
390 * Return the border color of this card. If the picture of this card is not
391 * <code>null</code> the returned color corresponds to the pixel placed on
392 * the topmost leftmost pixel.
393 *
394 * @return the border color of this card.
395 */
396 private static Color getBorderColor(BufferedImage image) {
397 Color borderColor;
398
399 if (CardFactory.borderColor != null) {
400
401 borderColor = CardFactory.borderColor;
402 } else {
403
404 if (image != null) {
405 borderColor = new Color(image.getRGB(0, 0));
406 if (borderColor.getRed() > 175 && borderColor.getGreen() > 175
407 && borderColor.getBlue() > 175) {
408 borderColor = Color.WHITE.darker();
409 } else {
410 borderColor = Color.BLACK.brighter();
411 }
412 } else {
413 borderColor = CardFactory.borderColor;
414 }
415 }
416 return borderColor;
417 }
418
419 /***
420 * card's image
421 */
422 private Image cardImage;
423
424 /***
425 * card's name
426 */
427 private String cardName;
428
429 }