1 //
2 // $Id: PicturePanel.java 95 2007-05-02 03:27:05 +0000 (mer., 02 mai 2007)
3 // /C=DE/ST=Baden-Wuerttemberg/O=ISDN4Linux/OU=Fritz
4 // Elfert/CN=svn-felfert@isdn4linux.de/emailAddress=fritz@fritz-elfert.de $
5 //
6 // jupload - A file upload applet.
7 // Copyright 2007 The JUpload Team
8 // Copyright 2002 Guillaume Chamberland-Larose
9 //
10 // Created: ?
11 // Creator: William JinHua Kwong
12 // Last modified: $Date: 2011-01-19 16:16:33 +0100 (mer., 19 janv. 2011) $
13 //
14 // This program is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free Software
16 // Foundation; either version 2 of the License, or (at your option) any later
17 // version. This program is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20 // details. You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software Foundation, Inc.,
22 // 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 package wjhk.jupload2.gui.image;
25
26 import java.awt.Canvas;
27 import java.awt.Cursor;
28 import java.awt.Graphics;
29 import java.awt.Image;
30 import java.awt.event.ComponentEvent;
31 import java.awt.event.ComponentListener;
32 import java.awt.event.MouseEvent;
33 import java.awt.event.MouseListener;
34
35 import javax.swing.AbstractButton;
36
37 import wjhk.jupload2.exception.JUploadException;
38 import wjhk.jupload2.filedata.PictureFileData;
39 import wjhk.jupload2.policies.UploadPolicy;
40
41 /**
42 * This panel is used to preview picture, when PictureUploadPolicy (or one of
43 * its inherited policy) is used. Manages the panel where pictures are
44 * displayed. <BR>
45 * Each time a user selects a file in the panel file, the PictureUploadPolicy
46 * calls
47 * {@link #setPictureFile(PictureFileData, AbstractButton, AbstractButton)}. I
48 * did an attempt to store the Image generated for the Panel size into the
49 * PictureFileData, to avoid to calculate the offscreenPicture each time the
50 * user select the same file again. But it doesn't work: the applet quickly runs
51 * out of memory, even after numerous calls of System.gc and finalize. <BR>
52 * <BR>
53 * This file is taken from the PictureApplet ((C) 2002 Guillaume
54 * Chamberland-Larose), available here: To contact Guillaume Chamberland-Larose
55 * for bugs, patches, suggestions: Please use the forums on the sourceforge web
56 * page for this project, located at:
57 * http://sourceforge.net/projects/picture-applet/ Updated : 2006 etienne_sf<BR>
58 * This program is free software; you can redistribute it and/or modify it under
59 * the terms of the GNU General Public License as published by the Free Software
60 * Foundation; either version 2 of the License, or (at your option) any later
61 * version. <BR>
62 * This program is distributed in the hope that it will be useful, but WITHOUT
63 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
64 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
65 * details. <BR>
66 * You should have received a copy of the GNU General Public License along with
67 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
68 * Place - Suite 330, Boston, MA 02111-1307, USA.
69 */
70
71 public class PicturePanel extends Canvas implements MouseListener,
72 ComponentListener {
73
74 /** A generated serialVersionUID, to avoid warning during compilation */
75 private static final long serialVersionUID = -3439340009940699981L;
76
77 private PictureFileData pictureFileData;
78
79 /**
80 * offscreenImage contains an image, that can be asked by
81 * {@link PictureFileData#getImage(Canvas, boolean)}. It is used to preview
82 * this picture.
83 */
84 private Image offscreenImage = null;
85
86 /**
87 * Indicates if the offscreen image should be calculated once and stored, to
88 * avoid to calculate it again. <BR>
89 * Indications: the offscreen image should be calculate only once for the
90 * picturePanel on the applet, and for each display when the user ask to
91 * display the fulscreen picture (by a click on the picturePanel).
92 */
93 private boolean hasToStoreOffscreenPicture = false;
94
95 /**
96 * The current upload policy.
97 */
98 protected UploadPolicy uploadPolicy;
99
100 /**
101 * Standard constructor.
102 *
103 * @param hasToStoreOffscreenPicture
104 * @param uploadPolicy The current upload policy
105 */
106 public PicturePanel(boolean hasToStoreOffscreenPicture,
107 UploadPolicy uploadPolicy) {
108 super();
109
110 this.hasToStoreOffscreenPicture = hasToStoreOffscreenPicture;
111 this.uploadPolicy = uploadPolicy;
112
113 // We want to trap the mouse actions on this picture.
114 addMouseListener(this);
115
116 // We want to know when a resize event occurs (to recalculate
117 // offscreenImage)
118 addComponentListener(this);
119 }
120
121 /**
122 * This setter is called by {@link PictureFileData} to set the picture that
123 * is to be previewed.
124 *
125 * @param pictureFileData The FileData for the image to be displayed. Null
126 * if no picture should be displayed.
127 * @param button1 A button that will be activated or not, depending of the
128 * pictures was correctly set into the panel. May be null, if not
129 * button is to be enabled.
130 * @param button2 Another button that will be activated or not. May also be
131 * null.
132 */
133 public void setPictureFile(PictureFileData pictureFileData,
134 AbstractButton button1, AbstractButton button2) {
135 // First : reset current picture configuration.
136 this.pictureFileData = null;
137 if (this.offscreenImage != null) {
138 this.offscreenImage.flush();
139 this.offscreenImage = null;
140 }
141
142 // Ask for an immediate repaint, to clear the panel (as offscreenImage
143 // is now null).
144 repaint();
145
146 // Then, we store the new picture data, get the offscreen picture and
147 // ask for a repaint.
148 boolean enableButton = false;
149 if (pictureFileData != null && pictureFileData.canRead()) {
150 this.pictureFileData = pictureFileData;
151
152 // A picture has been selected. The buttons must be enabled.
153 enableButton = true;
154
155 // Now, we display this picture.
156 calculateOffscreenImage();
157 repaint();
158 }
159
160 // Let's activate the given button ... if any.
161 if (button1 != null) {
162 button1.setEnabled(enableButton);
163 }
164 if (button2 != null) {
165 button2.setEnabled(enableButton);
166 }
167 }
168
169 /**
170 * @see java.awt.Canvas#paint(java.awt.Graphics)
171 */
172 @Override
173 public void paint(Graphics g) {
174 // First : clear the panel area.
175 g.clearRect(0, 0, getWidth(), getHeight());
176
177 /*
178 * The picture is calculated outside of the paint() event. See:
179 * calculateOffscreenImage() and componentResized. //Then, check if we
180 * must calculate the picture. if (pictureFileData != null) { //Now, we
181 * calculate the picture if we don't already have one. if
182 * (offscreenImage == null) { calculateOffscreenImage(); } }
183 */
184
185 // Then, display the picture, if any is defined.
186 if (this.offscreenImage != null) {
187 // Let's center this picture
188 int hMargin = (getWidth() - this.offscreenImage.getWidth(this)) / 2;
189 int vMargin = (getHeight() - this.offscreenImage.getHeight(this)) / 2;
190 g.drawImage(this.offscreenImage, hMargin, vMargin, this);
191 // Free the used memory.
192 this.offscreenImage.flush();
193 }
194 }
195
196 /**
197 * This function adds a quarter rotation to the current picture.
198 *
199 * @param quarter Number of quarters (90�) the picture should rotate. 1
200 * means rotating of 90� clockwise (?). Can be negative
201 * (counterclockwise), more than 1...
202 */
203 public void rotate(int quarter) {
204 if (this.pictureFileData != null) {
205 Cursor previousCursor = this.uploadPolicy.setWaitCursor();
206 this.pictureFileData.addRotation(quarter);
207 // The previously calculated picture is now wrong.
208 this.offscreenImage.flush();
209 this.offscreenImage = null;
210 calculateOffscreenImage();
211
212 repaint();
213 this.uploadPolicy.setCursor(previousCursor);
214 } else {
215 this.uploadPolicy
216 .displayWarn("Hum, this is really strange: there is no pictureFileData in the PicturePanel! Command is ignored.");
217 }
218 }
219
220 /**
221 * This method get the offscreenImage from the current pictureFileData. This
222 * image is null, if pictureFileData is null. In this case, the repaint will
223 * only clear the panel rectangle, on the screen.
224 */
225 private void calculateOffscreenImage() {
226 if (this.pictureFileData == null) {
227 // Nothing to do. offscreenImage should be null.
228 if (this.offscreenImage != null) {
229 this.offscreenImage = null;
230 this.uploadPolicy
231 .displayWarn("PicturePanel.calculateOffscreenImage(): pictureFileData is null (offscreenImage set to null");
232 }
233 } else if (this.offscreenImage == null) {
234 this.uploadPolicy
235 .displayDebug(
236 "PicturePanel.calculateOffscreenImage(): trying to calculate offscreenImage (PicturePanel.calculateOffscreenImage()",
237 30);
238 try {
239 this.offscreenImage = this.pictureFileData.getImage(this,
240 this.hasToStoreOffscreenPicture);
241 } catch (JUploadException e) {
242 this.uploadPolicy.displayErr(e);
243 // We won't try to display the picture for this file.
244 this.pictureFileData = null;
245 this.offscreenImage = null;
246 }
247 }
248 }
249
250 /**
251 * Is it really useful ??
252 */
253 @Override
254 protected void finalize() throws Throwable {
255 // super.finalize();
256 this.uploadPolicy.displayDebug("Within PicturePanel.finalize()", 10);
257
258 if (this.offscreenImage != null) {
259 this.offscreenImage.flush();
260 }
261 }
262
263 // ////////////////////////////////////////////////////////////////////////////////////////////////////
264 // /////////////////////// MouseListener interface
265 // ////////////////////////////////////////////////////////////////////////////////////////////////////
266 /** @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) */
267 public void mouseClicked(MouseEvent arg0) {
268 if (this.pictureFileData != null) {
269 // Ok, we have a picture. Let's display it.
270 this.uploadPolicy.onFileDoubleClicked(this.pictureFileData);
271 }
272 }
273
274 /** @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) */
275 public void mouseEntered(MouseEvent arg0) {
276 // Nothing to do.
277 }
278
279 /** @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) */
280 public void mouseExited(MouseEvent arg0) {
281 // Nothing to do.
282 }
283
284 /** @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) */
285 public void mousePressed(MouseEvent arg0) {
286 // Nothing to do.
287 }
288
289 /** @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) */
290 public void mouseReleased(MouseEvent arg0) {
291 // Nothing to do.
292 }
293
294 // ////////////////////////////////////////////////////////////////////////////////////////////////////
295 // /////////////////////// ComponentListener interface
296 // ////////////////////////////////////////////
297 // ////////////////////////////////////////////////////////////////////////////////////////////////////
298 /**
299 * @see java.awt.event.ComponentListener#componentHidden(java.awt.event.ComponentEvent)
300 */
301 public void componentHidden(ComponentEvent arg0) {
302 // No action
303 }
304
305 /**
306 * @see java.awt.event.ComponentListener#componentMoved(java.awt.event.ComponentEvent)
307 */
308 public void componentMoved(ComponentEvent arg0) {
309 // No action
310 }
311
312 /**
313 * @see java.awt.event.ComponentListener#componentResized(java.awt.event.ComponentEvent)
314 */
315 public void componentResized(ComponentEvent arg0) {
316 if (this.offscreenImage != null) {
317 this.offscreenImage.flush();
318 this.offscreenImage = null;
319 }
320
321 // Then we calculate a new image for this panel.
322 calculateOffscreenImage();
323 repaint();
324 }
325
326 /**
327 * @see java.awt.event.ComponentListener#componentShown(java.awt.event.ComponentEvent)
328 */
329 public void componentShown(ComponentEvent arg0) {
330 // No action
331 }
332 }