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 }