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