1 //
2 // $Id: JUploadPanelImpl.java 295 2007-06-27 08:43:25 +0000 (mer., 27 juin 2007)
3 // etienne_sf $
4 //
5 // jupload - A file upload applet.
6 // Copyright 2007 The JUpload Team
7 //
8 // Last modified: $Date: 2007-06-27 08:43:25 +0000 (mer., 27 juin 2007) $
9 //
10 // This program is free software; you can redistribute it and/or modify it under
11 // the terms of the GNU General Public License as published by the Free Software
12 // Foundation; either version 2 of the License, or (at your option) any later
13 // version. This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 // details. You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation, Inc.,
18 // 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 package wjhk.jupload2.gui.image;
21
22 /**
23 * This class contains the accessory that displays the image preview <B> in the
24 * file chooser</B>, when in picture mode.
25 *
26 * @see PictureUploadPolicy
27 */
28 import java.awt.Cursor;
29 import java.awt.Dimension;
30 import java.awt.Graphics;
31 import java.beans.PropertyChangeEvent;
32 import java.beans.PropertyChangeListener;
33 import java.io.File;
34
35 import javax.swing.ImageIcon;
36 import javax.swing.JComponent;
37 import javax.swing.JFileChooser;
38
39 import wjhk.jupload2.exception.JUploadException;
40 import wjhk.jupload2.filedata.PictureFileData;
41 import wjhk.jupload2.policies.UploadPolicy;
42
43 class LoadImageThread extends Thread {
44
45 /**
46 * That cursor that will be used each time the user select a new file, when
47 * resizing the picture before displaying in the preview accessory.
48 */
49 final Cursor waitCursor = new Cursor(Cursor.WAIT_CURSOR);
50
51 /**
52 * The file that is to be loaded.
53 */
54 File file;
55
56 /**
57 * The preview, where the resulting picture must be displayed.
58 */
59 JUploadImagePreview jUploadImagePreview;
60
61 /**
62 * Only constructor, with the file to be loaded.
63 *
64 * @param file The file to load, once the thread is started.
65 */
66 LoadImageThread(JUploadImagePreview jUploadImagePreview, File file) {
67 this.file = file;
68 this.jUploadImagePreview = jUploadImagePreview;
69 }
70
71 /**
72 * The work itself: it allows the loading and resizing of the picture in a
73 * separate thread, to avoid blocking the user interface.
74 */
75 @Override
76 public void run() {
77
78 this.jUploadImagePreview.uploadPolicy.displayDebug(
79 "LoadImageThread.start (start)", 50);
80 this.jUploadImagePreview.jFileChooser.setCursor(this.waitCursor);
81 ImageIcon thumbnail = null;
82 try {
83 thumbnail = PictureFileData.getImageIcon(this.file,
84 this.jUploadImagePreview.getWidth(),
85 this.jUploadImagePreview.getHeight(),
86 this.jUploadImagePreview.uploadPolicy);
87 } catch (JUploadException e) {
88 this.jUploadImagePreview.uploadPolicy.displayErr(e);
89 }
90
91 // A try to minimize memory footprint
92 PictureFileData.freeMemory("JUploadImagePreview.run()",
93 this.jUploadImagePreview.uploadPolicy);
94
95 if (thumbnail != null) {
96 this.jUploadImagePreview.setThumbnail(thumbnail);
97 }
98 this.jUploadImagePreview.jFileChooser.setCursor(null);
99 this.jUploadImagePreview.uploadPolicy.displayDebug(
100 "LoadImageThread.start (end)", 50);
101 }
102 }
103
104 /** ImagePreview.java by FileChooserDemo2.java. */
105 public class JUploadImagePreview extends JComponent implements
106 PropertyChangeListener {
107
108 /** A generated serialVersionUID, to avoid warning during compilation */
109 private static final long serialVersionUID = -6882108570945459638L;
110
111 /**
112 * The current upload policy.
113 */
114 UploadPolicy uploadPolicy;
115
116 /**
117 * Current file chooser, which owns this file preview.
118 */
119 JFileChooser jFileChooser = null;
120
121 /**
122 * The picture, resized to the preview size.
123 */
124 ImageIcon thumbnail = null;
125
126 /**
127 * The selected picture, which should contain the picture to display.
128 * Currently useless, as it is used only in the {@link #setFile(File)}
129 * method. It may be useful, in the future..
130 */
131 File file = null;
132
133 /**
134 * The current thread, that is loading the picture. A new thread is created,
135 * each time a new picture is to be loaded.
136 */
137 LoadImageThread loadImageThread = null;
138
139 /**
140 * The standard constructor for this class.
141 *
142 * @param jFileChooser The current file chooser, which will contain this
143 * acessory.
144 * @param uploadPolicy The current upload policy.
145 */
146 public JUploadImagePreview(JFileChooser jFileChooser,
147 UploadPolicy uploadPolicy) {
148 this.jFileChooser = jFileChooser;
149 this.uploadPolicy = uploadPolicy;
150
151 setPreferredSize(new Dimension(200, 200));
152 jFileChooser.addPropertyChangeListener(this);
153 }
154
155 /**
156 * Changes the current picture to display. This method is called by
157 * {@link LoadImageThread#start()} method, when the resized picture has been
158 * calculated.
159 *
160 * @param thumbnail
161 */
162 void setThumbnail(ImageIcon thumbnail) {
163 this.thumbnail = thumbnail;
164 repaint();
165 }
166
167 /**
168 * Changes the current file: this erases the current displayed picture, then
169 * call the {@link LoadImageThread#start()} method. This generate the
170 * picture asynchroneously. Directories are ignored.
171 */
172 void setFile(File fileParam) {
173 if (fileParam != null && fileParam.isDirectory()) {
174 this.file = null;
175 } else {
176 this.file = fileParam;
177 }
178
179 // First: clear the current picture.
180 this.thumbnail = null;
181 repaint();
182
183 // If a thread is running, let's stop it.
184 if (this.loadImageThread != null && this.loadImageThread.isAlive()) {
185 // Let's forget this thread.
186 this.loadImageThread.interrupt();
187 this.loadImageThread = null;
188 }
189
190 // Next: load aysnchronously the picture.
191 if (this.file != null) {
192 this.loadImageThread = new LoadImageThread(this, this.file);
193 // We want this thread to be executed before the icon loading
194 // threads.
195 this.loadImageThread.setPriority(Thread.MAX_PRIORITY);
196 // Let's start the thread, and exit: the applet is not blocked.
197 this.loadImageThread.start();
198 repaint();
199 }
200 }
201
202 /**
203 * Hum, we're interested in these events: DIRECTORY_CHANGED_PROPERTY and
204 * SELECTED_FILE_CHANGED_PROPERTY.
205 *
206 * @param e
207 */
208 public void propertyChange(PropertyChangeEvent e) {
209 String prop = e.getPropertyName();
210
211 if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(prop)) {
212 // The directory changed, don't show an image.
213 setFile(null);
214 } else if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(prop)) {
215 // If a file became selected, find out which one.
216 setFile((File) e.getNewValue());
217 }
218 }
219
220 /**
221 * Actual display of the picture. We just have to center the thumbnail,
222 * here.
223 */
224 @Override
225 protected void paintComponent(Graphics g) {
226 // Do we have a picture to display ?
227 if (this.thumbnail != null) {
228 int x = getWidth() / 2 - this.thumbnail.getIconWidth() / 2;
229 int y = getHeight() / 2 - this.thumbnail.getIconHeight() / 2;
230 if (y < 0) {
231 y = 0;
232 }
233 if (x < 5) {
234 x = 5;
235 }
236 this.thumbnail.paintIcon(this, g, x, y);
237 this.uploadPolicy.displayDebug(
238 "JUploadImagePreview.paintComponent, after paintIcon", 50);
239 }
240 }
241 }