View Javadoc
1   //
2   // $Id: PictureUploadPolicy.java 295 2007-06-27 08:43:25 +0000 (mer., 27 juin
3   // 2007) etienne_sf $
4   //
5   // jupload - A file upload applet.
6   // Copyright 2007 The JUpload Team
7   //
8   // Created: 2006-05-06
9   // Creator: etienne_sf
10  // Last modified: $Date: 2015-03-10 20:59:42 +0100 (mar., 10 mars 2015) $
11  //
12  // This program is free software; you can redistribute it and/or modify it under
13  // the terms of the GNU General Public License as published by the Free Software
14  // Foundation; either version 2 of the License, or (at your option) any later
15  // version. This program is distributed in the hope that it will be useful, but
16  // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18  // details. You should have received a copy of the GNU General Public License
19  // along with this program; if not, write to the Free Software Foundation, Inc.,
20  // 675 Mass Ave, Cambridge, MA 02139, USA.
21  
22  package wjhk.jupload2.policies;
23  
24  import java.awt.Cursor;
25  import java.awt.GridLayout;
26  import java.awt.Image;
27  import java.awt.SystemColor;
28  import java.awt.event.ActionEvent;
29  import java.awt.event.ActionListener;
30  import java.awt.image.ImageObserver;
31  import java.io.File;
32  
33  import javax.swing.BorderFactory;
34  import javax.swing.Icon;
35  import javax.swing.ImageIcon;
36  import javax.swing.JButton;
37  import javax.swing.JOptionPane;
38  import javax.swing.JPanel;
39  
40  import wjhk.jupload2.context.JUploadContext;
41  import wjhk.jupload2.exception.JUploadException;
42  import wjhk.jupload2.exception.JUploadExceptionStopAddingFiles;
43  import wjhk.jupload2.exception.JUploadIOException;
44  import wjhk.jupload2.filedata.FileData;
45  import wjhk.jupload2.filedata.PictureFileData;
46  import wjhk.jupload2.filedata.helper.ImageFileConversionInfo;
47  import wjhk.jupload2.gui.JUploadFileChooser;
48  import wjhk.jupload2.gui.JUploadPanel;
49  import wjhk.jupload2.gui.image.JUploadImagePreview;
50  import wjhk.jupload2.gui.image.PictureDialog;
51  import wjhk.jupload2.gui.image.PicturePanel;
52  
53  /**
54   * This class add handling of pictures to upload. <BR>
55   * <BR>
56   * <H4>Functionalities:</H4>
57   * <UL>
58   * <LI>The top panel (upper part of the applet display) is modified, by using UploadPolicy.
59   * {@link wjhk.jupload2.policies.UploadPolicy#createTopPanel(JButton, JButton, JButton, JUploadPanel)} . It contains a
60   * <B>preview</B> picture panel, and two additional buttons to rotate the selected picture in one direction or the
61   * other.
62   * <LI>Ability to set maximum width or height to a picture (with maxPicWidth and maxPicHeight applet parameters, see the
63   * global explanation on the <a href="UploadPolicy.html#parameters">parameters</a> section) of the UploadPolicy API
64   * page.
65   * <LI>Rotation of pictures, by quarter of turn.
66   * <LI><I>(To be implemented)</I> A target picture format can be used, to force all uploaded pictures to be in one
67   * picture format, jpeg for instance. All details are in the UploadPolicy <a
68   * href="UploadPolicy.html#parameters">parameters</a> section.
69   * </UL>
70   * <BR>
71   * <BR>
72   * See an example of HTML that calls this applet, just below. <H4>Parameters</H4> The description for all parameters of
73   * all polices has been grouped in the UploadPolicy <a href="UploadPolicy.html#parameters">parameters</a> section. <BR>
74   * The parameters implemented in this class are:
75   * <UL>
76   * <LI>maxPicWidth: Maximum width for the uploaded picture.
77   * <LI>maxPicHeight: Maximum height for the uploaded picture.
78   * <LI>targetPictureFormat : Define picture format conversions.
79   * <LI>keepOriginalFileExtensionForConvertedImages : handling of file extensions for image conversions.
80   * </UL>
81   * <A NAME="example"> <H4>HTML call example</H4> </A> You'll find below an example of how to put the applet into a PHP
82   * page: <BR>
83   * <XMP> <APPLET NAME="JUpload" CODE="wjhk.jupload2.JUploadApplet" ARCHIVE="plugins/jupload/wjhk.jupload.jar" <!--
84   * Applet display size, on the navigator page --> WIDTH="500" HEIGHT="700" <!-- The applet call some javascript
85   * function, so we must allow it : --> MAYSCRIPT > <!-- First, mandatory parameters --> <PARAM NAME="postURL"
86   * VALUE="http://some.host.com/youruploadpage.php"> <PARAM NAME="uploadPolicy" VALUE="PictureUploadPolicy"> <!-- Then,
87   * optional parameters --> <PARAM NAME="lang" VALUE="fr"> <PARAM NAME="maxPicHeight" VALUE="768"> <PARAM
88   * NAME="maxPicWidth" VALUE="1024"> <PARAM NAME="debugLevel" VALUE="0"> Java 1.4 or higher plugin required. </APPLET>
89   * </XMP>
90   * 
91   * @author etienne_sf
92   * @version $Revision: 1715 $
93   */
94  
95  public class PictureUploadPolicy extends DefaultUploadPolicy implements ActionListener, ImageObserver {
96  
97      /**
98       * Indicates that a BufferedImage is to be created when the user selects the file. <BR>
99       * If true : the Image is loaded once from the hard drive. This consumes memory, but is interesting for big
100      * pictures, when they are resized (see {@link #maxWidth} and {@link #maxHeight}). <BR>
101      * If false : it is loaded for each display on the applet, then once for the upload. <BR>
102      * <BR>
103      * Default : false, because the applet, while in the navigator, runs too quickly out of memory.
104      * 
105      * @see wjhk.jupload2.policies.UploadPolicy#DEFAULT_STORE_BUFFERED_IMAGE
106      */
107     private boolean storeBufferedImage;
108 
109     /**
110      * This parameter can contain a list to convert image formats. <br />
111      * see class description of {@link UploadPolicy} for details
112      * 
113      * @see wjhk.jupload2.policies.UploadPolicy#DEFAULT_TARGET_PICTURE_FORMAT
114      */
115     private String targetPictureFormat;
116 
117     /**
118      * see class description of {@link UploadPolicy} for details
119      * 
120      * @see wjhk.jupload2.policies.UploadPolicy#DEFAULT_KEEP_ORIG_EXTENSION
121      */
122     private boolean keepOrigExtension;
123 
124     /**
125      * the parsed {@link #targetPictureFormat} list
126      */
127     private ImageFileConversionInfo imageFileConversionInfo = new ImageFileConversionInfo("");
128 
129     /**
130      * Stored value for the fileChooserIconFromFileContent applet property.
131      * 
132      * @see UploadPolicy#PROP_FILE_CHOOSER_IMAGE_PREVIEW
133      */
134     private boolean fileChooserImagePreview = UploadPolicy.DEFAULT_FILE_CHOOSER_IMAGE_PREVIEW;
135 
136     /**
137      * Indicates wether or not the preview pictures must be calculated by the BufferedImage.getScaledInstance() method.
138      */
139     private boolean highQualityPreview;
140 
141     /**
142      * Maximal width for the uploaded picture. If the actual width for the picture is more than maxWidth, the picture is
143      * resized. The proportion between widht and height are maintained. Negative if no maximum width (no resizing). <BR>
144      * Default: -1.
145      * 
146      * @see wjhk.jupload2.policies.UploadPolicy#DEFAULT_MAX_WIDTH
147      */
148     private int maxWidth = -1;
149 
150     /**
151      * Maximal height for the uploaded picture. If the actual height for the picture is more than maxHeight, the picture
152      * is resized. The proportion between width and height are maintained. Negative if no maximum height (no resizing). <BR>
153      * Default: -1.
154      * 
155      * @see wjhk.jupload2.policies.UploadPolicy#DEFAULT_MAX_HEIGHT
156      */
157     private int maxHeight = -1;
158 
159     /**
160      * Used to control the compression of a jpeg written file, after transforming a picture.
161      * 
162      * @see UploadPolicy#PROP_PICTURE_COMPRESSION_QUALITY
163      */
164     private float pictureCompressionQuality = UploadPolicy.DEFAULT_PICTURE_COMPRESSION_QUALITY;
165 
166     /**
167      * Used to control whether PictureFileData should add metadata to transformed picture files, before upload (or
168      * remove metadata from normally untransformed picture files).
169      */
170     private boolean pictureTransmitMetadata;
171 
172     /**
173      * @see UploadPolicy
174      */
175     private int realMaxWidth = -1;
176 
177     /**
178      * @see UploadPolicy
179      */
180     private int realMaxHeight = -1;
181 
182     /**
183      * Button to allow the user to rotate the picture one quarter counter-clockwise.
184      */
185     private JButton rotateLeftButton;
186 
187     /**
188      * Button to allow the user to rotate the picture one quarter clockwise.
189      */
190     private JButton rotateRightButton;
191 
192     /**
193      * The picture panel, where the selected picture is displayed.
194      */
195     private PicturePanel picturePanel;
196 
197     /**
198      * The standard constructor, which transmit most informations to the super.Constructor().
199      * 
200      * @param juploadContext Reference to the current applet. Allows access to javascript functions.
201      * @throws JUploadException
202      */
203     public PictureUploadPolicy(JUploadContext juploadContext) throws JUploadException {
204         super(juploadContext);
205 
206         // Creation of the PictureFileDataPolicy, from parameters given to the
207         // applet, or from default values.
208         setFileChooserImagePreview(juploadContext.getParameter(PROP_FILE_CHOOSER_IMAGE_PREVIEW,
209                 DEFAULT_FILE_CHOOSER_IMAGE_PREVIEW));
210         setHighQualityPreview(juploadContext.getParameter(PROP_HIGH_QUALITY_PREVIEW, DEFAULT_HIGH_QUALITY_PREVIEW));
211         setMaxHeight(juploadContext.getParameter(PROP_MAX_HEIGHT, DEFAULT_MAX_HEIGHT));
212         setMaxWidth(juploadContext.getParameter(PROP_MAX_WIDTH, DEFAULT_MAX_WIDTH));
213         setPictureCompressionQuality(juploadContext.getParameter(PROP_PICTURE_COMPRESSION_QUALITY,
214                 DEFAULT_PICTURE_COMPRESSION_QUALITY));
215         setPictureTransmitMetadata(juploadContext.getParameter(PROP_PICTURE_TRANSMIT_METADATA,
216                 DEFAULT_PICTURE_TRANSMIT_METADATA));
217         setRealMaxHeight(juploadContext.getParameter(PROP_REAL_MAX_HEIGHT, DEFAULT_REAL_MAX_HEIGHT));
218         setRealMaxWidth(juploadContext.getParameter(PROP_REAL_MAX_WIDTH, DEFAULT_REAL_MAX_WIDTH));
219         setTargetPictureFormat(juploadContext.getParameter(PROP_TARGET_PICTURE_FORMAT, DEFAULT_TARGET_PICTURE_FORMAT));
220 
221         setKeepOrigExtension(juploadContext.getParameter(PROP_KEEP_ORIG_EXTENSION, DEFAULT_KEEP_ORIG_EXTENSION));
222 
223         displayDebug("[PictureUploadPolicy] end of constructor", 30);
224     }
225 
226     /**
227      * This methods actually returns a {@link PictureFileData} instance. It allows only pictures: if the file is not a
228      * picture, this method returns null, thus preventing the file to be added to the list of files to be uploaded.
229      * 
230      * @param file The file selected by the user (called once for each added file).
231      * @return An instance of {@link PictureFileData} or null if file is not a picture.
232      * @see wjhk.jupload2.policies.UploadPolicy#createFileData(File,File)
233      */
234     @Override
235     public FileData createFileData(File file) throws JUploadExceptionStopAddingFiles {
236         // Do standard rules accept this file ?
237         FileData defaultFileData = super.createFileData(file);
238 
239         if (defaultFileData == null) {
240             // The file is not allowed.
241             return null;
242         } else {
243             // Ok, the file is to be accepted. Is it a picture?
244             PictureFileData pfd = null;
245             try {
246                 pfd = new PictureFileData(file, this);
247             } catch (JUploadIOException e) {
248                 displayErr(e);
249             }
250 
251             // If we get a pfd, let' check that it's a picture.
252             if (pfd != null && pfd.isPicture()) {
253                 return pfd;
254             } else if (getAllowedFileExtensions() != null) {
255                 // A list of allowed extensions has been given, and, as we got
256                 // here, defaultFileData is not null, that is: this files match
257                 // the allowedFileEXtensions parameter. We return it.
258                 return defaultFileData;
259             } else {
260                 // We now use the JUploadExceptionStopAddingFiles exception, to
261                 // allow the user to stop adding files.
262                 String msg = getLocalizedString("notAPicture", file.getName());
263 
264                 // Alert only once, when several files are not pictures... hum,
265                 displayWarn(msg);
266                 if (JOptionPane.showConfirmDialog(null, msg, "alert", JOptionPane.OK_CANCEL_OPTION,
267                         JOptionPane.WARNING_MESSAGE) == JOptionPane.CANCEL_OPTION) {
268                     // The user want to stop to add files to the list. For
269                     // instance, when he/she added a whole directory, and it
270                     // contains a lot of files that don't match the allowed file
271                     // extension.
272                     throw new JUploadExceptionStopAddingFiles("Stopped by the user");
273                 }
274                 return null;
275             }
276         }
277     }
278 
279     /**
280      * This method override the default topPanel, and adds:<BR>
281      * <UL>
282      * <LI>Two rotation buttons, to rotate the currently selected picture.
283      * <LI>A Preview area, to view the selected picture
284      * </UL>
285      * 
286      * @see wjhk.jupload2.policies.UploadPolicy#createTopPanel(JButton, JButton, JButton, JUploadPanel)
287      */
288     @Override
289     public JPanel createTopPanel(JButton browse, JButton remove, JButton removeAll, JUploadPanel jUploadPanel) {
290         // The top panel is verticaly divided in :
291         // - On the left, the button bar (buttons one above another)
292         // - On the right, the preview PicturePanel.
293 
294         // Creation of specific buttons
295         this.rotateLeftButton = new JButton(getLocalizedString("buttonRotateLeft"));
296         this.rotateLeftButton.setIcon(new ImageIcon(getClass().getResource("/images/rotateLeft.gif")));
297         this.rotateLeftButton.addActionListener(this);
298         this.rotateLeftButton.addMouseListener(jUploadPanel.getMouseListener());
299         this.rotateLeftButton.setEnabled(false);
300 
301         this.rotateRightButton = new JButton(getLocalizedString("buttonRotateRight"));
302         this.rotateRightButton.setIcon(new ImageIcon(getClass().getResource("/images/rotateRight.gif")));
303         this.rotateRightButton.addActionListener(this);
304         this.rotateRightButton.addMouseListener(jUploadPanel.getMouseListener());
305         this.rotateRightButton.setEnabled(false);
306 
307         // The button bar
308         JPanel buttonPanel = new JPanel();
309         buttonPanel.setLayout(new GridLayout(5, 1, 5, 5));
310         buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 5));
311         buttonPanel.add(browse);
312         buttonPanel.add(this.rotateLeftButton);
313         buttonPanel.add(this.rotateRightButton);
314         buttonPanel.add(removeAll);
315         buttonPanel.add(remove);
316 
317         // The preview PicturePanel
318         JPanel pPanel = new JPanel();
319         pPanel.setLayout(new GridLayout(1, 1));
320         pPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 10));
321 
322         this.picturePanel = new PicturePanel(true, this);
323         this.picturePanel.addMouseListener(jUploadPanel.getMouseListener());
324         pPanel.add(this.picturePanel);
325         // Setting specific cursor for this panel, default for other parts of
326         // the applet.
327         setCursor(null);
328 
329         // And last but not least ... creation of the top panel:
330         JPanel topPanel = new JPanel();
331         topPanel.setLayout(new GridLayout(1, 2));
332         topPanel.add(buttonPanel);
333         topPanel.add(pPanel);
334 
335         jUploadPanel.getJComponent().setBorder(BorderFactory.createLineBorder(SystemColor.controlDkShadow));
336 
337         return topPanel;
338     }// createTopPanel
339 
340     /**
341      * This method handles the clicks on the rotation buttons. All other actions are managed by the
342      * {@link DefaultUploadPolicy}.
343      * 
344      * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
345      */
346     public void actionPerformed(ActionEvent e) {
347         displayInfo("Action : " + e.getActionCommand());
348         if (e.getActionCommand() == this.rotateLeftButton.getActionCommand()) {
349             this.picturePanel.rotate(-1);
350         } else if (e.getActionCommand() == this.rotateRightButton.getActionCommand()) {
351             this.picturePanel.rotate(1);
352         }
353     }// actionPerformed
354 
355     /**
356      * @see wjhk.jupload2.policies.UploadPolicy#onFileSelected(wjhk.jupload2.filedata.FileData)
357      */
358     @Override
359     public void onFileSelected(FileData fileData) {
360         if (fileData != null) {
361             displayDebug("File selected: " + fileData.getFileName(), 30);
362         }
363         if (this.picturePanel != null) {
364             // If this file is a picture, we display it.
365             if (fileData instanceof PictureFileData) {
366                 Cursor previousCursor = setWaitCursor();
367                 this.picturePanel.setPictureFile((PictureFileData) fileData, this.rotateLeftButton,
368                         this.rotateRightButton);
369                 setCursor(previousCursor);
370             } else {
371                 this.picturePanel.setPictureFile(null, this.rotateLeftButton, this.rotateRightButton);
372             }
373         }
374     }
375 
376     /**
377      * Open the 'big' preview dialog box. It allows the user to see a full screen preview of the choosen picture.<BR>
378      * This method does nothing if the panel has no selected picture, that is when pictureFileData is null.
379      * 
380      * @see UploadPolicy#onFileDoubleClicked(FileData)
381      */
382     @Override
383     public void onFileDoubleClicked(FileData pictureFileData) {
384         if (pictureFileData == null) {
385             // No action
386         } else if (!(pictureFileData instanceof PictureFileData)) {
387             displayWarn("PictureUploadPolicy: received a non PictureFileData in onFileDoubleClicked");
388         } else {
389             new PictureDialog(null, (PictureFileData) pictureFileData, this);
390         }
391     }
392 
393     /** @see UploadPolicy#beforeUpload() */
394     @Override
395     public boolean beforeUpload() {
396         // We clear the current picture selection. This insures a correct
397         // managing of enabling/disabling of
398         // buttons, even if the user stops the upload.
399         getContext().getUploadPanel().getFilePanel().clearSelection();
400         if (this.picturePanel != null) {
401             this.picturePanel.setPictureFile(null, this.rotateLeftButton, this.rotateRightButton);
402         }
403 
404         // Then, we call the standard action, if any.
405         return super.beforeUpload();
406     }
407 
408     // ////////////////////////////////////////////////////////////////////////////////////////////////////
409     // /////////////////////// Getters and Setters
410     // ////////////////////////////////////////////////
411     // ////////////////////////////////////////////////////////////////////////////////////////////////////
412 
413     /**
414      * Getter for fileChooserImagePreview.
415      * 
416      * @return Current value for the applet parameter: fileChooserImagePreview
417      * @see UploadPolicy#PROP_FILE_CHOOSER_IMAGE_PREVIEW
418      */
419     public boolean getFileChooserImagePreview() {
420         return this.fileChooserImagePreview;
421     }
422 
423     /**
424      * Setter for fileChooserIconFromFileContent. Current allowed values are: -1, 0, 1. Default value is 0.
425      * 
426      * @param fileChooserImagePreview new value to store, for the applet parameter: fileChooserImagePreview.
427      * @see UploadPolicy#PROP_FILE_CHOOSER_IMAGE_PREVIEW
428      */
429     public void setFileChooserImagePreview(boolean fileChooserImagePreview) {
430         this.fileChooserImagePreview = fileChooserImagePreview;
431     }
432 
433     /** @return the applet parameter <I>highQualityPreview</I>. */
434     public boolean getHighQualityPreview() {
435         return this.highQualityPreview;
436     }
437 
438     /** @param highQualityPreview the highQualityPreview to set */
439     void setHighQualityPreview(boolean highQualityPreview) {
440         this.highQualityPreview = highQualityPreview;
441     }
442 
443     /**
444      * @return Returns the maxHeight, that should be used by pictures non transformed (rotated...) by the applet.
445      */
446     public int getMaxHeight() {
447         return this.maxHeight;
448     }
449 
450     /** @param maxHeight the maxHeight to set */
451     void setMaxHeight(int maxHeight) {
452         if (maxHeight <= 0) {
453             this.maxHeight = Integer.MAX_VALUE;
454             displayWarn("[setMaxHeight] maxHeight switched from " + maxHeight + " to " + this.maxHeight);
455         } else {
456             this.maxHeight = maxHeight;
457         }
458     }
459 
460     /**
461      * @return Returns the maxWidth, that should be used by pictures non transformed (rotated...) by the applet.
462      */
463     public int getMaxWidth() {
464         return this.maxWidth;
465     }
466 
467     /** @param maxWidth the maxWidth to set */
468     void setMaxWidth(int maxWidth) {
469         if (maxWidth <= 0) {
470             this.maxWidth = Integer.MAX_VALUE;
471             displayWarn("[setMaxWidth] maxWidth switched from " + maxWidth + " to " + this.maxWidth);
472         } else {
473             this.maxWidth = maxWidth;
474         }
475     }
476 
477     /**
478      * @return The current value for picture compression.
479      */
480     public float getPictureCompressionQuality() {
481         return this.pictureCompressionQuality;
482     }
483 
484     /**
485      * @see #pictureCompressionQuality
486      * @param pictureCompressionQuality The new value for picture compression.
487      */
488     void setPictureCompressionQuality(float pictureCompressionQuality) {
489         this.pictureCompressionQuality = pictureCompressionQuality;
490     }
491 
492     /**
493      * @return The current value for transmission (or no transmission) of picture metadata.
494      */
495     public boolean getPictureTransmitMetadata() {
496         return this.pictureTransmitMetadata;
497     }
498 
499     /**
500      * @see #pictureTransmitMetadata
501      * @param pictureTransmitMetadata The new value for this attribute.
502      */
503     void setPictureTransmitMetadata(boolean pictureTransmitMetadata) {
504         this.pictureTransmitMetadata = pictureTransmitMetadata;
505     }
506 
507     /**
508      * @return Returns the maxHeight, that should be used by pictures that are transformed (rotated...) by the applet.
509      */
510     public int getRealMaxHeight() {
511         return (this.realMaxHeight == Integer.MAX_VALUE) ? this.maxHeight : this.realMaxHeight;
512     }
513 
514     /** @param realMaxHeight the realMaxHeight to set */
515     void setRealMaxHeight(int realMaxHeight) {
516         this.realMaxHeight = realMaxHeight;
517     }
518 
519     /**
520      * @return Returns the maxWidth, that should be used by pictures that are transformed (rotated...) by the applet.
521      */
522     public int getRealMaxWidth() {
523         return (this.realMaxWidth == Integer.MAX_VALUE) ? this.maxWidth : this.realMaxWidth;
524     }
525 
526     /** @param realMaxWidth the realMaxWidth to set */
527     void setRealMaxWidth(int realMaxWidth) {
528         this.realMaxWidth = realMaxWidth;
529     }
530 
531     /** @return Returns the targetPictureFormat. */
532     public String getTargetPictureFormat() {
533         return this.targetPictureFormat;
534     }
535 
536     /**
537      * @return The current ImageFileConversionInfo
538      */
539     public ImageFileConversionInfo getImageFileConversionInfo() {
540         return this.imageFileConversionInfo;
541     }
542 
543     /**
544      * we expect e.g. "png,bmp:jpg;gif:png;"
545      * 
546      * @param targetPictureFormat the targetPictureFormat to set
547      * @throws JUploadException if the conversionList is erroneous
548      */
549     void setTargetPictureFormat(String targetPictureFormat) throws JUploadException {
550         this.targetPictureFormat = targetPictureFormat;
551         this.imageFileConversionInfo = new ImageFileConversionInfo(targetPictureFormat);
552     }
553 
554     /**
555      * @return <ul>
556      *         <li><code>true</code>, if the the original file extension should be kept</li>
557      *         <li><code>false</code>, if the the original file extension should be changed to the target picture
558      *         format, that the file has been converted to</li>
559      *         </ul>
560      */
561     public boolean getKeepOrigExtension() {
562         return this.keepOrigExtension;
563     }
564 
565     /**
566      * @param keepOrigExtension if the original file extension should be kept ' <code>true</code>', or changed '
567      *            <code>false</code>' (if the image was converted)
568      */
569     void setKeepOrigExtension(boolean keepOrigExtension) throws JUploadException {
570         this.keepOrigExtension = keepOrigExtension;
571     }
572 
573     /**
574      * This method manages the applet parameters that are specific to this class. The super.setProperty method is called
575      * for other properties.
576      * 
577      * @param prop The property which value should change
578      * @param value The new value for this property. If invalid, the default value is used.
579      * @see wjhk.jupload2.policies.UploadPolicy#setProperty(java.lang.String, java.lang.String)
580      */
581     @Override
582     public void setProperty(String prop, String value) throws JUploadException {
583         // The, we check the local properties.
584         if (prop.equals(PROP_FILE_CHOOSER_IMAGE_PREVIEW)) {
585             setFileChooserImagePreview(getContext().parseBoolean(value, getFileChooserImagePreview()));
586         } else if (prop.equals(PROP_HIGH_QUALITY_PREVIEW)) {
587             setHighQualityPreview(getContext().parseBoolean(value, this.highQualityPreview));
588         } else if (prop.equals(PROP_MAX_HEIGHT)) {
589             setMaxHeight(getContext().parseInt(value, this.maxHeight));
590         } else if (prop.equals(PROP_MAX_WIDTH)) {
591             setMaxWidth(getContext().parseInt(value, this.maxWidth));
592         } else if (prop.equals(PROP_PICTURE_COMPRESSION_QUALITY)) {
593             setPictureCompressionQuality(getContext().parseFloat(value, this.pictureCompressionQuality));
594         } else if (prop.equals(PROP_PICTURE_TRANSMIT_METADATA)) {
595             setPictureTransmitMetadata(getContext().parseBoolean(value, this.pictureTransmitMetadata));
596         } else if (prop.equals(PROP_REAL_MAX_HEIGHT)) {
597             setRealMaxHeight(getContext().parseInt(value, this.realMaxHeight));
598         } else if (prop.equals(PROP_REAL_MAX_WIDTH)) {
599             setRealMaxWidth(getContext().parseInt(value, this.realMaxWidth));
600         } else if (prop.equals(PROP_TARGET_PICTURE_FORMAT)) {
601             setTargetPictureFormat(value);
602         } else if (prop.equals(PROP_KEEP_ORIG_EXTENSION)) {
603             setKeepOrigExtension(getContext().parseBoolean(value, this.keepOrigExtension));
604         } else {
605             // Otherwise, transmission to the mother class.
606             super.setProperty(prop, value);
607         }
608     }
609 
610     /** @see DefaultUploadPolicy#displayParameterStatus() */
611     @Override
612     public void displayParameterStatus() {
613         super.displayParameterStatus();
614 
615         displayDebug("======= Parameters managed by PictureUploadPolicy", 30);
616         displayDebug(PROP_FILE_CHOOSER_IMAGE_PREVIEW + ": " + getFileChooserImagePreview(), 30);
617         displayDebug(PROP_HIGH_QUALITY_PREVIEW + " : " + this.highQualityPreview, 30);
618         displayDebug(PROP_PICTURE_COMPRESSION_QUALITY + " : " + getPictureCompressionQuality(), 30);
619         displayDebug(PROP_PICTURE_TRANSMIT_METADATA + " : " + getPictureTransmitMetadata(), 30);
620         displayDebug(PROP_MAX_WIDTH + " : " + this.maxWidth + ", " + PROP_MAX_HEIGHT + " : " + this.maxHeight, 30);
621         displayDebug(PROP_REAL_MAX_WIDTH + " : " + this.realMaxWidth + ", " + PROP_REAL_MAX_HEIGHT + " : "
622                 + this.realMaxHeight, 30);
623         displayDebug(PROP_STORE_BUFFERED_IMAGE + " : " + this.storeBufferedImage, 30);
624         displayDebug(PROP_TARGET_PICTURE_FORMAT + " : " + this.targetPictureFormat, 30);
625         displayDebug("Format conversions : " + getImageFileConversionInfo(), 40);
626         displayDebug("", 30);
627     }
628 
629     /**
630      * Calls the {@link DefaultUploadPolicy#setWaitCursor()} method, then erases the picture panel specific cursor.
631      * 
632      * @see DefaultUploadPolicy#setCursor(Cursor)
633      */
634     @Override
635     public Cursor setWaitCursor() {
636         Cursor previousCursor = super.setWaitCursor();
637         this.picturePanel.setCursor(null);
638         return previousCursor;
639     }
640 
641     /**
642      * Calls the {@link DefaultUploadPolicy#setCursor(Cursor)} method, then set the picture panel specific cursor.
643      * 
644      * @see DefaultUploadPolicy#setCursor(Cursor)
645      */
646     @Override
647     public Cursor setCursor(Cursor cursor) {
648         Cursor oldCursor = super.setCursor(null);
649         this.picturePanel.setCursor(new Cursor(Cursor.HAND_CURSOR));
650         return oldCursor;
651     }
652 
653     /**
654      * Creates the file chooser, from the default implementation, then add an accessory to preview pictures.
655      * 
656      * @see UploadPolicy#createFileChooser()
657      */
658     @Override
659     public JUploadFileChooser createFileChooser() {
660         JUploadFileChooser jufc = super.createFileChooser();
661         if (getFileChooserImagePreview()) {
662             jufc.setAccessory(new JUploadImagePreview(jufc, this));
663         }
664         return jufc;
665     }
666 
667     /**
668      * Returns an icon, calculated from the image content. Currently only pictures managed by ImageIO can be displayed.
669      * Once upon a day, extracting the first picture of a video may become reality... ;-) <BR>
670      * Note: this method is called in a dedicated thread by the JUploadFileChooser, to avoid to calculate the icon for
671      * all pictures, when opening a new folder.
672      * 
673      * @return The calculated ImageIcon, or null if no picture can be extracted.
674      * @see UploadPolicy#fileViewGetIcon(File)
675      * @see UploadPolicy#PROP_FILE_CHOOSER_ICON_FROM_FILE_CONTENT
676      */
677     @Override
678     public Icon fileViewGetIcon(File file) {
679         try {
680             return PictureFileData.getImageIcon(file, getFileChooserIconSize(), getFileChooserIconSize(), this);
681         } catch (JUploadException e) {
682             displayErr(e);
683             return null;
684         }
685     }
686 
687     /**
688      * @see wjhk.jupload2.policies.DefaultUploadPolicy#getUploadFilename(wjhk.jupload2.filedata.FileData, int)
689      */
690     @Override
691     public String getUploadFilename(FileData fileData, int index) throws JUploadException {
692         String fileName = fileData.getFileName();
693         if (!this.keepOrigExtension) {
694             String targetFormatOrNull = this.imageFileConversionInfo.getTargetFormatOrNull(fileData.getFileExtension());
695             if (targetFormatOrNull != null) {
696 
697                 int endIndex = fileName.length() - fileData.getFileExtension().length();
698                 StringBuilder newFilename = new StringBuilder(fileName.substring(0, endIndex));
699                 newFilename.append(targetFormatOrNull);
700                 fileName = newFilename.toString();
701             }
702         }
703 
704         return getEncodedFilename(fileName);
705     }
706 
707     /**
708      * Implementation of the ImageObserver interface
709      * 
710      * @param arg0
711      * @param arg1
712      * @param arg2
713      * @param arg3
714      * @param arg4
715      * @param arg5
716      * @return true or false
717      */
718     public boolean imageUpdate(Image arg0, int arg1, int arg2, int arg3, int arg4, int arg5) {
719         return true;
720     }
721 }