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