View Javadoc
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 }